[3/3,v3] Implement remote_bfd_iovec_stat using vFile:fstat

Message ID 1426002678-30472-1-git-send-email-gbenson@redhat.com
State Superseded
Headers

Commit Message

Gary Benson March 10, 2015, 3:51 p.m. UTC
  Sorry for the noise on this patch, but I found a comment that
needed updating.  This version (v3) of this patch contains that
update (to symfile.c).  Version 2 of this patch removed a few
lines of random debug code I'd left in remote_bfd_iovec_stat.
Aside from those tweaks, the remainder of the patch is as
originally mailed.

---
This patch implements the function remote_bfd_iovec_stat using a
vFile:fstat hostio call to the remote target.  If vFile:fstat is
not supported GDB creates a dummy result by zeroing the supplied
stat structure and then setting it's st_size field to INT_MAX.
This mimic's GDB's previous behaviour, with the exception that
GDB did not previously zero the structure so all other fields
would have been returned unchanged, which is to say very likely
populated with random values from the stack.

gdb/ChangeLog:

	* remote-fileio.h (remote_fileio_to_host_stat): New declaration.
	* remote-fileio.c (remote_fileio_to_host_uint): New function.
	(remote_fileio_to_host_ulong): Likewise.
	(remote_fileio_to_host_mode): Likewise.
	(remote_fileio_to_host_time): Likewise.
	(remote_fileio_to_host_stat): Likewise.
	* remote.c (PACKET_vFile_fstat): New enum value.
	(remote_protocol_features): Register the "vFile:fstat" feature.
	(remote_hostio_fstat): New function.
	(remote_bfd_iovec_stat): Use the above.
	(_initialize_remote): Register new "set/show remote
	hostio-fstat-packet" command.
	* symfile.c (separate_debug_file_exists): Update comment.

gdb/doc/ChangeLog:

	* gdb.texinfo (Remote Configuration): Document the
	"set/show remote hostio-fstat-packet" command.
---
 gdb/ChangeLog       |   16 ++++++++++
 gdb/doc/ChangeLog   |    5 +++
 gdb/doc/gdb.texinfo |    4 ++
 gdb/remote-fileio.c |   80 +++++++++++++++++++++++++++++++++++++++++++++++++++
 gdb/remote-fileio.h |    4 ++
 gdb/remote.c        |   74 ++++++++++++++++++++++++++++++++++++++++++++--
 gdb/symfile.c       |   17 ++++++-----
 7 files changed, 188 insertions(+), 12 deletions(-)
  

Comments

Pedro Alves March 10, 2015, 6:31 p.m. UTC | #1
On 03/10/2015 03:51 PM, Gary Benson wrote:
> 
> +
> +/* Unpack an fio_uint_t.  */
> +
> +static unsigned int
> +remote_fileio_to_host_uint (fio_uint_t fnum)
> +{
> +  gdb_byte *buf, *lim;
> +  unsigned int num = 0;
> +
> +  for (buf = (gdb_byte *) fnum, lim = buf + 4; buf < lim; buf++)
> +    {
> +      num <<= 8;
> +      num |= *buf;
> +    }

How about we use

  extract_unsigned_integer ((gdb_byte *) fnum, 4, BFD_ENDIAN_BIG)

instead?

Otherwise looks good.

Thanks,
Pedro Alves
  
Pedro Alves March 10, 2015, 6:36 p.m. UTC | #2
Sorry, forgot to merge this comment with the other mail...

On 03/10/2015 03:51 PM, Gary Benson wrote:
> +   into ST.  Return 0 on success, or -1 if an error occurs (and
> +   set *REMOTE_ERRNO).  */
> +
> +static int
> +remote_hostio_fstat (struct target_ops *self,
> +		     int fd, struct stat *st,
> +		     int *remote_errno)
> +{
> +  struct remote_state *rs = get_remote_state ();
> +  char *p = rs->buf;
> +  int left = get_remote_packet_size ();
> +  int attachment_len, ret;
> +  char *attachment;
> +  struct fio_stat fst;
> +  int read_len;
> +
> +  if (packet_support (PACKET_vFile_fstat) != PACKET_ENABLE)
> +    {
> +      memset (st, 0, sizeof (struct stat));
> +      st->st_size = INT_MAX;

A future reader may wonder why this isn't ENOSYS instead.  I think
a comment here would help.

> +      return 0;
> +    }

Thanks,
Pedro Alves
  
Gary Benson March 11, 2015, 10:23 a.m. UTC | #3
Pedro Alves wrote:
> On 03/10/2015 03:51 PM, Gary Benson wrote:
> > +/* Unpack an fio_uint_t.  */
> > +
> > +static unsigned int
> > +remote_fileio_to_host_uint (fio_uint_t fnum)
> > +{
> > +  gdb_byte *buf, *lim;
> > +  unsigned int num = 0;
> > +
> > +  for (buf = (gdb_byte *) fnum, lim = buf + 4; buf < lim; buf++)
> > +    {
> > +      num <<= 8;
> > +      num |= *buf;
> > +    }
> 
> How about we use
> 
>   extract_unsigned_integer ((gdb_byte *) fnum, 4, BFD_ENDIAN_BIG)
> 
> instead?

Ok.

> > +   into ST.  Return 0 on success, or -1 if an error occurs (and
> > +   set *REMOTE_ERRNO).  */
> > +
> > +static int
> > +remote_hostio_fstat (struct target_ops *self,
> > +		     int fd, struct stat *st,
> > +		     int *remote_errno)
> > +{
> > +  struct remote_state *rs = get_remote_state ();
> > +  char *p = rs->buf;
> > +  int left = get_remote_packet_size ();
> > +  int attachment_len, ret;
> > +  char *attachment;
> > +  struct fio_stat fst;
> > +  int read_len;
> > +
> > +  if (packet_support (PACKET_vFile_fstat) != PACKET_ENABLE)
> > +    {
> > +      memset (st, 0, sizeof (struct stat));
> > +      st->st_size = INT_MAX;
> 
> A future reader may wonder why this isn't ENOSYS instead.  I think
> a comment here would help.

How about this:

      /* Strictly we should return -1, ENOSYS here, but when
	 "set sysroot remote:" was implemented in August 2008
	 BFD's need for a stat function was sidestepped with
	 this hack.  This was not remedied until March 2015
	 so we retain the previous behavior to avoid breaking
	 compatibility.

	 Note that the memset is a March 2015 addition; older
	 GDBs set st_size *and nothing else* so the structure
	 would have garbage in all other fields.  This might
	 break something but retaining the previous behavior
	 here would be just too wrong.  */

Are you ok for me to commit this patch, reordered before the
gdbserver changes, with extract_unsigned_integer used in
remote_fileio_to_host_{uint,ulong}, and that comment added?
(I will regenerate patch 2 with updated docs for Eli to
approve).

Thanks,
Gary
  
Pedro Alves March 11, 2015, 11:22 a.m. UTC | #4
On 03/11/2015 10:23 AM, Gary Benson wrote:
> Pedro Alves wrote:
>>> +  if (packet_support (PACKET_vFile_fstat) != PACKET_ENABLE)
>>> +    {
>>> +      memset (st, 0, sizeof (struct stat));
>>> +      st->st_size = INT_MAX;
>>
>> A future reader may wonder why this isn't ENOSYS instead.  I think
>> a comment here would help.
> 
> How about this:
> 
>       /* Strictly we should return -1, ENOSYS here, but when
> 	 "set sysroot remote:" was implemented in August 2008
> 	 BFD's need for a stat function was sidestepped with
> 	 this hack.  This was not remedied until March 2015
> 	 so we retain the previous behavior to avoid breaking
> 	 compatibility.
> 
> 	 Note that the memset is a March 2015 addition; older
> 	 GDBs set st_size *and nothing else* so the structure
> 	 would have garbage in all other fields.  This might
> 	 break something but retaining the previous behavior
> 	 here would be just too wrong.  */

Thanks.

It also occurred to me something else on the gdbserver patch.
I'll send a follow up.

> Are you ok for me to commit this patch, reordered before the
> gdbserver changes, with extract_unsigned_integer used in
> remote_fileio_to_host_{uint,ulong}, and that comment added?

It be easier for me to just see the patch before answering, but
I think I am, though I'd like to take another look at the docs
patch with everything combined, to cross check whether more
bits would be missing.

I think it'd be good to have a "RSP packets: how to add / best practices
how to document" wiki page/guide, serving as both guidance for
submitters and for cross checking for reviewers, mentioning
things like remembering to document the "set remote foo commands",
qSupported entries, NEWS, etc.

> (I will regenerate patch 2 with updated docs for Eli to
> approve).

Thanks,
Pedro Alves
  

Patch

diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo
index 8d4af3c..552da31 100644
--- a/gdb/doc/gdb.texinfo
+++ b/gdb/doc/gdb.texinfo
@@ -19748,6 +19748,10 @@  are:
 @tab @code{vFile:readlink}
 @tab Host I/O
 
+@item @code{hostio-fstat-packet}
+@tab @code{vFile:fstat}
+@tab Host I/O
+
 @item @code{noack-packet}
 @tab @code{QStartNoAckMode}
 @tab Packet acknowledgment
diff --git a/gdb/remote-fileio.c b/gdb/remote-fileio.c
index 0ce0714..aaf839d 100644
--- a/gdb/remote-fileio.c
+++ b/gdb/remote-fileio.c
@@ -1321,6 +1321,86 @@  remote_fileio_request (char *buf, int ctrlc_pending_p)
 
   remote_fileio_sig_exit ();
 }
+
+
+/* Unpack an fio_uint_t.  */
+
+static unsigned int
+remote_fileio_to_host_uint (fio_uint_t fnum)
+{
+  gdb_byte *buf, *lim;
+  unsigned int num = 0;
+
+  for (buf = (gdb_byte *) fnum, lim = buf + 4; buf < lim; buf++)
+    {
+      num <<= 8;
+      num |= *buf;
+    }
+
+  return num;
+}
+
+/* Unpack an fio_ulong_t.  */
+
+static ULONGEST
+remote_fileio_to_host_ulong (fio_ulong_t fnum)
+{
+  gdb_byte *buf, *lim;
+  ULONGEST num = 0;
+
+  for (buf = (gdb_byte *) fnum, lim = buf + 8; buf < lim; buf++)
+    {
+      num <<= 8;
+      num |= *buf;
+    }
+
+  return num;
+}
+
+/* Unpack an fio_mode_t.  */
+
+static mode_t
+remote_fileio_to_host_mode (fio_mode_t fnum)
+{
+  return remote_fileio_mode_to_host (remote_fileio_to_host_uint (fnum),
+				     0);
+}
+
+/* Unpack an fio_time_t.  */
+
+static time_t
+remote_fileio_to_host_time (fio_time_t fnum)
+{
+  return remote_fileio_to_host_uint (fnum);
+}
+
+
+/* See remote-fileio.h.  */
+
+void
+remote_fileio_to_host_stat (struct fio_stat *fst, struct stat *st)
+{
+  memset (st, 0, sizeof (struct stat));
+
+  st->st_dev = remote_fileio_to_host_uint (fst->fst_dev);
+  st->st_ino = remote_fileio_to_host_uint (fst->fst_ino);
+  st->st_mode = remote_fileio_to_host_mode (fst->fst_mode);
+  st->st_nlink = remote_fileio_to_host_uint (fst->fst_nlink);
+  st->st_uid = remote_fileio_to_host_uint (fst->fst_uid);
+  st->st_gid = remote_fileio_to_host_uint (fst->fst_gid);
+  st->st_rdev = remote_fileio_to_host_uint (fst->fst_rdev);
+  st->st_size = remote_fileio_to_host_ulong (fst->fst_size);
+#ifdef HAVE_STRUCT_STAT_ST_BLKSIZE
+  st->st_blksize = remote_fileio_to_host_ulong (fst->fst_blksize);
+#endif
+#if HAVE_STRUCT_STAT_ST_BLOCKS
+  st->st_blocks = remote_fileio_to_host_ulong (fst->fst_blocks);
+#endif
+  st->st_atime = remote_fileio_to_host_time (fst->fst_atime);
+  st->st_mtime = remote_fileio_to_host_time (fst->fst_mtime);
+  st->st_ctime = remote_fileio_to_host_time (fst->fst_ctime);
+}
+
 
 static void
 set_system_call_allowed (char *args, int from_tty)
diff --git a/gdb/remote-fileio.h b/gdb/remote-fileio.h
index 8b32868..d30ae6a 100644
--- a/gdb/remote-fileio.h
+++ b/gdb/remote-fileio.h
@@ -38,4 +38,8 @@  extern void initialize_remote_fileio (
   struct cmd_list_element *remote_set_cmdlist,
   struct cmd_list_element *remote_show_cmdlist);
 
+/* Unpack a struct fio_stat.  */
+extern void remote_fileio_to_host_stat (struct fio_stat *fst,
+					struct stat *st);
+
 #endif
diff --git a/gdb/remote.c b/gdb/remote.c
index 495dfdc..52adbbb 100644
--- a/gdb/remote.c
+++ b/gdb/remote.c
@@ -1253,6 +1253,7 @@  enum {
   PACKET_vFile_close,
   PACKET_vFile_unlink,
   PACKET_vFile_readlink,
+  PACKET_vFile_fstat,
   PACKET_qXfer_auxv,
   PACKET_qXfer_features,
   PACKET_qXfer_libraries,
@@ -4042,7 +4043,9 @@  static const struct protocol_feature remote_protocol_features[] = {
   { "Qbtrace-conf:bts:size", PACKET_DISABLE, remote_supported_packet,
     PACKET_Qbtrace_conf_bts_size },
   { "swbreak", PACKET_DISABLE, remote_supported_packet, PACKET_swbreak_feature },
-  { "hwbreak", PACKET_DISABLE, remote_supported_packet, PACKET_hwbreak_feature }
+  { "hwbreak", PACKET_DISABLE, remote_supported_packet, PACKET_hwbreak_feature },
+  { "vFile:fstat", PACKET_DISABLE, remote_supported_packet,
+    PACKET_vFile_fstat },
 };
 
 static char *remote_support_xml;
@@ -10059,6 +10062,55 @@  remote_hostio_readlink (struct target_ops *self,
   return ret;
 }
 
+/* Read information about the open file FD on the remote target
+   into ST.  Return 0 on success, or -1 if an error occurs (and
+   set *REMOTE_ERRNO).  */
+
+static int
+remote_hostio_fstat (struct target_ops *self,
+		     int fd, struct stat *st,
+		     int *remote_errno)
+{
+  struct remote_state *rs = get_remote_state ();
+  char *p = rs->buf;
+  int left = get_remote_packet_size ();
+  int attachment_len, ret;
+  char *attachment;
+  struct fio_stat fst;
+  int read_len;
+
+  if (packet_support (PACKET_vFile_fstat) != PACKET_ENABLE)
+    {
+      memset (st, 0, sizeof (struct stat));
+      st->st_size = INT_MAX;
+      return 0;
+    }
+
+  remote_buffer_add_string (&p, &left, "vFile:fstat:");
+
+  remote_buffer_add_int (&p, &left, fd);
+
+  ret = remote_hostio_send_command (p - rs->buf, PACKET_vFile_fstat,
+				    remote_errno, &attachment,
+				    &attachment_len);
+  if (ret < 0)
+    return ret;
+
+  read_len = remote_unescape_input ((gdb_byte *) attachment, attachment_len,
+				    (gdb_byte *) &fst, sizeof (fst));
+
+  if (read_len != ret)
+    error (_("vFile:fstat returned %d, but %d bytes."), ret, read_len);
+
+  if (read_len != sizeof (fst))
+    error (_("vFile:fstat returned %d bytes, but expecting %d."),
+	   read_len, (int) sizeof (fst));
+
+  remote_fileio_to_host_stat (&fst, st);
+
+  return 0;
+}
+
 static int
 remote_fileio_errno_to_host (int errnum)
 {
@@ -10203,9 +10255,20 @@  remote_bfd_iovec_pread (struct bfd *abfd, void *stream, void *buf,
 static int
 remote_bfd_iovec_stat (struct bfd *abfd, void *stream, struct stat *sb)
 {
-  /* FIXME: We should probably implement remote_hostio_stat.  */
-  sb->st_size = INT_MAX;
-  return 0;
+  int fd = *(int *) stream;
+  int remote_errno;
+  int result;
+
+  result = remote_hostio_fstat (find_target_at (process_stratum),
+				fd, sb, &remote_errno);
+
+  if (result == -1)
+    {
+      errno = remote_fileio_errno_to_host (remote_errno);
+      bfd_set_error (bfd_error_system_call);
+    }
+
+  return result;
 }
 
 int
@@ -12342,6 +12405,9 @@  Show the maximum size of the address (in bits) in a memory packet."), NULL,
   add_packet_config_cmd (&remote_protocol_packets[PACKET_vFile_readlink],
 			 "vFile:readlink", "hostio-readlink", 0);
 
+  add_packet_config_cmd (&remote_protocol_packets[PACKET_vFile_fstat],
+			 "vFile:fstat", "hostio-fstat", 0);
+
   add_packet_config_cmd (&remote_protocol_packets[PACKET_vAttach],
 			 "vAttach", "attach", 0);
 
diff --git a/gdb/symfile.c b/gdb/symfile.c
index c2a71ec..ba099d3 100644
--- a/gdb/symfile.c
+++ b/gdb/symfile.c
@@ -1377,11 +1377,12 @@  separate_debug_file_exists (const char *name, unsigned long crc,
 
      Some operating systems, e.g. Windows, do not provide a meaningful
      st_ino; they always set it to zero.  (Windows does provide a
-     meaningful st_dev.)  Do not indicate a duplicate library in that
-     case.  While there is no guarantee that a system that provides
-     meaningful inode numbers will never set st_ino to zero, this is
-     merely an optimization, so we do not need to worry about false
-     negatives.  */
+     meaningful st_dev.)  Files accessed from gdbservers that do not
+     support the vFile:fstat packet will also have st_ino set to zero.
+     Do not indicate a duplicate library in either case.  While there
+     is no guarantee that a system that provides meaningful inode
+     numbers will never set st_ino to zero, this is merely an
+     optimization, so we do not need to worry about false negatives.  */
 
   if (bfd_stat (abfd, &abfd_stat) == 0
       && abfd_stat.st_ino != 0
@@ -1409,9 +1410,9 @@  separate_debug_file_exists (const char *name, unsigned long crc,
     {
       unsigned long parent_crc;
 
-      /* If one (or both) the files are accessed for example the via "remote:"
-	 gdbserver way it does not support the bfd_stat operation.  Verify
-	 whether those two files are not the same manually.  */
+      /* If the files could not be verified as different with
+	 bfd_stat then we need to calculate the parent's CRC
+	 to verify whether the files are different or not.  */
 
       if (!verified_as_different)
 	{