[v3,5/5] Extend "set cwd" to work on gdbserver

Message ID 20170921225926.23132-6-sergiodj@redhat.com
State New, archived
Headers

Commit Message

Sergio Durigan Junior Sept. 21, 2017, 10:59 p.m. UTC
  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 gdbserver is supposed to cd into before executing the inferior.
The good thing is that since this feature is already implemented on
nat/fork-inferior.c, all gdbserver has to do is to basically implement
"set_inferior_cwd" and call it whenever such packet arrives.

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:
yyyy-mm-dd  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:
yyyy-mm-dd  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:
yyyy-mm-dd  Sergio Durigan Junior  <sergiodj@redhat.com>

	* gdb.base/set-cwd.exp: Make it available on gdbserver.

gdb/doc/ChangeLog:
yyyy-mm-dd  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.
---
 gdb/NEWS                           | 12 ++++++++++++
 gdb/common/common-inferior.h       |  3 +++
 gdb/doc/gdb.texinfo                | 39 +++++++++++++++++++++++++++++++++++---
 gdb/gdbserver/inferiors.c          |  9 +++++++++
 gdb/gdbserver/server.c             | 18 +++++++++++++++++-
 gdb/gdbserver/win32-low.c          | 15 ++++++++++++---
 gdb/infcmd.c                       |  7 ++++---
 gdb/remote.c                       | 37 ++++++++++++++++++++++++++++++++++++
 gdb/testsuite/gdb.base/set-cwd.exp | 11 +++++++++--
 9 files changed, 139 insertions(+), 12 deletions(-)
  

Comments

Eli Zaretskii Sept. 22, 2017, 8:12 a.m. UTC | #1
> From: Sergio Durigan Junior <sergiodj@redhat.com>
> Cc: Pedro Alves <palves@redhat.com>,	Sergio Durigan Junior <sergiodj@redhat.com>
> Date: Thu, 21 Sep 2017 18:59:26 -0400
> 
> 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 gdbserver is supposed to cd into before executing the inferior.
> The good thing is that since this feature is already implemented on
> nat/fork-inferior.c, all gdbserver has to do is to basically implement
> "set_inferior_cwd" and call it whenever such packet arrives.

This once again raises the issue of whether to send expanded or
unexpanded directory down the wire, and if unexpanded, then what is
the meaning of the default "~" in the inferior.

> diff --git a/gdb/NEWS b/gdb/NEWS
> index c131713293..4ac340eeb5 100644
> --- a/gdb/NEWS
> +++ b/gdb/NEWS
> @@ -23,6 +23,14 @@
>  
>  * New features in the GDB remote stub, GDBserver
>  
> +  ** GDBserver is now able to set the inferior's current working
> +     directory.
> +
> +     The user can set the desired working directory to be used by the
> +     remote inferior on GDB, using the new "set cwd" command, which
> +     will instruct GDB to tell GDBserver about this directory change
> +     the next time an inferior is run.
> +
>    ** New "--selftest" command line option runs some GDBserver self
>       tests.  These self tests are disabled in releases.
>  
> @@ -56,6 +64,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.

This part is OK.

> diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo
> index 899afb92b6..7434de2a68 100644
> --- a/gdb/doc/gdb.texinfo
> +++ b/gdb/doc/gdb.texinfo

OK for this part.

> +  if (inferior_cwd != NULL)
> +    {
> +      size_t cwdlen = strlen (inferior_cwd);
> +
> +      wcwd = alloca ((cwdlen + 1) * sizeof (wchar_t));
> +      mbstowcs (wcwd, inferior_cwd, cwdlen + 1);
> +    }

no error checking of the mbstowcs conversion?

>    ret = CreateProcessW (wprogram, /* image name */
>  			wargs,    /* command line */
>  			NULL,     /* security, not supported */
> @@ -586,7 +595,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 +608,7 @@ create_process (const char *program, char *args,
>  			TRUE,     /* inherit handles */
>  			flags,    /* start flags */
>  			NULL,     /* environment */
> -			NULL,     /* current directory */
> +			inferior_cwd,     /* current directory */
>  			&si,      /* start info */
>  			pi);      /* proc info */

Once again, this feeds CreateProcess with an unexpanded directory,
which AFAIU will not work if the directory includes "~".

> +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));
> +

Shouldn't this do some encoding conversion, from the GDB charset to
the target charset, before encoding in hex?

Thanks.
  
Sergio Durigan Junior Sept. 22, 2017, 6:45 p.m. UTC | #2
On Friday, September 22 2017, Eli Zaretskii wrote:

>> From: Sergio Durigan Junior <sergiodj@redhat.com>
>> Cc: Pedro Alves <palves@redhat.com>,	Sergio Durigan Junior <sergiodj@redhat.com>
>> Date: Thu, 21 Sep 2017 18:59:26 -0400
>> 
>> 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 gdbserver is supposed to cd into before executing the inferior.
>> The good thing is that since this feature is already implemented on
>> nat/fork-inferior.c, all gdbserver has to do is to basically implement
>> "set_inferior_cwd" and call it whenever such packet arrives.
>
> This once again raises the issue of whether to send expanded or
> unexpanded directory down the wire, and if unexpanded, then what is
> the meaning of the default "~" in the inferior.

FWIW, I decided (based on another message by Pedro) to modify the
behaviour of "set cwd" without arguments.  Before it was setting the
inferior's cwd as "~", but now it clears out whatever cwd that has been
specified by the user.

But of course, the user can still do "set cwd ~".  We do not expand
paths on the host, as I explained in another message, so gdbserver will
see "~" coming down the wire.  Then, when the inferior is to be started,
gdbserver will perform the path expansion based on what
"gdb_tilde_expand" (i.e., "glob") does.

>> +  if (inferior_cwd != NULL)
>> +    {
>> +      size_t cwdlen = strlen (inferior_cwd);
>> +
>> +      wcwd = alloca ((cwdlen + 1) * sizeof (wchar_t));
>> +      mbstowcs (wcwd, inferior_cwd, cwdlen + 1);
>> +    }
>
> no error checking of the mbstowcs conversion?

Sorry, I am not a Windows programmer.  Other places in the code also
don't check for errors.  I'd be happy to improve this code, but I refuse
to touch a Windows machine so I'm doing this all this without any
testing.  But please, feel absolutely free to point out how this code
should look like.

>>    ret = CreateProcessW (wprogram, /* image name */
>>  			wargs,    /* command line */
>>  			NULL,     /* security, not supported */
>> @@ -586,7 +595,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 +608,7 @@ create_process (const char *program, char *args,
>>  			TRUE,     /* inherit handles */
>>  			flags,    /* start flags */
>>  			NULL,     /* environment */
>> -			NULL,     /* current directory */
>> +			inferior_cwd,     /* current directory */
>>  			&si,      /* start info */
>>  			pi);      /* proc info */
>
> Once again, this feeds CreateProcess with an unexpanded directory,
> which AFAIU will not work if the directory includes "~".

You're right; I've changed that now.

>> +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));
>> +
>
> Shouldn't this do some encoding conversion, from the GDB charset to
> the target charset, before encoding in hex?

I don't know.  There's nothing related to charset on gdb/gdbserver/, but
then again I don't know if we've ever encountered a case that demanded
conversions.  I can investigate this a bit more.

Thanks,
  
Eli Zaretskii Sept. 22, 2017, 7:08 p.m. UTC | #3
> From: Sergio Durigan Junior <sergiodj@redhat.com>
> Cc: gdb-patches@sourceware.org,  palves@redhat.com
> Date: Fri, 22 Sep 2017 14:45:59 -0400
> 
> >> +  if (inferior_cwd != NULL)
> >> +    {
> >> +      size_t cwdlen = strlen (inferior_cwd);
> >> +
> >> +      wcwd = alloca ((cwdlen + 1) * sizeof (wchar_t));
> >> +      mbstowcs (wcwd, inferior_cwd, cwdlen + 1);
> >> +    }
> >
> > no error checking of the mbstowcs conversion?
> 
> Sorry, I am not a Windows programmer.  Other places in the code also
> don't check for errors.

Not checking for errors in these conversions can be worse on Windows
than on other platforms, because the Windows' wchar_t supports only
the BMP, so the chances of getting a conversion error are higher than
on Unix.

> I'd be happy to improve this code, but I refuse to touch a Windows
> machine so I'm doing this all this without any testing.  But please,
> feel absolutely free to point out how this code should look like.

mbstowcs returns NULL if it fails, so I suggest to throw an error in
that case.  I see no reason for anything fancier.

> >> +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));
> >> +
> >
> > Shouldn't this do some encoding conversion, from the GDB charset to
> > the target charset, before encoding in hex?
> 
> I don't know.  There's nothing related to charset on gdb/gdbserver/, but
> then again I don't know if we've ever encountered a case that demanded
> conversions.  I can investigate this a bit more.

GDB does know about target-charset and host-charset.  I'd expect file
names that are sent to the target be in the target charset, but since
what get_inferior_cwd returns is in host charset (it was typed by the
user), I think a conversion might be in order.
  
Sergio Durigan Junior Sept. 22, 2017, 8:47 p.m. UTC | #4
On Friday, September 22 2017, Eli Zaretskii wrote:

>> From: Sergio Durigan Junior <sergiodj@redhat.com>
>> Cc: gdb-patches@sourceware.org,  palves@redhat.com
>> Date: Fri, 22 Sep 2017 14:45:59 -0400
>> 
>> >> +  if (inferior_cwd != NULL)
>> >> +    {
>> >> +      size_t cwdlen = strlen (inferior_cwd);
>> >> +
>> >> +      wcwd = alloca ((cwdlen + 1) * sizeof (wchar_t));
>> >> +      mbstowcs (wcwd, inferior_cwd, cwdlen + 1);
>> >> +    }
>> >
>> > no error checking of the mbstowcs conversion?
>> 
>> Sorry, I am not a Windows programmer.  Other places in the code also
>> don't check for errors.
>
> Not checking for errors in these conversions can be worse on Windows
> than on other platforms, because the Windows' wchar_t supports only
> the BMP, so the chances of getting a conversion error are higher than
> on Unix.
>
>> I'd be happy to improve this code, but I refuse to touch a Windows
>> machine so I'm doing this all this without any testing.  But please,
>> feel absolutely free to point out how this code should look like.
>
> mbstowcs returns NULL if it fails, so I suggest to throw an error in
> that case.  I see no reason for anything fancier.

OK, that I can do :-).

>> >> +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));
>> >> +
>> >
>> > Shouldn't this do some encoding conversion, from the GDB charset to
>> > the target charset, before encoding in hex?
>> 
>> I don't know.  There's nothing related to charset on gdb/gdbserver/, but
>> then again I don't know if we've ever encountered a case that demanded
>> conversions.  I can investigate this a bit more.
>
> GDB does know about target-charset and host-charset.  I'd expect file
> names that are sent to the target be in the target charset, but since
> what get_inferior_cwd returns is in host charset (it was typed by the
> user), I think a conversion might be in order.

I don't know.  We never seem to do that in other cases.  For example,
when we are starting the inferior remotely:

  static int
  extended_remote_run (const std::string &args)
  {
    ...
    if (strlen (remote_exec_file) * 2 + len >= get_remote_packet_size ())
      error (_("Remote file name too long for run packet"));
    len += 2 * bin2hex ((gdb_byte *) remote_exec_file, rs->buf + len,
                        strlen (remote_exec_file));


The "remote_exec_file" variable is also something that the user inputs
through the "set remote exec-file" command.  It doesn't seem like we
need to worry about charset conversion here.

Thanks,
  
Eli Zaretskii Sept. 23, 2017, 6 a.m. UTC | #5
> From: Sergio Durigan Junior <sergiodj@redhat.com>
> Cc: gdb-patches@sourceware.org,  palves@redhat.com
> Date: Fri, 22 Sep 2017 16:47:26 -0400
> 
> > GDB does know about target-charset and host-charset.  I'd expect file
> > names that are sent to the target be in the target charset, but since
> > what get_inferior_cwd returns is in host charset (it was typed by the
> > user), I think a conversion might be in order.
> 
> I don't know.  We never seem to do that in other cases.  For example,
> when we are starting the inferior remotely:
> 
>   static int
>   extended_remote_run (const std::string &args)
>   {
>     ...
>     if (strlen (remote_exec_file) * 2 + len >= get_remote_packet_size ())
>       error (_("Remote file name too long for run packet"));
>     len += 2 * bin2hex ((gdb_byte *) remote_exec_file, rs->buf + len,
>                         strlen (remote_exec_file));
> 
> 
> The "remote_exec_file" variable is also something that the user inputs
> through the "set remote exec-file" command.  It doesn't seem like we
> need to worry about charset conversion here.

If remote_exec_file came from the target, that's okay, as it would be
already in the target charset.  But if it is typed by the user, then I
guess we indeed have such problems, when the 2 charsets are different.

Anyway, I don't want to block the changeset or hijack the discussions.
Feel free to go ahead with pushing if we generally ignore this issue
elsewhere.

Thanks.
  
Pedro Alves Sept. 27, 2017, 2:42 p.m. UTC | #6
On 09/21/2017 11:59 PM, Sergio Durigan Junior wrote:
> 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 gdbserver is supposed to cd into before executing the inferior.
       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

Unix implementation detail.

> The good thing is that since this feature is already implemented on
> nat/fork-inferior.c, all gdbserver has to do is to basically implement
> "set_inferior_cwd" and call it whenever such packet arrives.

Unix implementation detail.  That's not how it works for Windows.

> 
> 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:
> yyyy-mm-dd  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:
> yyyy-mm-dd  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:
> yyyy-mm-dd  Sergio Durigan Junior  <sergiodj@redhat.com>
> 
> 	* gdb.base/set-cwd.exp: Make it available on gdbserver.
> 
> gdb/doc/ChangeLog:
> yyyy-mm-dd  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.
> ---
>  gdb/NEWS                           | 12 ++++++++++++
>  gdb/common/common-inferior.h       |  3 +++
>  gdb/doc/gdb.texinfo                | 39 +++++++++++++++++++++++++++++++++++---
>  gdb/gdbserver/inferiors.c          |  9 +++++++++
>  gdb/gdbserver/server.c             | 18 +++++++++++++++++-
>  gdb/gdbserver/win32-low.c          | 15 ++++++++++++---
>  gdb/infcmd.c                       |  7 ++++---
>  gdb/remote.c                       | 37 ++++++++++++++++++++++++++++++++++++
>  gdb/testsuite/gdb.base/set-cwd.exp | 11 +++++++++--
>  9 files changed, 139 insertions(+), 12 deletions(-)
> 
> diff --git a/gdb/NEWS b/gdb/NEWS
> index c131713293..4ac340eeb5 100644
> --- a/gdb/NEWS
> +++ b/gdb/NEWS
> @@ -23,6 +23,14 @@
>  
>  * New features in the GDB remote stub, GDBserver
>  
> +  ** GDBserver is now able to set the inferior's current working
> +     directory.
> +
> +     The user can set the desired working directory to be used by the
> +     remote inferior on GDB, using the new "set cwd" command, which
> +     will instruct GDB to tell GDBserver about this directory change
> +     the next time an inferior is run.
> +
>    ** New "--selftest" command line option runs some GDBserver self
>       tests.  These self tests are disabled in releases.
>  
> @@ -56,6 +64,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 515a8c0f4e..26acddc84a 100644
> --- a/gdb/common/common-inferior.h
> +++ b/gdb/common/common-inferior.h
> @@ -34,4 +34,7 @@ extern char *get_exec_file (int err);
>     been set, then return NULL.  */
>  extern const char *get_inferior_cwd ();
>  
> +/* Set the inferior current working directory.  */
> +extern void set_inferior_cwd (const char *cwd);
> +
>  #endif /* ! COMMON_INFERIOR_H */
> diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo
> index 899afb92b6..7434de2a68 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
>  @code{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 @code{gdbserver}'s working directory if remote
> +debugging.  @xref{Working Directory, ,Your Program's Working
> +Directory}.

Elsewhere in the manual we say "the remote server" instead of @code{gdbserver},
because not all remote debugging uses gdbserver.

>  
>  @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
>  @code{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 @code{gdbserver}'s current working directory if remote
> +debugging.

Ditto.

>  
>  You can also change @value{GDBN}'s current working directory by using
>  the @code{cd} command.
> @@ -20993,6 +20997,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}
> @@ -36781,6 +36789,28 @@ Reply:
>  @table @samp
>  @item OK
>  The request succeeded.
> +
> +@item QSetWorkingDir:@var{hex-value}

I think it'd be clearer to say @var{directory}, and
then say below that @var{directory} is an hex-encoded
string, like you're already doing.  That's what we do
elsewhere in the manual.

> +@anchor{QSetWorkingDir packet}
> +@cindex set working directory, remote request
> +@cindex @samp{QSetWorkingDir} packet
> +This packet is used to inform @command{gdbserver} of the intended

Ditto re. "gdbserver".

> +current working directory for programs that are going to be executed.
> +
> +The packet is composed by @var{hex-value}, an hex encoded
> +representation of the directory to be entered by @command{gdbserver}.
> +
> +This packet is only transmitted when the user issues a @code{set cwd}
> +command in @value{GDBN} (@pxref{Working Directory, ,Your Program's
> +Working Directory}).

"This packet is only transmitted when set cwd" suggests to me that
the packet is sent immediately when the user types "set cwd".

  This packet is only transmitted if the user explicitly
  specifies a directory with the @kdb{set cwd} command.

note: 
  s/when/if/.
  s/@code/@kdb

> diff --git a/gdb/gdbserver/inferiors.c b/gdb/gdbserver/inferiors.c
> index e78ad4faf1..326d01f4d9 100644
> --- a/gdb/gdbserver/inferiors.c
> +++ b/gdb/gdbserver/inferiors.c
> @@ -456,3 +456,12 @@ get_inferior_cwd ()
>  {
>    return current_inferior_cwd;
>  }
> +
> +/* See common/common-inferior.h.  */
> +
> +void
> +set_inferior_cwd (const char *cwd)
> +{
> +  xfree ((void *) current_inferior_cwd);
> +  current_inferior_cwd = xstrdup (cwd);
> +}
> diff --git a/gdb/gdbserver/server.c b/gdb/gdbserver/server.c
> index f3eee31052..14f8a732a7 100644
> --- a/gdb/gdbserver/server.c
> +++ b/gdb/gdbserver/server.c
> @@ -869,6 +869,21 @@ handle_general_set (char *own_buf)
>        return;
>      }
>  
> +  if (startswith (own_buf, "QSetWorkingDir:"))
> +    {
> +      const char *p = own_buf + strlen ("QSetWorkingDir:");
> +      std::string path = hex2str (p);
> +
> +      set_inferior_cwd (path.c_str ());
> +
> +      if (remote_debug)
> +	debug_printf (_("[Changed current directory to %s]\n"),
> +		      path.c_str ());

Please tweak the debug string to be clear that this is the
inferior's cwd, not gdbserver's.

> +      write_ok (own_buf);
> +
> +      return;
> +    }
> +
>    /* Otherwise we didn't know what packet it was.  Say we didn't
>       understand it.  */
>    own_buf[0] = 0;
> @@ -2355,7 +2370,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 cc84d15c2f..62b222d2fa 100644
> --- a/gdb/gdbserver/win32-low.c
> +++ b/gdb/gdbserver/win32-low.c
> @@ -562,10 +562,11 @@ static BOOL
>  create_process (const char *program, char *args,
>  		DWORD flags, PROCESS_INFORMATION *pi)
>  {
> +  const char *inferior_cwd = get_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 +580,14 @@ create_process (const char *program, char *args,
>    wargs = alloca ((argslen + 1) * sizeof (wchar_t));
>    mbstowcs (wargs, args, argslen + 1);
>  
> +  if (inferior_cwd != NULL)
> +    {
> +      size_t cwdlen = strlen (inferior_cwd);
> +
> +      wcwd = alloca ((cwdlen + 1) * sizeof (wchar_t));
> +      mbstowcs (wcwd, inferior_cwd, cwdlen + 1);
> +    }
> +
>    ret = CreateProcessW (wprogram, /* image name */
>  			wargs,    /* command line */
>  			NULL,     /* security, not supported */
> @@ -586,7 +595,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 +608,7 @@ create_process (const char *program, char *args,
>  			TRUE,     /* inherit handles */
>  			flags,    /* start flags */
>  			NULL,     /* environment */
> -			NULL,     /* current directory */
> +			inferior_cwd,     /* current directory */
>  			&si,      /* start info */
>  			pi);      /* proc info */
>  #endif
> diff --git a/gdb/infcmd.c b/gdb/infcmd.c
> index 4c5bbfdbf2..f483a33a44 100644
> --- a/gdb/infcmd.c
> +++ b/gdb/infcmd.c
> @@ -250,9 +250,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.  */
> +/* See common/common-inferior.h.  */
>  
> -static void
> +void
>  set_inferior_cwd (const char *cwd)
>  {
>    if (*cwd == '\0')
> @@ -292,7 +292,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 gdbserver's\n\
> +cwd if remote debugging.\n"));

gdbserver -> remote server.

> +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)
> +	{

What happens if you do:

 set cwd foo
 run
 kill
 set cwd    # clear
 run

Do we clear the cwd on the remote end or we do we fail the
NULL check above?

> +/* See common/common-inferior.h.  */
> +
> +void
> +set_inferior_cwd (const char *cwd)
> +{
> +  xfree ((void *) current_inferior_cwd);
> +  current_inferior_cwd = xstrdup (cwd);
> +}

This always sets to non-NULL.  So is it really possible
to get back to the original clear state?  Doesn't look like it?
Do we have a test for that?


> +	  std::string hexpath = bin2hex ((const gdb_byte *) inferior_cwd,
> +					 strlen (inferior_cwd));
> +
> +	  xsnprintf (rs->buf, get_remote_packet_size (),
> +		     "QSetWorkingDir:%s", hexpath.c_str ());
> +	  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 changing working directory: %s"),
> +		   rs->buf);

Again "changing".   Maybe say "setting the inferior's working directory"
instead.


> +	}
> +    }
> +}
> +
>  /* 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
> @@ -9686,6 +9718,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)
> @@ -14185,6 +14219,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/gdb.base/set-cwd.exp b/gdb/testsuite/gdb.base/set-cwd.exp
> index f2700ec44d..32458e384e 100644
> --- a/gdb/testsuite/gdb.base/set-cwd.exp
> +++ b/gdb/testsuite/gdb.base/set-cwd.exp
> @@ -15,11 +15,18 @@
>  # 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 gdbserver"
> +if { [use_gdb_stub] } {
> +    untested "not valid on native-gdbserver"

There are many other boards that set use_gdb_stub, not just
native-gdbserver.  Other testcases say:

untested "skipping tests due to use_gdb_stub"


>      return
>  }
>  
> +if { [target_info gdb_protocol] == "remote" } {
> +    load_lib gdbserver-support.exp
> +    if { [skip_gdbserver_tests] } {
> +	return
> +    }
> +}
> +

Please remember to drop this part.

>  standard_testfile
>  
>  if { [prepare_for_testing "failed to prepare" $testfile $srcfile debug] } {
> 


Thanks,
Pedro Alves
  
Sergio Durigan Junior Sept. 27, 2017, 9:48 p.m. UTC | #7
On Wednesday, September 27 2017, Pedro Alves wrote:

> On 09/21/2017 11:59 PM, Sergio Durigan Junior wrote:
>> 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 gdbserver is supposed to cd into before executing the inferior.
>        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
>
> Unix implementation detail.

Rewrote as:

  [...]
  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.

  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.
  [...]

>> The good thing is that since this feature is already implemented on
>> nat/fork-inferior.c, all gdbserver has to do is to basically implement
>> "set_inferior_cwd" and call it whenever such packet arrives.
>
> Unix implementation detail.  That's not how it works for Windows.

See above.

>> 
>> 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:
>> yyyy-mm-dd  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:
>> yyyy-mm-dd  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:
>> yyyy-mm-dd  Sergio Durigan Junior  <sergiodj@redhat.com>
>> 
>> 	* gdb.base/set-cwd.exp: Make it available on gdbserver.
>> 
>> gdb/doc/ChangeLog:
>> yyyy-mm-dd  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.
>> ---
>>  gdb/NEWS                           | 12 ++++++++++++
>>  gdb/common/common-inferior.h       |  3 +++
>>  gdb/doc/gdb.texinfo                | 39 +++++++++++++++++++++++++++++++++++---
>>  gdb/gdbserver/inferiors.c          |  9 +++++++++
>>  gdb/gdbserver/server.c             | 18 +++++++++++++++++-
>>  gdb/gdbserver/win32-low.c          | 15 ++++++++++++---
>>  gdb/infcmd.c                       |  7 ++++---
>>  gdb/remote.c                       | 37 ++++++++++++++++++++++++++++++++++++
>>  gdb/testsuite/gdb.base/set-cwd.exp | 11 +++++++++--
>>  9 files changed, 139 insertions(+), 12 deletions(-)
>> 
>> diff --git a/gdb/NEWS b/gdb/NEWS
>> index c131713293..4ac340eeb5 100644
>> --- a/gdb/NEWS
>> +++ b/gdb/NEWS
>> @@ -23,6 +23,14 @@
>>  
>>  * New features in the GDB remote stub, GDBserver
>>  
>> +  ** GDBserver is now able to set the inferior's current working
>> +     directory.
>> +
>> +     The user can set the desired working directory to be used by the
>> +     remote inferior on GDB, using the new "set cwd" command, which
>> +     will instruct GDB to tell GDBserver about this directory change
>> +     the next time an inferior is run.
>> +
>>    ** New "--selftest" command line option runs some GDBserver self
>>       tests.  These self tests are disabled in releases.
>>  
>> @@ -56,6 +64,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 515a8c0f4e..26acddc84a 100644
>> --- a/gdb/common/common-inferior.h
>> +++ b/gdb/common/common-inferior.h
>> @@ -34,4 +34,7 @@ extern char *get_exec_file (int err);
>>     been set, then return NULL.  */
>>  extern const char *get_inferior_cwd ();
>>  
>> +/* Set the inferior current working directory.  */
>> +extern void set_inferior_cwd (const char *cwd);
>> +
>>  #endif /* ! COMMON_INFERIOR_H */
>> diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo
>> index 899afb92b6..7434de2a68 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
>>  @code{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 @code{gdbserver}'s working directory if remote
>> +debugging.  @xref{Working Directory, ,Your Program's Working
>> +Directory}.
>
> Elsewhere in the manual we say "the remote server" instead of @code{gdbserver},
> because not all remote debugging uses gdbserver.

Updated.

>>  
>>  @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
>>  @code{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 @code{gdbserver}'s current working directory if remote
>> +debugging.
>
> Ditto.

Updated.

>>  
>>  You can also change @value{GDBN}'s current working directory by using
>>  the @code{cd} command.
>> @@ -20993,6 +20997,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}
>> @@ -36781,6 +36789,28 @@ Reply:
>>  @table @samp
>>  @item OK
>>  The request succeeded.
>> +
>> +@item QSetWorkingDir:@var{hex-value}
>
> I think it'd be clearer to say @var{directory}, and
> then say below that @var{directory} is an hex-encoded
> string, like you're already doing.  That's what we do
> elsewhere in the manual.

Sure.  Updated

>
>> +@anchor{QSetWorkingDir packet}
>> +@cindex set working directory, remote request
>> +@cindex @samp{QSetWorkingDir} packet
>> +This packet is used to inform @command{gdbserver} of the intended
>
> Ditto re. "gdbserver".

Updated.

>> +current working directory for programs that are going to be executed.
>> +
>> +The packet is composed by @var{hex-value}, an hex encoded
>> +representation of the directory to be entered by @command{gdbserver}.
>> +
>> +This packet is only transmitted when the user issues a @code{set cwd}
>> +command in @value{GDBN} (@pxref{Working Directory, ,Your Program's
>> +Working Directory}).
>
> "This packet is only transmitted when set cwd" suggests to me that
> the packet is sent immediately when the user types "set cwd".
>
>   This packet is only transmitted if the user explicitly
>   specifies a directory with the @kdb{set cwd} command.

Rewrote it.

> note: 
>   s/when/if/.
>   s/@code/@kdb

It's @kbd (from "keyboard").  But I know, our muscle memory wants us to
type "db" :-P.

Even though I slightly disagree here (commands are not keybindings), I
found that this is indeed what GDB uses.  Anyway, using @kbd now.

>> diff --git a/gdb/gdbserver/inferiors.c b/gdb/gdbserver/inferiors.c
>> index e78ad4faf1..326d01f4d9 100644
>> --- a/gdb/gdbserver/inferiors.c
>> +++ b/gdb/gdbserver/inferiors.c
>> @@ -456,3 +456,12 @@ get_inferior_cwd ()
>>  {
>>    return current_inferior_cwd;
>>  }
>> +
>> +/* See common/common-inferior.h.  */
>> +
>> +void
>> +set_inferior_cwd (const char *cwd)
>> +{
>> +  xfree ((void *) current_inferior_cwd);
>> +  current_inferior_cwd = xstrdup (cwd);
>> +}
>> diff --git a/gdb/gdbserver/server.c b/gdb/gdbserver/server.c
>> index f3eee31052..14f8a732a7 100644
>> --- a/gdb/gdbserver/server.c
>> +++ b/gdb/gdbserver/server.c
>> @@ -869,6 +869,21 @@ handle_general_set (char *own_buf)
>>        return;
>>      }
>>  
>> +  if (startswith (own_buf, "QSetWorkingDir:"))
>> +    {
>> +      const char *p = own_buf + strlen ("QSetWorkingDir:");
>> +      std::string path = hex2str (p);
>> +
>> +      set_inferior_cwd (path.c_str ());
>> +
>> +      if (remote_debug)
>> +	debug_printf (_("[Changed current directory to %s]\n"),
>> +		      path.c_str ());
>
> Please tweak the debug string to be clear that this is the
> inferior's cwd, not gdbserver's.

OK, changed to:

debug_printf (_("[Set the inferior's current directory to %s]\n"),
	      path.c_str ());

>> +      write_ok (own_buf);
>> +
>> +      return;
>> +    }
>> +
>>    /* Otherwise we didn't know what packet it was.  Say we didn't
>>       understand it.  */
>>    own_buf[0] = 0;
>> @@ -2355,7 +2370,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 cc84d15c2f..62b222d2fa 100644
>> --- a/gdb/gdbserver/win32-low.c
>> +++ b/gdb/gdbserver/win32-low.c
>> @@ -562,10 +562,11 @@ static BOOL
>>  create_process (const char *program, char *args,
>>  		DWORD flags, PROCESS_INFORMATION *pi)
>>  {
>> +  const char *inferior_cwd = get_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 +580,14 @@ create_process (const char *program, char *args,
>>    wargs = alloca ((argslen + 1) * sizeof (wchar_t));
>>    mbstowcs (wargs, args, argslen + 1);
>>  
>> +  if (inferior_cwd != NULL)
>> +    {
>> +      size_t cwdlen = strlen (inferior_cwd);
>> +
>> +      wcwd = alloca ((cwdlen + 1) * sizeof (wchar_t));
>> +      mbstowcs (wcwd, inferior_cwd, cwdlen + 1);
>> +    }
>> +
>>    ret = CreateProcessW (wprogram, /* image name */
>>  			wargs,    /* command line */
>>  			NULL,     /* security, not supported */
>> @@ -586,7 +595,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 +608,7 @@ create_process (const char *program, char *args,
>>  			TRUE,     /* inherit handles */
>>  			flags,    /* start flags */
>>  			NULL,     /* environment */
>> -			NULL,     /* current directory */
>> +			inferior_cwd,     /* current directory */
>>  			&si,      /* start info */
>>  			pi);      /* proc info */
>>  #endif
>> diff --git a/gdb/infcmd.c b/gdb/infcmd.c
>> index 4c5bbfdbf2..f483a33a44 100644
>> --- a/gdb/infcmd.c
>> +++ b/gdb/infcmd.c
>> @@ -250,9 +250,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.  */
>> +/* See common/common-inferior.h.  */
>>  
>> -static void
>> +void
>>  set_inferior_cwd (const char *cwd)
>>  {
>>    if (*cwd == '\0')
>> @@ -292,7 +292,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 gdbserver's\n\
>> +cwd if remote debugging.\n"));
>
> gdbserver -> remote server.

Updated.

>> +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)
>> +	{
>
> What happens if you do:
>
>  set cwd foo
>  run
>  kill
>  set cwd    # clear
>  run
>
> Do we clear the cwd on the remote end or we do we fail the
> NULL check above?

In this specific version of the patch, which does not have the
implementation to clear out the inferior's cwd, the empty "set cwd"
would actually make the "~" as the current directory for the inferior.
But in the next version (which I'll send), when "inferior_cwd == NULL" I
will send an empty QSetWorkingDir packet (which means I'll extend the
QSetWorkingDir packet to accept empty arguments), and that will clear
things up in the server side.

>
>> +/* See common/common-inferior.h.  */
>> +
>> +void
>> +set_inferior_cwd (const char *cwd)
>> +{
>> +  xfree ((void *) current_inferior_cwd);
>> +  current_inferior_cwd = xstrdup (cwd);
>> +}
>
> This always sets to non-NULL.  So is it really possible
> to get back to the original clear state?  Doesn't look like it?
> Do we have a test for that?

Not in this specific version, no.  This was something decided *after* I
had sent this version.  In my local tree I have code implementing the
"clear up" behaviour, and I'll add a test for that as well.

>
>
>> +	  std::string hexpath = bin2hex ((const gdb_byte *) inferior_cwd,
>> +					 strlen (inferior_cwd));
>> +
>> +	  xsnprintf (rs->buf, get_remote_packet_size (),
>> +		     "QSetWorkingDir:%s", hexpath.c_str ());
>> +	  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 changing working directory: %s"),
>> +		   rs->buf);
>
> Again "changing".   Maybe say "setting the inferior's working directory"
> instead.

OK.

>
>
>> +	}
>> +    }
>> +}
>> +
>>  /* 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
>> @@ -9686,6 +9718,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)
>> @@ -14185,6 +14219,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/gdb.base/set-cwd.exp b/gdb/testsuite/gdb.base/set-cwd.exp
>> index f2700ec44d..32458e384e 100644
>> --- a/gdb/testsuite/gdb.base/set-cwd.exp
>> +++ b/gdb/testsuite/gdb.base/set-cwd.exp
>> @@ -15,11 +15,18 @@
>>  # 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 gdbserver"
>> +if { [use_gdb_stub] } {
>> +    untested "not valid on native-gdbserver"
>
> There are many other boards that set use_gdb_stub, not just
> native-gdbserver.  Other testcases say:
>
> untested "skipping tests due to use_gdb_stub"

Hm, OK.

Does this look correct now, though?

>>      return
>>  }
>>  
>> +if { [target_info gdb_protocol] == "remote" } {
>> +    load_lib gdbserver-support.exp
>> +    if { [skip_gdbserver_tests] } {
>> +	return
>> +    }
>> +}
>> +
>
> Please remember to drop this part.

Already did.  Thanks.

>>  standard_testfile
>>  
>>  if { [prepare_for_testing "failed to prepare" $testfile $srcfile debug] } {
>> 
>
>
> Thanks,
> Pedro Alves

Thanks,
  
Pedro Alves Sept. 29, 2017, 2:03 p.m. UTC | #8
On 09/27/2017 10:48 PM, Sergio Durigan Junior wrote:

>> note: 
>>   s/when/if/.
>>   s/@code/@kdb
> 
> It's @kbd (from "keyboard").  But I know, our muscle memory wants us to
> type "db" :-P.

;-)

> 
> Even though I slightly disagree here (commands are not keybindings), I
> found that this is indeed what GDB uses.  Anyway, using @kbd now.

See discussion starting here:

  https://sourceware.org/ml/gdb-patches/2017-06/msg00592.html

> 
> Not in this specific version, no.  This was something decided *after* I
> had sent this version.  In my local tree I have code implementing the
> "clear up" behaviour, and I'll add a test for that as well.

OK, thanks.  Sorry I got confused.

>> There are many other boards that set use_gdb_stub, not just
>> native-gdbserver.  Other testcases say:
>>
>> untested "skipping tests due to use_gdb_stub"
> 
> Hm, OK.
> 
> Does this look correct now, though?

I don't know; I'll take a look at v4.  We may
still need is_remote checks depending on whether the
tests have assumptions about build==host or host==target.

Thanks,
Pedro Alves
  
Sergio Durigan Junior Sept. 29, 2017, 6:33 p.m. UTC | #9
On Friday, September 29 2017, Pedro Alves wrote:

>> It's @kbd (from "keyboard").  But I know, our muscle memory wants us to
>> type "db" :-P.
>
> ;-)
>
>> 
>> Even though I slightly disagree here (commands are not keybindings), I
>> found that this is indeed what GDB uses.  Anyway, using @kbd now.
>
> See discussion starting here:
>
>   https://sourceware.org/ml/gdb-patches/2017-06/msg00592.html

Aha.  Thanks for the reference.
  

Patch

diff --git a/gdb/NEWS b/gdb/NEWS
index c131713293..4ac340eeb5 100644
--- a/gdb/NEWS
+++ b/gdb/NEWS
@@ -23,6 +23,14 @@ 
 
 * New features in the GDB remote stub, GDBserver
 
+  ** GDBserver is now able to set the inferior's current working
+     directory.
+
+     The user can set the desired working directory to be used by the
+     remote inferior on GDB, using the new "set cwd" command, which
+     will instruct GDB to tell GDBserver about this directory change
+     the next time an inferior is run.
+
   ** New "--selftest" command line option runs some GDBserver self
      tests.  These self tests are disabled in releases.
 
@@ -56,6 +64,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 515a8c0f4e..26acddc84a 100644
--- a/gdb/common/common-inferior.h
+++ b/gdb/common/common-inferior.h
@@ -34,4 +34,7 @@  extern char *get_exec_file (int err);
    been set, then return NULL.  */
 extern const char *get_inferior_cwd ();
 
+/* Set the inferior current working directory.  */
+extern void set_inferior_cwd (const char *cwd);
+
 #endif /* ! COMMON_INFERIOR_H */
diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo
index 899afb92b6..7434de2a68 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
 @code{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 @code{gdbserver}'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
 @code{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 @code{gdbserver}'s current working directory if remote
+debugging.
 
 You can also change @value{GDBN}'s current working directory by using
 the @code{cd} command.
@@ -20993,6 +20997,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}
@@ -36781,6 +36789,28 @@  Reply:
 @table @samp
 @item OK
 The request succeeded.
+
+@item QSetWorkingDir:@var{hex-value}
+@anchor{QSetWorkingDir packet}
+@cindex set working directory, remote request
+@cindex @samp{QSetWorkingDir} packet
+This packet is used to inform @command{gdbserver} of the intended
+current working directory for programs that are going to be executed.
+
+The packet is composed by @var{hex-value}, an hex encoded
+representation of the directory to be entered by @command{gdbserver}.
+
+This packet is only transmitted when the user issues a @code{set cwd}
+command in @value{GDBN} (@pxref{Working Directory, ,Your Program's
+Working Directory}).
+
+This packet is only available in extended mode (@pxref{extended
+mode}).
+
+Reply:
+@table @samp
+@item OK
+The request succeeded.
 @end table
 
 This packet is not probed by default; the remote stub must request it,
@@ -36811,6 +36841,9 @@  Reply:
 @table @samp
 @item OK
 The request succeeded.
+
+@item E @var{nn}
+An error occurred.  The error number @var{nn} is given as hex digits.
 @end table
 
 This packet is not probed by default; the remote stub must request it,
diff --git a/gdb/gdbserver/inferiors.c b/gdb/gdbserver/inferiors.c
index e78ad4faf1..326d01f4d9 100644
--- a/gdb/gdbserver/inferiors.c
+++ b/gdb/gdbserver/inferiors.c
@@ -456,3 +456,12 @@  get_inferior_cwd ()
 {
   return current_inferior_cwd;
 }
+
+/* See common/common-inferior.h.  */
+
+void
+set_inferior_cwd (const char *cwd)
+{
+  xfree ((void *) current_inferior_cwd);
+  current_inferior_cwd = xstrdup (cwd);
+}
diff --git a/gdb/gdbserver/server.c b/gdb/gdbserver/server.c
index f3eee31052..14f8a732a7 100644
--- a/gdb/gdbserver/server.c
+++ b/gdb/gdbserver/server.c
@@ -869,6 +869,21 @@  handle_general_set (char *own_buf)
       return;
     }
 
+  if (startswith (own_buf, "QSetWorkingDir:"))
+    {
+      const char *p = own_buf + strlen ("QSetWorkingDir:");
+      std::string path = hex2str (p);
+
+      set_inferior_cwd (path.c_str ());
+
+      if (remote_debug)
+	debug_printf (_("[Changed current directory to %s]\n"),
+		      path.c_str ());
+      write_ok (own_buf);
+
+      return;
+    }
+
   /* Otherwise we didn't know what packet it was.  Say we didn't
      understand it.  */
   own_buf[0] = 0;
@@ -2355,7 +2370,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 cc84d15c2f..62b222d2fa 100644
--- a/gdb/gdbserver/win32-low.c
+++ b/gdb/gdbserver/win32-low.c
@@ -562,10 +562,11 @@  static BOOL
 create_process (const char *program, char *args,
 		DWORD flags, PROCESS_INFORMATION *pi)
 {
+  const char *inferior_cwd = get_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 +580,14 @@  create_process (const char *program, char *args,
   wargs = alloca ((argslen + 1) * sizeof (wchar_t));
   mbstowcs (wargs, args, argslen + 1);
 
+  if (inferior_cwd != NULL)
+    {
+      size_t cwdlen = strlen (inferior_cwd);
+
+      wcwd = alloca ((cwdlen + 1) * sizeof (wchar_t));
+      mbstowcs (wcwd, inferior_cwd, cwdlen + 1);
+    }
+
   ret = CreateProcessW (wprogram, /* image name */
 			wargs,    /* command line */
 			NULL,     /* security, not supported */
@@ -586,7 +595,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 +608,7 @@  create_process (const char *program, char *args,
 			TRUE,     /* inherit handles */
 			flags,    /* start flags */
 			NULL,     /* environment */
-			NULL,     /* current directory */
+			inferior_cwd,     /* current directory */
 			&si,      /* start info */
 			pi);      /* proc info */
 #endif
diff --git a/gdb/infcmd.c b/gdb/infcmd.c
index 4c5bbfdbf2..f483a33a44 100644
--- a/gdb/infcmd.c
+++ b/gdb/infcmd.c
@@ -250,9 +250,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.  */
+/* See common/common-inferior.h.  */
 
-static void
+void
 set_inferior_cwd (const char *cwd)
 {
   if (*cwd == '\0')
@@ -292,7 +292,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 gdbserver's\n\
+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 33b0c2a09d..18d3aaea3f 100644
--- a/gdb/remote.c
+++ b/gdb/remote.c
@@ -1434,6 +1434,7 @@  enum {
   PACKET_QPassSignals,
   PACKET_QCatchSyscalls,
   PACKET_QProgramSignals,
+  PACKET_QSetWorkingDir,
   PACKET_QStartupWithShell,
   PACKET_QEnvironmentHexEncoded,
   PACKET_QEnvironmentReset,
@@ -4665,6 +4666,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,
@@ -9644,6 +9647,35 @@  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 ());
+	  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 changing working 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
@@ -9686,6 +9718,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)
@@ -14185,6 +14219,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/gdb.base/set-cwd.exp b/gdb/testsuite/gdb.base/set-cwd.exp
index f2700ec44d..32458e384e 100644
--- a/gdb/testsuite/gdb.base/set-cwd.exp
+++ b/gdb/testsuite/gdb.base/set-cwd.exp
@@ -15,11 +15,18 @@ 
 # 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 gdbserver"
+if { [use_gdb_stub] } {
+    untested "not valid on native-gdbserver"
     return
 }
 
+if { [target_info gdb_protocol] == "remote" } {
+    load_lib gdbserver-support.exp
+    if { [skip_gdbserver_tests] } {
+	return
+    }
+}
+
 standard_testfile
 
 if { [prepare_for_testing "failed to prepare" $testfile $srcfile debug] } {