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

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

Commit Message

Sergio Durigan Junior Sept. 19, 2017, 4:28 a.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) 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".
	* remote.c: Add PACKET_QSetWorkingDir.
	(remote_protocol_features) <QSetWorkingDir>: New entry for
	PACKET_QSetWorkingDir.
	(extended_remote_handle_inferior_cwd): New function.
	(extended_remote_create_inferior): Call
	"extended_remote_handle_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 "inferior_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                           | 11 ++++++++++
 gdb/common/common-inferior.h       |  4 ++++
 gdb/doc/gdb.texinfo                | 44 ++++++++++++++++++++++++++++++++++----
 gdb/gdbserver/inferiors.c          |  9 ++++++++
 gdb/gdbserver/server.c             | 18 +++++++++++++++-
 gdb/gdbserver/win32-low.c          |  5 +++--
 gdb/infcmd.c                       |  5 ++---
 gdb/remote.c                       | 35 ++++++++++++++++++++++++++++++
 gdb/testsuite/gdb.base/set-cwd.exp | 14 ++++++++----
 9 files changed, 131 insertions(+), 14 deletions(-)
  

Comments

Pedro Alves Sept. 20, 2017, 2:34 p.m. UTC | #1
On 09/19/2017 05:28 AM, 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.
> 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) 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".
> 	* remote.c: Add PACKET_QSetWorkingDir.
> 	(remote_protocol_features) <QSetWorkingDir>: New entry for
> 	PACKET_QSetWorkingDir.
> 	(extended_remote_handle_inferior_cwd): New function.
> 	(extended_remote_create_inferior): Call
> 	"extended_remote_handle_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 "inferior_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                           | 11 ++++++++++
>  gdb/common/common-inferior.h       |  4 ++++
>  gdb/doc/gdb.texinfo                | 44 ++++++++++++++++++++++++++++++++++----
>  gdb/gdbserver/inferiors.c          |  9 ++++++++
>  gdb/gdbserver/server.c             | 18 +++++++++++++++-
>  gdb/gdbserver/win32-low.c          |  5 +++--
>  gdb/infcmd.c                       |  5 ++---
>  gdb/remote.c                       | 35 ++++++++++++++++++++++++++++++
>  gdb/testsuite/gdb.base/set-cwd.exp | 14 ++++++++----
>  9 files changed, 131 insertions(+), 14 deletions(-)
> 
> diff --git a/gdb/NEWS b/gdb/NEWS
> index 0dcfcc98af..a0f78e4c35 100644
> --- a/gdb/NEWS
> +++ b/gdb/NEWS
> @@ -39,6 +39,14 @@
>       variables that are to be set or unset from GDB.  These variables
>       will affect the environment to be passed to the inferior.
>  
> +  ** On Unix systems, GDBserver is now able to enter a directory
> +     before starting an inferior.
> +
> +     This is done by using the "cd" command in GDB, which instructs it
> +     to tell GDBserver about this directory change the next time an
> +     inferior is run.  If you want to make GDBserver enter the
> +     directory your GDB is currently in, you can do a "cd ." in GDB.

This all looks stale to me.

> +
>  * New remote packets
>  
>  QEnvironmentHexEncoded
> @@ -56,6 +64,9 @@ QEnvironmentReset
>  QStartupWithShell
>    Indicates whether the inferior must be started with a shell or not.
>  
> +QSetWorkingDir
> +  Tell GDBserver to enter another directory before starting the inferior.

Should this really be described in terms of gdbserver entering a
directory?  That seems like fork-child implementation detail.
Do we really want this to affect gdbserver's current directory
as well, maybe in future use cases, or just the inferior's cwd?

> --- 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.  This directory will be
> +   entered by the debugger before executing the inferior.  */
> +extern void set_inferior_cwd (const char *cwd);

Again described in terms of target implementation detail.

> +
>  #endif /* ! COMMON_INFERIOR_H */
> diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo
> index c513a49c26..fc20a74bce 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
> @@ -2429,7 +2431,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.
> @@ -2444,7 +2448,8 @@ Specify Files}.
>  @item set cwd @r{[}@var{directory}@r{]}
>  Set the inferior's working directory to @var{directory}.  If not
>  given, @var{directory} uses @file{'~'}.  This has no effect on
> -@value{GDBN}'s working directory.
> +@value{GDBN}'s working directory.  This setting works for both native
> +and remote debugging.

Not sure we should add such a sentence for a particular command alone;
If I read the resulting manual without context of this patch, I wonder
whether this means that the other settings described above (like e.g.,
set args/environment) don't work with remote debugging.

>  
>  @kindex show cwd
>  @cindex show inferior's working directory
> @@ -20982,6 +20987,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{cd}

This reference to "cd" is probably incorrect in this version and should
be "set cwd", right?

> +
>  @item @code{conditional-breakpoints-packet}
>  @tab @code{Z0 and Z1}
>  @tab @code{Support for target-side breakpoint condition evaluation}
> @@ -36770,6 +36779,30 @@ 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
> +On UNIX-like targets, it is possible to set the current working
> +directory that @command{gdbserver} will enter before starting the
> +inferior.  This packet is used to inform @command{gdbserver} of a
> +directory into which it should enter during the startup process.

I don't see why this is talking about Unix-like targets in particular.
You're making it work on Windows too, right?  I don't think we should
talk in terms of gdbserver, for the matter.  I think the first sentence
could all go away.  We should instead say that this packet is used to
inform the remote server of the intended current directory for programs
that are next run.

> +
> +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{cd}
> +command in @value{GDBN} (@pxref{Working Directory, ,Your Program's
> +Working Directory}).

Reference to "cd" is stale.

> +
> +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,
> @@ -36800,6 +36833,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 f4faff9d77..a159708632 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;
> @@ -2345,7 +2360,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..b9fff29d74 100644
> --- a/gdb/gdbserver/win32-low.c
> +++ b/gdb/gdbserver/win32-low.c
> @@ -562,6 +562,7 @@ 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
> @@ -586,7 +587,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 */
> +			inferior_cwd,     /* current directory */
>  			NULL,     /* start info, not supported */
>  			pi);      /* proc info */

This path takes a wide string, so you'd need to 
do the alloca + mbstowcs above, like done with wprogram.

>  #else
> @@ -599,7 +600,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 178a3ca15f..a51a3d4e40 100644

>  
> +/* Helper function to handle the change of the current working
> +   directory in the remote.  */
> +
> +static void
> +extended_remote_handle_inferior_cwd (struct remote_state *rs)

I'd call "set", not "handle" (ditto comments).  "handle" to me
indicates that you're handling a command that you received.  But
here we're sending the command.

> +{
> +  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 (strcmp (rs->buf, "OK") != 0)
> +	    error (_("\
> +Remote replied unexpectedly while changing working directory: %s"),
> +		   rs->buf);

Please use packet_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
> @@ -9658,6 +9688,8 @@ Remote replied unexpectedly while setting startup-with-shell: %s"),
>  
>    extended_remote_environment_support (rs);
>  
> +  extended_remote_handle_inferior_cwd (rs);
> +
>    /* Now restart the remote server.  */
>    run_worked = extended_remote_run (args) != -1;
>    if (!run_worked)
> @@ -14126,6 +14158,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 3a6ffd3862..d3104287a0 100644
> --- a/gdb/testsuite/gdb.base/set-cwd.exp
> +++ b/gdb/testsuite/gdb.base/set-cwd.exp
> @@ -15,10 +15,16 @@
>  # 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 { ![isnative] || [is_remote target] || [is_remote host]
> -     || [target_info gdb_protocol] == "extended-remote" } then {
> -    untested "not implemented on gdbserver"
> -    return
> +if { [target_info exists gdb_protocol] } {
> +    if { [target_info gdb_protocol] == "remote" } {
> +	untested "not implemented on native-gdbserver"
> +	return
> +    }
> +
> +    load_lib gdbserver-support.exp
> +    if { [skip_gdbserver_tests] } {
> +	return
> +    }
>  }

This drops the is_remote host and target checks, but the test is
using  "$::env(HOME)", so it really can't work when
remote-host/target testing, because that is accessing HOME in the
build machine (where dejagnu runs) not of the host machine
(where gdb runs) or the target machine (where gdbserver runs):

proc test_tilde_expansion { } {
    if { [info exists ::env(HOME)] } {
	with_test_prefix "test tilde expansion" {
	    set home $::env(HOME)


I don't understand the explicit check for gdbserver in
skip_gdbserver_tests.

Seems to me that instead of that, and the "remote" check we should skip
the test if use_gdb_stub, because that's what indicates that when you
connect to a target, you're already debugging something, like with
plain remote debugging.

Thanks,
Pedro Alves
  
Sergio Durigan Junior Sept. 20, 2017, 11:49 p.m. UTC | #2
On Wednesday, September 20 2017, Pedro Alves wrote:

> On 09/19/2017 05:28 AM, 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.
>> 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) 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".
>> 	* remote.c: Add PACKET_QSetWorkingDir.
>> 	(remote_protocol_features) <QSetWorkingDir>: New entry for
>> 	PACKET_QSetWorkingDir.
>> 	(extended_remote_handle_inferior_cwd): New function.
>> 	(extended_remote_create_inferior): Call
>> 	"extended_remote_handle_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 "inferior_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                           | 11 ++++++++++
>>  gdb/common/common-inferior.h       |  4 ++++
>>  gdb/doc/gdb.texinfo                | 44 ++++++++++++++++++++++++++++++++++----
>>  gdb/gdbserver/inferiors.c          |  9 ++++++++
>>  gdb/gdbserver/server.c             | 18 +++++++++++++++-
>>  gdb/gdbserver/win32-low.c          |  5 +++--
>>  gdb/infcmd.c                       |  5 ++---
>>  gdb/remote.c                       | 35 ++++++++++++++++++++++++++++++
>>  gdb/testsuite/gdb.base/set-cwd.exp | 14 ++++++++----
>>  9 files changed, 131 insertions(+), 14 deletions(-)
>> 
>> diff --git a/gdb/NEWS b/gdb/NEWS
>> index 0dcfcc98af..a0f78e4c35 100644
>> --- a/gdb/NEWS
>> +++ b/gdb/NEWS
>> @@ -39,6 +39,14 @@
>>       variables that are to be set or unset from GDB.  These variables
>>       will affect the environment to be passed to the inferior.
>>  
>> +  ** On Unix systems, GDBserver is now able to enter a directory
>> +     before starting an inferior.
>> +
>> +     This is done by using the "cd" command in GDB, which instructs it
>> +     to tell GDBserver about this directory change the next time an
>> +     inferior is run.  If you want to make GDBserver enter the
>> +     directory your GDB is currently in, you can do a "cd ." in GDB.
>
> This all looks stale to me.

Indeed, sorry about this mistake.  I will rewrite the entry as follows:

* New features in the GDB remote stub, GDBserver

  ** GDBserver is now able to enter a directory before starting an
     inferior.

     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 remote packets
>>  
>>  QEnvironmentHexEncoded
>> @@ -56,6 +64,9 @@ QEnvironmentReset
>>  QStartupWithShell
>>    Indicates whether the inferior must be started with a shell or not.
>>  
>> +QSetWorkingDir
>> +  Tell GDBserver to enter another directory before starting the inferior.
>
> Should this really be described in terms of gdbserver entering a
> directory?  That seems like fork-child implementation detail.
> Do we really want this to affect gdbserver's current directory
> as well, maybe in future use cases, or just the inferior's cwd?

I've changed the description of the packet to:

QSetWorkingDir
  Tell GDBserver that the inferior to be started should use a specific
  working directory.

As for your other question, I assume that if we ever want to change
gdbserver's cwd the best way would be to create a different packet, so
as not to confuse with this one.

>> --- 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.  This directory will be
>> +   entered by the debugger before executing the inferior.  */
>> +extern void set_inferior_cwd (const char *cwd);
>
> Again described in terms of target implementation detail.

Removed the target-specific part.

>> +
>>  #endif /* ! COMMON_INFERIOR_H */
>> diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo
>> index c513a49c26..fc20a74bce 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
>> @@ -2429,7 +2431,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.
>> @@ -2444,7 +2448,8 @@ Specify Files}.
>>  @item set cwd @r{[}@var{directory}@r{]}
>>  Set the inferior's working directory to @var{directory}.  If not
>>  given, @var{directory} uses @file{'~'}.  This has no effect on
>> -@value{GDBN}'s working directory.
>> +@value{GDBN}'s working directory.  This setting works for both native
>> +and remote debugging.
>
> Not sure we should add such a sentence for a particular command alone;
> If I read the resulting manual without context of this patch, I wonder
> whether this means that the other settings described above (like e.g.,
> set args/environment) don't work with remote debugging.

Good point.  Here's what we say a little above:

  @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 if
  native debugging, or @code{gdbserver}'s working directory if remote
  debugging.  @xref{Working Directory, ,Your Program's Working
  Directory}.

This makes it clear that the feature works for both scenarios, so I
think it's safe to just remove the sentence on "set cwd".  This is what
I'll do.

>
>>  
>>  @kindex show cwd
>>  @cindex show inferior's working directory
>> @@ -20982,6 +20987,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{cd}
>
> This reference to "cd" is probably incorrect in this version and should
> be "set cwd", right?

Right, fixed.  Thanks.

>> +
>>  @item @code{conditional-breakpoints-packet}
>>  @tab @code{Z0 and Z1}
>>  @tab @code{Support for target-side breakpoint condition evaluation}
>> @@ -36770,6 +36779,30 @@ 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
>> +On UNIX-like targets, it is possible to set the current working
>> +directory that @command{gdbserver} will enter before starting the
>> +inferior.  This packet is used to inform @command{gdbserver} of a
>> +directory into which it should enter during the startup process.
>
> I don't see why this is talking about Unix-like targets in particular.
> You're making it work on Windows too, right?  I don't think we should
> talk in terms of gdbserver, for the matter.  I think the first sentence
> could all go away.  We should instead say that this packet is used to
> inform the remote server of the intended current directory for programs
> that are next run.

Makes sense, now that you've pointed out many other places that are
referring to target-specific details.  I'll rewrite this part as:

@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{cd}
>> +command in @value{GDBN} (@pxref{Working Directory, ,Your Program's
>> +Working Directory}).
>
> Reference to "cd" is stale.

Fixed.

>> +
>> +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,
>> @@ -36800,6 +36833,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 f4faff9d77..a159708632 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;
>> @@ -2345,7 +2360,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..b9fff29d74 100644
>> --- a/gdb/gdbserver/win32-low.c
>> +++ b/gdb/gdbserver/win32-low.c
>> @@ -562,6 +562,7 @@ 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
>> @@ -586,7 +587,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 */
>> +			inferior_cwd,     /* current directory */
>>  			NULL,     /* start info, not supported */
>>  			pi);      /* proc info */
>
> This path takes a wide string, so you'd need to 
> do the alloca + mbstowcs above, like done with wprogram.

Ah, didn't know that.  Improved the code to do it.

>>  #else
>> @@ -599,7 +600,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 178a3ca15f..a51a3d4e40 100644
>
>>  
>> +/* Helper function to handle the change of the current working
>> +   directory in the remote.  */
>> +
>> +static void
>> +extended_remote_handle_inferior_cwd (struct remote_state *rs)
>
> I'd call "set", not "handle" (ditto comments).  "handle" to me
> indicates that you're handling a command that you received.  But
> here we're sending the command.

OK, done.

>> +{
>> +  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 (strcmp (rs->buf, "OK") != 0)
>> +	    error (_("\
>> +Remote replied unexpectedly while changing working directory: %s"),
>> +		   rs->buf);
>
> Please use packet_ok.

Done.

>> +	}
>> +    }
>> +}
>> +
>>  /* 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
>> @@ -9658,6 +9688,8 @@ Remote replied unexpectedly while setting startup-with-shell: %s"),
>>  
>>    extended_remote_environment_support (rs);
>>  
>> +  extended_remote_handle_inferior_cwd (rs);
>> +
>>    /* Now restart the remote server.  */
>>    run_worked = extended_remote_run (args) != -1;
>>    if (!run_worked)
>> @@ -14126,6 +14158,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 3a6ffd3862..d3104287a0 100644
>> --- a/gdb/testsuite/gdb.base/set-cwd.exp
>> +++ b/gdb/testsuite/gdb.base/set-cwd.exp
>> @@ -15,10 +15,16 @@
>>  # 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 { ![isnative] || [is_remote target] || [is_remote host]
>> -     || [target_info gdb_protocol] == "extended-remote" } then {
>> -    untested "not implemented on gdbserver"
>> -    return
>> +if { [target_info exists gdb_protocol] } {
>> +    if { [target_info gdb_protocol] == "remote" } {
>> +	untested "not implemented on native-gdbserver"
>> +	return
>> +    }
>> +
>> +    load_lib gdbserver-support.exp
>> +    if { [skip_gdbserver_tests] } {
>> +	return
>> +    }
>>  }
>
> This drops the is_remote host and target checks, but the test is
> using  "$::env(HOME)", so it really can't work when
> remote-host/target testing, because that is accessing HOME in the
> build machine (where dejagnu runs) not of the host machine
> (where gdb runs) or the target machine (where gdbserver runs):
>
> proc test_tilde_expansion { } {
>     if { [info exists ::env(HOME)] } {
> 	with_test_prefix "test tilde expansion" {
> 	    set home $::env(HOME)

OK, that makes sense, but I wasn't aware that there is a problem between
"host" and "build" machines.  This is becoming absurdly confuse to me,
sorry.

In this case, I'd have to check for ![is_remote host], is that right?

> I don't understand the explicit check for gdbserver in
> skip_gdbserver_tests.

I was thinking of the following scenario:

- The users wants to skip gdbserver tests

- He runs the test as "make check-gdb TESTS=gdb.base/set-cwd.exp"

- Because of the unconditional call to "skip_gdbserver_tests", the test
  doesn't run at all, even though the test *should* run because the user
  hasn't specified any remote board, etc.

> Seems to me that instead of that, and the "remote" check we should skip
> the test if use_gdb_stub, because that's what indicates that when you
> connect to a target, you're already debugging something, like with
> plain remote debugging.

OK, so a simple check to "[use_gdb_stub]" would suffice, you say?  That
doesn't solve the problem with calling ::env above, right?
  
Sergio Durigan Junior Sept. 21, 2017, 1:37 a.m. UTC | #3
On Wednesday, September 20 2017, I wrote:

> On Wednesday, September 20 2017, Pedro Alves wrote:
>
>> On 09/19/2017 05:28 AM, 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.
>>> 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) 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".
>>> 	* remote.c: Add PACKET_QSetWorkingDir.
>>> 	(remote_protocol_features) <QSetWorkingDir>: New entry for
>>> 	PACKET_QSetWorkingDir.
>>> 	(extended_remote_handle_inferior_cwd): New function.
>>> 	(extended_remote_create_inferior): Call
>>> 	"extended_remote_handle_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 "inferior_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                           | 11 ++++++++++
>>>  gdb/common/common-inferior.h       |  4 ++++
>>>  gdb/doc/gdb.texinfo                | 44 ++++++++++++++++++++++++++++++++++----
>>>  gdb/gdbserver/inferiors.c          |  9 ++++++++
>>>  gdb/gdbserver/server.c             | 18 +++++++++++++++-
>>>  gdb/gdbserver/win32-low.c          |  5 +++--
>>>  gdb/infcmd.c                       |  5 ++---
>>>  gdb/remote.c                       | 35 ++++++++++++++++++++++++++++++
>>>  gdb/testsuite/gdb.base/set-cwd.exp | 14 ++++++++----
>>>  9 files changed, 131 insertions(+), 14 deletions(-)
>>> 
>>> diff --git a/gdb/NEWS b/gdb/NEWS
>>> index 0dcfcc98af..a0f78e4c35 100644
>>> --- a/gdb/NEWS
>>> +++ b/gdb/NEWS
>>> @@ -39,6 +39,14 @@
>>>       variables that are to be set or unset from GDB.  These variables
>>>       will affect the environment to be passed to the inferior.
>>>  
>>> +  ** On Unix systems, GDBserver is now able to enter a directory
>>> +     before starting an inferior.
>>> +
>>> +     This is done by using the "cd" command in GDB, which instructs it
>>> +     to tell GDBserver about this directory change the next time an
>>> +     inferior is run.  If you want to make GDBserver enter the
>>> +     directory your GDB is currently in, you can do a "cd ." in GDB.
>>
>> This all looks stale to me.
>
> Indeed, sorry about this mistake.  I will rewrite the entry as follows:
>
> * New features in the GDB remote stub, GDBserver
>
>   ** GDBserver is now able to enter a directory before starting an
>      inferior.
>
>      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.

Actually, the first sentence is still wrong.  How about:

  ** 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.

?
  
Pedro Alves Sept. 22, 2017, 10:47 a.m. UTC | #4
On 09/21/2017 12:49 AM, Sergio Durigan Junior wrote:
> On Wednesday, September 20 2017, Pedro Alves wrote:

>> This all looks stale to me.
> 
> Indeed, sorry about this mistake.  I will rewrite the entry as follows:
> 
> * New features in the GDB remote stub, GDBserver
> 
>   ** GDBserver is now able to enter a directory before starting an
>      inferior.
> 
>      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.

I still think this is talking too much in terms of implementation
detail, but I'll reply again to v3.

>>> --- a/gdb/testsuite/gdb.base/set-cwd.exp
>>> +++ b/gdb/testsuite/gdb.base/set-cwd.exp
>>> @@ -15,10 +15,16 @@
>>>  # 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 { ![isnative] || [is_remote target] || [is_remote host]
>>> -     || [target_info gdb_protocol] == "extended-remote" } then {
>>> -    untested "not implemented on gdbserver"
>>> -    return
>>> +if { [target_info exists gdb_protocol] } {
>>> +    if { [target_info gdb_protocol] == "remote" } {
>>> +	untested "not implemented on native-gdbserver"
>>> +	return
>>> +    }
>>> +
>>> +    load_lib gdbserver-support.exp
>>> +    if { [skip_gdbserver_tests] } {
>>> +	return
>>> +    }
>>>  }
>>
>> This drops the is_remote host and target checks, but the test is
>> using  "$::env(HOME)", so it really can't work when
>> remote-host/target testing, because that is accessing HOME in the
>> build machine (where dejagnu runs) not of the host machine
>> (where gdb runs) or the target machine (where gdbserver runs):
>>
>> proc test_tilde_expansion { } {
>>     if { [info exists ::env(HOME)] } {
>> 	with_test_prefix "test tilde expansion" {
>> 	    set home $::env(HOME)
> 
> OK, that makes sense, but I wasn't aware that there is a problem between
> "host" and "build" machines.  This is becoming absurdly confuse to me,
> sorry.

We've discussed this off list already.

> 
> In this case, I'd have to check for ![is_remote host], is that right?
> 
>> I don't understand the explicit check for gdbserver in
>> skip_gdbserver_tests.
> 
> I was thinking of the following scenario:
> 
> - The users wants to skip gdbserver tests
> 
> - He runs the test as "make check-gdb TESTS=gdb.base/set-cwd.exp"
> 
> - Because of the unconditional call to "skip_gdbserver_tests", the test
>   doesn't run at all, even though the test *should* run because the user
>   hasn't specified any remote board, etc.

And that's what I don't understand at all.  skip_gdbserver_tests
is useful for the gdb.server/ tests that spawn gdbserver even
if testing with the local/unix board, i.e., the native target.
But this testcase isn't spawning gdbserver manually, unlike e.g., the
gdb.server/ tests.  It just runs against whatever target is
specified by --target_board.

> 
>> Seems to me that instead of that, and the "remote" check we should skip
>> the test if use_gdb_stub, because that's what indicates that when you
>> connect to a target, you're already debugging something, like with
>> plain remote debugging.
> 
> OK, so a simple check to "[use_gdb_stub]" would suffice, you say?  That
> doesn't solve the problem with calling ::env above, right?

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

> On 09/21/2017 12:49 AM, Sergio Durigan Junior wrote:
>> On Wednesday, September 20 2017, Pedro Alves wrote:
>
>>> This all looks stale to me.
>> 
>> Indeed, sorry about this mistake.  I will rewrite the entry as follows:
>> 
>> * New features in the GDB remote stub, GDBserver
>> 
>>   ** GDBserver is now able to enter a directory before starting an
>>      inferior.
>> 
>>      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.
>
> I still think this is talking too much in terms of implementation
> detail, but I'll reply again to v3.

I'm curious to know why.  I'll wait for your review.

>> In this case, I'd have to check for ![is_remote host], is that right?
>> 
>>> I don't understand the explicit check for gdbserver in
>>> skip_gdbserver_tests.
>> 
>> I was thinking of the following scenario:
>> 
>> - The users wants to skip gdbserver tests
>> 
>> - He runs the test as "make check-gdb TESTS=gdb.base/set-cwd.exp"
>> 
>> - Because of the unconditional call to "skip_gdbserver_tests", the test
>>   doesn't run at all, even though the test *should* run because the user
>>   hasn't specified any remote board, etc.
>
> And that's what I don't understand at all.  skip_gdbserver_tests
> is useful for the gdb.server/ tests that spawn gdbserver even
> if testing with the local/unix board, i.e., the native target.
> But this testcase isn't spawning gdbserver manually, unlike e.g., the
> gdb.server/ tests.  It just runs against whatever target is
> specified by --target_board.

Ah.  Then I *really* misunderstood these concepts.  Thanks for
clarifying this to me.  v3 still has the call to "skip_gdbserver_tests",
so please ignore it.

Thanks,
  
Pedro Alves Sept. 27, 2017, 1:28 p.m. UTC | #6
On 09/22/2017 07:33 PM, Sergio Durigan Junior wrote:
> On Friday, September 22 2017, Pedro Alves wrote:
> 
>> On 09/21/2017 12:49 AM, Sergio Durigan Junior wrote:
>>> On Wednesday, September 20 2017, Pedro Alves wrote:
>>
>>>> This all looks stale to me.
>>>
>>> Indeed, sorry about this mistake.  I will rewrite the entry as follows:
>>>
>>> * New features in the GDB remote stub, GDBserver
>>>
>>>   ** GDBserver is now able to enter a directory before starting an
>>>      inferior.
>>>
>>>      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.
>>
>> I still think this is talking too much in terms of implementation
>> detail, but I'll reply again to v3.
> 
> I'm curious to know why.  I'll wait for your review.

Specifically:

 "GDBserver is now able to enter a directory before starting an inferior."

This is Unix/fork specific.

 "to tell GDBserver about this directory change"

"change" seems to imply GDBserver itself changes dir.  The new inferior
never changes directory because it is started with the specified
directory in the first place.

I'll go look at v3 now.

Thanks,
Pedro Alves
  

Patch

diff --git a/gdb/NEWS b/gdb/NEWS
index 0dcfcc98af..a0f78e4c35 100644
--- a/gdb/NEWS
+++ b/gdb/NEWS
@@ -39,6 +39,14 @@ 
      variables that are to be set or unset from GDB.  These variables
      will affect the environment to be passed to the inferior.
 
+  ** On Unix systems, GDBserver is now able to enter a directory
+     before starting an inferior.
+
+     This is done by using the "cd" command in GDB, which instructs it
+     to tell GDBserver about this directory change the next time an
+     inferior is run.  If you want to make GDBserver enter the
+     directory your GDB is currently in, you can do a "cd ." in GDB.
+
 * New remote packets
 
 QEnvironmentHexEncoded
@@ -56,6 +64,9 @@  QEnvironmentReset
 QStartupWithShell
   Indicates whether the inferior must be started with a shell or not.
 
+QSetWorkingDir
+  Tell GDBserver to enter another directory before starting the inferior.
+
 * 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..65c23a936b 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.  This directory will be
+   entered by the debugger before executing the inferior.  */
+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 c513a49c26..fc20a74bce 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
@@ -2429,7 +2431,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.
@@ -2444,7 +2448,8 @@  Specify Files}.
 @item set cwd @r{[}@var{directory}@r{]}
 Set the inferior's working directory to @var{directory}.  If not
 given, @var{directory} uses @file{'~'}.  This has no effect on
-@value{GDBN}'s working directory.
+@value{GDBN}'s working directory.  This setting works for both native
+and remote debugging.
 
 @kindex show cwd
 @cindex show inferior's working directory
@@ -20982,6 +20987,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{cd}
+
 @item @code{conditional-breakpoints-packet}
 @tab @code{Z0 and Z1}
 @tab @code{Support for target-side breakpoint condition evaluation}
@@ -36770,6 +36779,30 @@  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
+On UNIX-like targets, it is possible to set the current working
+directory that @command{gdbserver} will enter before starting the
+inferior.  This packet is used to inform @command{gdbserver} of a
+directory into which it should enter during the startup process.
+
+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{cd}
+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,
@@ -36800,6 +36833,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 f4faff9d77..a159708632 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;
@@ -2345,7 +2360,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..b9fff29d74 100644
--- a/gdb/gdbserver/win32-low.c
+++ b/gdb/gdbserver/win32-low.c
@@ -562,6 +562,7 @@  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
@@ -586,7 +587,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 */
+			inferior_cwd,     /* current directory */
 			NULL,     /* start info, not supported */
 			pi);      /* proc info */
 #else
@@ -599,7 +600,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 178a3ca15f..a51a3d4e40 100644
--- a/gdb/infcmd.c
+++ b/gdb/infcmd.c
@@ -252,10 +252,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.  This directory will be
-   entered by GDB before executing the inferior.  */
+/* See common/common-inferior.h.  */
 
-static void
+void
 set_inferior_cwd (const char *cwd)
 {
   struct inferior *inf = current_inferior ();
diff --git a/gdb/remote.c b/gdb/remote.c
index 0963693a22..d900157ca9 100644
--- a/gdb/remote.c
+++ b/gdb/remote.c
@@ -1428,6 +1428,7 @@  enum {
   PACKET_QPassSignals,
   PACKET_QCatchSyscalls,
   PACKET_QProgramSignals,
+  PACKET_QSetWorkingDir,
   PACKET_QStartupWithShell,
   PACKET_QEnvironmentHexEncoded,
   PACKET_QEnvironmentReset,
@@ -4637,6 +4638,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,
@@ -9616,6 +9619,33 @@  extended_remote_environment_support (struct remote_state *rs)
       send_environment_packet (rs, "unset", "QEnvironmentUnset", el.c_str ());
 }
 
+/* Helper function to handle the change of the current working
+   directory in the remote.  */
+
+static void
+extended_remote_handle_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 (strcmp (rs->buf, "OK") != 0)
+	    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
@@ -9658,6 +9688,8 @@  Remote replied unexpectedly while setting startup-with-shell: %s"),
 
   extended_remote_environment_support (rs);
 
+  extended_remote_handle_inferior_cwd (rs);
+
   /* Now restart the remote server.  */
   run_worked = extended_remote_run (args) != -1;
   if (!run_worked)
@@ -14126,6 +14158,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 3a6ffd3862..d3104287a0 100644
--- a/gdb/testsuite/gdb.base/set-cwd.exp
+++ b/gdb/testsuite/gdb.base/set-cwd.exp
@@ -15,10 +15,16 @@ 
 # 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 { ![isnative] || [is_remote target] || [is_remote host]
-     || [target_info gdb_protocol] == "extended-remote" } then {
-    untested "not implemented on gdbserver"
-    return
+if { [target_info exists gdb_protocol] } {
+    if { [target_info gdb_protocol] == "remote" } {
+	untested "not implemented on native-gdbserver"
+	return
+    }
+
+    load_lib gdbserver-support.exp
+    if { [skip_gdbserver_tests] } {
+	return
+    }
 }
 
 standard_testfile