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


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

Re: [PATCH v2 5/5] Extend "set cwd" to work on gdbserver


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
GPG key ID: 237A 54B1 0287 28BF 00EF  31F4 D0EB 7628 65FC 5E36
Please send encrypted e-mail if possible
http://sergiodj.net/


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