Mirror of the gdb-patches mailing list
 help / color / mirror / Atom feed
From: Abhay Kandpal <abhay@linux.ibm.com>
To: gdb-patches@sourceware.org
Cc: aburgess@redhat.com, Ulrich.Weigand@de.ibm.com, eliz@gnu.org,
	cel@linux.ibm.com, abhay.k@ibm.com,
	Abhay Kandpal <abhay@linux.ibm.com>
Subject: [PATCH v4 1/2] gdbserver: widen the stat fields returned by the vFile packets
Date: Thu, 29 Oct 2026 04:21:23 -0500	[thread overview]
Message-ID: <20261029092124.233055-2-abhay@linux.ibm.com> (raw)
In-Reply-To: <20261029092124.233055-1-abhay@linux.ibm.com>

The struct sent by the vFile:fstat, vFile:stat and vFile:lstat packets
declares st_dev, st_ino, st_nlink, st_rdev and the three timestamps as
4-byte fields, while the corresponding struct stat members are 8 bytes
on a 64-bit host.  The values are silently truncated.

This is not visible on a filesystem whose inode numbers stay below
2^32, but it is on a large one.  On an 86 TB xfs volume,
gdb.server/fileio-packets.exp fails because the inode reported by
vFile:lstat does not match the one reported locally:

  remote = {..., 'st_ino': 2161233200, ...}
  local  = {..., 'st_ino': 122420317488, ...}

The field widths cannot simply be changed, as that would alter the wire
layout and break communication between different versions of GDB and
gdbserver.  Add a new 'stat64' qSupported feature instead.  When both
sides report it, the vFile stat packets return struct fio_stat_wide, in
which the seven too-narrow fields are 8 bytes; otherwise the existing
struct fio_stat is used, exactly as before.

gdbserver packs the host struct stat directly into whichever form was
negotiated, and GDB selects the unpacker by the length of the reply.
The feature flag is reset on each new connection, like the other
qSupported flags.

A value which does not fit in a narrow field now produces a warning
rather than being truncated silently.  The check is in
host_to_fileio_uint and host_to_fileio_time, which the F-packet stat
and fstat calls also use, so GDB now warns there too.

The F-packet file-i/o protocol uses the same struct, but writes it
into inferior memory rather than sending it as packet data, so it
cannot use qSupported negotiation.  It is handled separately in the
next patch.

While here, drop a duplicate include of gdbsupport/fileio.h from
gdbserver/hostio.cc, and add a missing blank line after a comment in
gdbserver/hostio.h.

Tested on powerpc64le-linux; gdb.server/fileio-packets.exp now passes on
a filesystem with inode numbers above 2^32 and continues to pass on one
without, with no regressions in the full testsuite.

Bug: https://sourceware.org/bugzilla/show_bug.cgi?id=34567
Reviewed-By: Eli Zaretskii <eliz@gnu.org>
---
 gdb/NEWS                                   | 14 ++++
 gdb/doc/gdb.texinfo                        | 50 ++++++++++++++
 gdb/remote-fileio.c                        | 24 +++++++
 gdb/remote-fileio.h                        |  5 ++
 gdb/remote.c                               | 35 +++++++---
 gdb/testsuite/gdb.server/fileio-packets.py | 59 ++++++++++-------
 gdbserver/hostio.cc                        | 77 +++++++++++-----------
 gdbserver/hostio.h                         |  1 +
 gdbserver/server.cc                        |  5 +-
 gdbserver/server.h                         |  5 ++
 gdbsupport/fileio.cc                       | 32 +++++++++
 gdbsupport/fileio.h                        | 48 ++++++++++++--
 12 files changed, 282 insertions(+), 73 deletions(-)

diff --git a/gdb/NEWS b/gdb/NEWS
index 7303ec0e460..47425535661 100644
--- a/gdb/NEWS
+++ b/gdb/NEWS
@@ -83,6 +83,20 @@ info locals
   The new "-shadowed on|off" option overrides the "set print shadowed"
   setting for a single invocation of the command.
 
+* Changed remote packets
+
+stat64 in qSupported
+
+  The new stat64 feature within the qSupported packet allows GDB and
+  the stub to agree on a wider form of the stat structure returned by
+  the vFile:fstat, vFile:stat and vFile:lstat packets, in which st_dev,
+  st_ino, st_nlink, st_rdev and the three timestamps are 8 bytes rather
+  than 4.  The wider form is used only when both sides report the
+  feature; otherwise the existing format is used, and values which do
+  not fit are truncated with a warning.  Note that the narrow form
+  reads timestamps as unsigned, so it overflows in 2106 rather than
+  2038.
+
 *** Changes in GDB 18
 
 * Support for the Common Trace Format (CTF) has been removed.  GDB now
diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo
index 66152d2582e..4d606377987 100644
--- a/gdb/doc/gdb.texinfo
+++ b/gdb/doc/gdb.texinfo
@@ -46232,6 +46232,11 @@ inspected, if @samp{qIsAddressTagged} (@pxref{qIsAddressTagged}) packet
 is not supported by the stub.  Access to the @file{/proc/@var{pid}/smaps}
 file is done via @samp{vFile} requests.
 
+@item stat64
+The remote stub supports the wider form of the stat structure returned
+by the @samp{vFile:fstat}, @samp{vFile:stat} and @samp{vFile:lstat}
+packets (@pxref{struct stat64}).
+
 @item error-message
 The remote stub supports replying with an error in a
 @samp{E.@var{errtext}} (@xref{textual error reply}) format from the
@@ -47478,6 +47483,9 @@ On success the information is returned as a binary attachment
 and the return value is the size of this attachment in bytes.
 If an error occurs the return value is -1.  The format of the
 returned binary attachment is as described in @ref{struct stat}.
+If both @value{GDBN} and the stub report the @samp{stat64} feature in
+the @samp{qSupported} exchange, the wider format is used instead
+(@pxref{struct stat64}).
 
 @item vFile:stat: @var{filename}
 Get information about the file @var{filename} on the target as if from
@@ -47485,6 +47493,9 @@ a @samp{stat} call.  On success the information is returned as a binary
 attachment and the return value is the size of this attachment in
 bytes.  If an error occurs the return value is -1.  The format of the
 returned binary attachment is as described in @ref{struct stat}.
+If both @value{GDBN} and the stub report the @samp{stat64} feature in
+the @samp{qSupported} exchange, the wider format is used instead
+(@pxref{struct stat64}).
 
 If @var{filename} is a symbolic link, then the information returned is
 about the file the link refers to, this is inline with the @samp{stat}
@@ -47496,6 +47507,9 @@ an @samp{lstat} call.  On success the information is returned as a
 binary attachment and the return value is the size of this attachment
 in bytes.  If an error occurs the return value is -1.  The format of
 the returned binary attachment is as described in @ref{struct stat}.
+If both @value{GDBN} and the stub report the @samp{stat64} feature in
+the @samp{qSupported} exchange, the wider format is used instead
+(@pxref{struct stat64}).
 
 This packet is identical to @samp{vFile:stat}, except if
 @var{filename} is a symbolic link, then this packet returns
@@ -48690,6 +48704,7 @@ protocol.
 * Pointer Values::
 * Memory Transfer::
 * struct stat::
+* struct stat64::
 * struct timeval::
 @end menu
 
@@ -48816,6 +48831,41 @@ Note that due to size differences between the host, target, and protocol
 representations of @code{struct stat} members, these members could eventually
 get truncated on the target.
 
+@node struct stat64
+@unnumberedsubsubsec struct stat64
+@cindex struct stat64, in file-i/o protocol
+
+When the @samp{stat64} feature has been negotiated, the buffer returned
+by the @samp{vFile:fstat}, @samp{vFile:stat} and @samp{vFile:lstat}
+packets uses the following representation instead:
+
+@smallexample
+struct stat64 @{
+    uint64_t      st_dev;      /* device */
+    uint64_t      st_ino;      /* inode */
+    mode_t        st_mode;     /* protection */
+    uint64_t      st_nlink;    /* number of hard links */
+    unsigned int  st_uid;      /* user ID of owner */
+    unsigned int  st_gid;      /* group ID of owner */
+    uint64_t      st_rdev;     /* device type (if inode device) */
+    uint64_t      st_size;     /* total size, in bytes */
+    uint64_t      st_blksize;  /* blocksize for filesystem I/O */
+    uint64_t      st_blocks;   /* number of blocks allocated */
+    uint64_t      st_atime;    /* time of last access */
+    uint64_t      st_mtime;    /* time of last modification */
+    uint64_t      st_ctime;    /* time of last change */
+@};
+@end smallexample
+
+This structure is of size 92 bytes.  The fields have the same meanings
+as in the narrow form (@pxref{struct stat}), but @code{st_dev},
+@code{st_ino}, @code{st_nlink}, @code{st_rdev} and the three timestamps
+are wide enough to hold the values found on a 64-bit host without
+truncation.
+
+This representation is only used by the @samp{vFile} packets; the
+File-I/O protocol always uses the narrow form (@pxref{struct stat}).
+
 @node struct timeval
 @unnumberedsubsubsec struct timeval
 @cindex struct timeval, in file-i/o protocol
diff --git a/gdb/remote-fileio.c b/gdb/remote-fileio.c
index a151161371d..a65db27d04e 100644
--- a/gdb/remote-fileio.c
+++ b/gdb/remote-fileio.c
@@ -1221,6 +1221,30 @@ remote_fileio_to_host_stat (struct fio_stat *fst, struct stat *st)
   st->st_ctime = remote_fileio_to_host_time (fst->fst_ctime);
 }
 \f
+/* See remote-fileio.h.  */
+
+void
+remote_fileio_wide_to_host_stat (struct fio_stat_wide *fst, struct stat *st)
+{
+  memset (st, 0, sizeof (struct stat));
+  st->st_dev = remote_fileio_to_host_ulong (fst->fst_dev);
+  st->st_ino = remote_fileio_to_host_ulong (fst->fst_ino);
+  st->st_mode = remote_fileio_to_host_mode (fst->fst_mode);
+  st->st_nlink = remote_fileio_to_host_ulong (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_ulong (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_ulong (fst->fst_atime);
+  st->st_mtime = remote_fileio_to_host_ulong (fst->fst_mtime);
+  st->st_ctime = remote_fileio_to_host_ulong (fst->fst_ctime);
+}
 
 static void
 set_system_call_allowed (const char *args, int from_tty)
diff --git a/gdb/remote-fileio.h b/gdb/remote-fileio.h
index d01b3df92ca..105a13851c4 100644
--- a/gdb/remote-fileio.h
+++ b/gdb/remote-fileio.h
@@ -44,4 +44,9 @@ extern void initialize_remote_fileio (
 extern void remote_fileio_to_host_stat (struct fio_stat *fst,
 					struct stat *st);
 
+/* Unpack a struct fio_stat_wide.  */
+
+extern void remote_fileio_wide_to_host_stat (struct fio_stat_wide *fst,
+					     struct stat *st);
+
 #endif /* GDB_REMOTE_FILEIO_H */
diff --git a/gdb/remote.c b/gdb/remote.c
index 6e3a2089b9e..39d975684eb 100644
--- a/gdb/remote.c
+++ b/gdb/remote.c
@@ -389,6 +389,9 @@ enum {
      packets and the tag violation stop replies.  */
   PACKET_memory_tagging_feature,
 
+  /* Support for the wide form of struct stat in vFile stat replies.  */
+  PACKET_stat64_feature,
+
   /* Support for the qIsAddressTagged packet.  */
   PACKET_qIsAddressTagged,
 
@@ -6188,6 +6191,8 @@ static const struct protocol_feature remote_protocol_features[] = {
   { "no-resumed", PACKET_DISABLE, remote_supported_packet, PACKET_no_resumed },
   { "memory-tagging", PACKET_DISABLE, remote_supported_packet,
     PACKET_memory_tagging_feature },
+  { "stat64", PACKET_DISABLE, remote_supported_packet,
+    PACKET_stat64_feature },
   { "error-message", PACKET_ENABLE, remote_supported_packet,
     PACKET_accept_error_message },
   { "binary-upload", PACKET_DISABLE, remote_supported_packet, PACKET_x },
@@ -6298,6 +6303,10 @@ remote_target::remote_query_supported ()
 	  != AUTO_BOOLEAN_FALSE)
 	remote_query_supported_append (&q, "QThreadOptions+");
 
+      if (m_features.packet_set_cmd_state (PACKET_stat64_feature)
+	  != AUTO_BOOLEAN_FALSE)
+	remote_query_supported_append (&q, "stat64+");
+
       if (m_features.packet_set_cmd_state (PACKET_no_resumed)
 	  != AUTO_BOOLEAN_FALSE)
 	remote_query_supported_append (&q, "no-resumed+");
@@ -13656,7 +13665,11 @@ remote_target::fileio_readlink (struct inferior *inf, const char *filename,
    remote syscall reply.  EXPECTED_LEN is the length returned from the
    fstat or stat call, this the length of the returned data (in ATTACHMENT)
    once it has been decoded.  The fstat/stat result (from the ATTACHMENT
-   data) is to be placed in ST.  */
+   data) is to be placed in ST.
+
+   The reply holds either a struct fio_stat or, if the stat64 feature was
+   negotiated, the wider struct fio_stat_wide; the two are distinguished
+   by their length.  */
 
 static int
 fileio_process_fstat_and_lstat_reply (const char *attachment,
@@ -13664,21 +13677,24 @@ fileio_process_fstat_and_lstat_reply (const char *attachment,
 				      int expected_len,
 				      struct stat *st)
 {
-  struct fio_stat fst;
+  gdb_byte buf[sizeof (struct fio_stat_wide)];
 
   int read_len
     = remote_unescape_input ((gdb_byte *) attachment, attachment_len,
-			     (gdb_byte *) &fst, sizeof (fst));
+			     buf, sizeof (buf));
 
   if (read_len != expected_len)
     error (_("vFile:fstat returned %d, but %d bytes."),
 	   expected_len, 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);
+  if (read_len == sizeof (struct fio_stat_wide))
+    remote_fileio_wide_to_host_stat ((struct fio_stat_wide *) buf, st);
+  else if (read_len == sizeof (struct fio_stat))
+    remote_fileio_to_host_stat ((struct fio_stat *) buf, st);
+  else
+    error (_("vFile:fstat returned %d bytes, but expecting %d or %d."),
+	   read_len, (int) sizeof (struct fio_stat),
+	   (int) sizeof (struct fio_stat_wide));
 
   return 0;
 }
@@ -17032,6 +17048,9 @@ Show the maximum size of the address (in bits) in a memory packet."), NULL,
   add_packet_config_cmd (PACKET_memory_tagging_feature,
 			 "memory-tagging-feature", "memory-tagging-feature", 0);
 
+  add_packet_config_cmd (PACKET_stat64_feature,
+			 "stat64-feature", "stat64-feature", 0);
+
   add_packet_config_cmd (PACKET_qIsAddressTagged,
 			 "qIsAddressTagged", "memory-tagging-address-check", 0);
 
diff --git a/gdb/testsuite/gdb.server/fileio-packets.py b/gdb/testsuite/gdb.server/fileio-packets.py
index 54ae56fa68a..7e3a68bcdd9 100644
--- a/gdb/testsuite/gdb.server/fileio-packets.py
+++ b/gdb/testsuite/gdb.server/fileio-packets.py
@@ -57,33 +57,48 @@ def decode_stat_reply(buf, byteorder="big"):
 
     buf = unescape_remote_data(buf)
 
-    if (
-        buf[0] != ord("F")
-        or buf[1] != ord("4")
-        or buf[2] != ord("0")
-        or buf[3] != ord(";")
-        or len(buf) != 68
-    ):
+    if buf[0:4] == b"F40;" and len(buf) == 68:
+        wide = False
+    elif buf[0:4] == b"F5c;" and len(buf) == 96:
+        wide = True
+    else:
         print(f"decode_stat_reply failed: {buf}\t(length = {len(buf)})")
         return None
 
-    # Discard the 'F40;' prefix.  The rest is the 64 bytes of data to
-    # be decoded.
+    # Discard the 'FNN;' prefix.
     buf = buf[4:]
 
-    st_dev = int.from_bytes(buf[0:4], byteorder=byteorder)
-    st_ino = int.from_bytes(buf[4:8], byteorder=byteorder)
-    st_mode = int.from_bytes(buf[8:12], byteorder=byteorder)
-    st_nlink = int.from_bytes(buf[12:16], byteorder=byteorder)
-    st_uid = int.from_bytes(buf[16:20], byteorder=byteorder)
-    st_gid = int.from_bytes(buf[20:24], byteorder=byteorder)
-    st_rdev = int.from_bytes(buf[24:28], byteorder=byteorder)
-    st_size = int.from_bytes(buf[28:36], byteorder=byteorder)
-    st_blksize = int.from_bytes(buf[36:44], byteorder=byteorder)
-    st_blocks = int.from_bytes(buf[44:52], byteorder=byteorder)
-    st_atime = int.from_bytes(buf[52:56], byteorder=byteorder)
-    st_mtime = int.from_bytes(buf[56:60], byteorder=byteorder)
-    st_ctime = int.from_bytes(buf[60:64], byteorder=byteorder)
+    def field(off, size):
+        return int.from_bytes(buf[off : off + size], byteorder=byteorder)
+
+    if wide:
+        st_dev = field(0, 8)
+        st_ino = field(8, 8)
+        st_mode = field(16, 4)
+        st_nlink = field(20, 8)
+        st_uid = field(28, 4)
+        st_gid = field(32, 4)
+        st_rdev = field(36, 8)
+        st_size = field(44, 8)
+        st_blksize = field(52, 8)
+        st_blocks = field(60, 8)
+        st_atime = field(68, 8)
+        st_mtime = field(76, 8)
+        st_ctime = field(84, 8)
+    else:
+        st_dev = field(0, 4)
+        st_ino = field(4, 4)
+        st_mode = field(8, 4)
+        st_nlink = field(12, 4)
+        st_uid = field(16, 4)
+        st_gid = field(20, 4)
+        st_rdev = field(24, 4)
+        st_size = field(28, 8)
+        st_blksize = field(36, 8)
+        st_blocks = field(44, 8)
+        st_atime = field(52, 4)
+        st_mtime = field(56, 4)
+        st_ctime = field(60, 4)
 
     return {
         "st_dev": st_dev,
diff --git a/gdbserver/hostio.cc b/gdbserver/hostio.cc
index b9ca27c2ff4..9966ecb0842 100644
--- a/gdbserver/hostio.cc
+++ b/gdbserver/hostio.cc
@@ -26,7 +26,6 @@
 #include <unistd.h>
 #include <sys/types.h>
 #include <sys/stat.h>
-#include "gdbsupport/fileio.h"
 
 struct fd_list
 {
@@ -459,13 +458,47 @@ handle_pwrite (char *own_buf, int packet_len)
   free (data);
 }
 
+/* Reply to a vFile stat request with the result in ST: in the wide
+   form if GDB has asked for it, otherwise in the narrow form.  */
+
+static void
+hostio_send_stat_reply (char *own_buf, struct stat *st,
+			int *new_packet_len)
+{
+  client_state &cs = get_client_state ();
+  struct fio_stat narrow;
+  struct fio_stat_wide wide;
+  char *data;
+  int len;
+
+  if (cs.stat64_feature)
+    {
+      host_to_fileio_stat_wide (st, &wide);
+      data = (char *) &wide;
+      len = sizeof (wide);
+    }
+  else
+    {
+      host_to_fileio_stat (st, &narrow);
+      data = (char *) &narrow;
+      len = sizeof (narrow);
+    }
+
+  int bytes_sent = hostio_reply_with_data (own_buf, data, len,
+					   new_packet_len);
+
+  /* If the response does not fit into a single packet, do not attempt
+     to return a partial response, but simply fail.  */
+  if (bytes_sent < len)
+    write_enn (own_buf);
+}
+
 static void
 handle_fstat (char *own_buf, int *new_packet_len)
 {
-  int fd, bytes_sent;
+  int fd;
   char *p;
   struct stat st;
-  struct fio_stat fst;
 
   p = own_buf + strlen ("vFile:fstat:");
 
@@ -483,25 +516,14 @@ handle_fstat (char *own_buf, int *new_packet_len)
       return;
     }
 
-  host_to_fileio_stat (&st, &fst);
-
-  bytes_sent = hostio_reply_with_data (own_buf,
-				       (char *) &fst, sizeof (fst),
-				       new_packet_len);
-
-  /* If the response does not fit into a single packet, do not attempt
-     to return a partial response, but simply fail.  */
-  if (bytes_sent < sizeof (fst))
-    write_enn (own_buf);
+  hostio_send_stat_reply (own_buf, &st, new_packet_len);
 }
 
 static void
 handle_stat (char *own_buf, int *new_packet_len)
 {
-  int bytes_sent;
   char *p;
   struct stat st;
-  struct fio_stat fst;
   char filename[HOSTIO_PATH_MAX];
 
   p = own_buf + strlen ("vFile:stat:");
@@ -519,25 +541,15 @@ handle_stat (char *own_buf, int *new_packet_len)
       return;
     }
 
-  host_to_fileio_stat (&st, &fst);
-
-  bytes_sent = hostio_reply_with_data (own_buf,
-				       (char *) &fst, sizeof (fst),
-				       new_packet_len);
-
-  /* If the response does not fit into a single packet, do not attempt
-     to return a partial response, but simply fail.  */
-  if (bytes_sent < sizeof (fst))
-    write_enn (own_buf);
+  hostio_send_stat_reply (own_buf, &st, new_packet_len);
 }
 
 static void
 handle_lstat (char *own_buf, int *new_packet_len)
 {
-  int ret, bytes_sent;
+  int ret;
   char *p;
   struct stat st;
-  struct fio_stat fst;
   char filename[HOSTIO_PATH_MAX];
 
   p = own_buf + strlen ("vFile:lstat:");
@@ -560,16 +572,7 @@ handle_lstat (char *own_buf, int *new_packet_len)
       return;
     }
 
-  host_to_fileio_stat (&st, &fst);
-
-  bytes_sent = hostio_reply_with_data (own_buf,
-				       (char *) &fst, sizeof (fst),
-				       new_packet_len);
-
-  /* If the response does not fit into a single packet, do not attempt
-     to return a partial response, but simply fail.  */
-  if (bytes_sent < sizeof (fst))
-    write_enn (own_buf);
+  hostio_send_stat_reply (own_buf, &st, new_packet_len);
 }
 
 static void
diff --git a/gdbserver/hostio.h b/gdbserver/hostio.h
index 7a6fb94cd2c..4061292f094 100644
--- a/gdbserver/hostio.h
+++ b/gdbserver/hostio.h
@@ -20,6 +20,7 @@
 #define GDBSERVER_HOSTIO_H
 
 /* Per-connection setup.  */
+
 extern void hostio_handle_new_gdb_connection (void);
 
 extern int handle_vFile (char *, int, int *);
diff --git a/gdbserver/server.cc b/gdbserver/server.cc
index 74774fcde7c..d16b9552003 100644
--- a/gdbserver/server.cc
+++ b/gdbserver/server.cc
@@ -2744,6 +2744,8 @@ handle_query (char *own_buf, int packet_len, int *new_packet_len_p)
 		cs.single_inferior_argument = true;
 	      else if (feature == "multi-wp-addr+")
 		cs.multiple_wp_addr_feature = true;
+	      else if (feature == "stat64+")
+		cs.stat64_feature = true;
 	      else
 		{
 		  /* Move the unknown features all together.  */
@@ -2760,7 +2762,7 @@ handle_query (char *own_buf, int packet_len, int *new_packet_len_p)
 	       "PacketSize=%x;QPassSignals+;QProgramSignals+;"
 	       "QStartupWithShell+;QEnvironmentHexEncoded+;"
 	       "QEnvironmentReset+;QEnvironmentUnset+;"
-	       "QSetWorkingDir+;binary-upload+",
+	       "QSetWorkingDir+;binary-upload+;stat64+",
 	       PBUFSIZ - 1);
 
       if (target_supports_catch_syscall ())
@@ -4630,6 +4632,7 @@ captured_main (int argc, char *argv[])
       cs.memory_tagging_feature = false;
       cs.error_message_supported = false;
       cs.multiple_wp_addr_feature = false;
+      cs.stat64_feature = false;
 
       remote_open (port);
 
diff --git a/gdbserver/server.h b/gdbserver/server.h
index 1a9e6ef62f8..f86a8701301 100644
--- a/gdbserver/server.h
+++ b/gdbserver/server.h
@@ -179,6 +179,11 @@ struct client_state
   /* If true, memory tagging features are supported.  */
   bool memory_tagging_feature = false;
 
+  /* True if GDB supports the wide form of struct stat in the vFile
+     fstat, stat and lstat replies.  When false, gdbserver sends the
+     narrow struct fio_stat.  */
+  bool stat64_feature = false;
+
   /* If true then E.errtext style errors are supported everywhere,
      including for the qRcmd and m packet.  When false E.errtext errors
      are not supported with qRcmd and m packets, but are still supported
diff --git a/gdbsupport/fileio.cc b/gdbsupport/fileio.cc
index 6d2ffb14544..0c45c32c8e5 100644
--- a/gdbsupport/fileio.cc
+++ b/gdbsupport/fileio.cc
@@ -305,3 +305,35 @@ host_to_fileio_stat (struct stat *st, struct fio_stat *fst)
   host_to_fileio_time (st->st_mtime, fst->fst_mtime);
   host_to_fileio_time (st->st_ctime, fst->fst_ctime);
 }
+
+/* See fileio.h.  */
+
+void
+host_to_fileio_stat_wide (struct stat *st, struct fio_stat_wide *fst)
+{
+  LONGEST blksize;
+
+  host_to_fileio_ulong ((LONGEST) st->st_dev, fst->fst_dev);
+  host_to_fileio_ulong ((LONGEST) st->st_ino, fst->fst_ino);
+  host_to_fileio_mode (st->st_mode, fst->fst_mode);
+  host_to_fileio_ulong ((LONGEST) st->st_nlink, fst->fst_nlink);
+  host_to_fileio_uint ((long) st->st_uid, fst->fst_uid);
+  host_to_fileio_uint ((long) st->st_gid, fst->fst_gid);
+  host_to_fileio_ulong ((LONGEST) st->st_rdev, fst->fst_rdev);
+  host_to_fileio_ulong ((LONGEST) st->st_size, fst->fst_size);
+#ifdef HAVE_STRUCT_STAT_ST_BLKSIZE
+  blksize = st->st_blksize;
+#else
+  blksize = 512;
+#endif
+  host_to_fileio_ulong (blksize, fst->fst_blksize);
+#if HAVE_STRUCT_STAT_ST_BLOCKS
+  host_to_fileio_ulong ((LONGEST) st->st_blocks, fst->fst_blocks);
+#else
+  host_to_fileio_ulong (((LONGEST) st->st_size + blksize - 1) / blksize,
+			fst->fst_blocks);
+#endif
+  host_to_fileio_ulong ((LONGEST) st->st_atime, fst->fst_atime);
+  host_to_fileio_ulong ((LONGEST) st->st_mtime, fst->fst_mtime);
+  host_to_fileio_ulong ((LONGEST) st->st_ctime, fst->fst_ctime);
+}
diff --git a/gdbsupport/fileio.h b/gdbsupport/fileio.h
index c2592cf8c15..44b9bdcafc6 100644
--- a/gdbsupport/fileio.h
+++ b/gdbsupport/fileio.h
@@ -120,9 +120,11 @@ using fio_time_t = char[FIO_TIME_LEN];
 using fio_long_t = char[FIO_LONG_LEN];
 using fio_ulong_t = char[FIO_ULONG_LEN];
 
-/* Struct stat as used in protocol.  For complete independence
-   of host/target systems, it's defined as an array with offsets
-   to the members. */
+/* Struct stat as used in the protocol.  This is the format used by the
+   F-packet file-i/o protocol, and by the vFile stat packets when the
+   stat64 feature has not been negotiated.  Several fields are too narrow
+   to hold the corresponding struct stat member on a 64-bit host; see
+   struct fio_stat_wide.  */
 
 struct fio_stat
 {
@@ -141,6 +143,29 @@ struct fio_stat
   fio_time_t  fst_ctime;
 };
 
+/* Struct stat as used in the wide form of the protocol.  The fields
+   which cannot hold the corresponding struct stat member on a 64-bit
+   host are widened to 8 bytes.  This layout is only used by the vFile
+   stat packets, and only when the stat64 feature has been negotiated
+   with the peer.  */
+
+struct fio_stat_wide
+{
+  fio_ulong_t fst_dev;
+  fio_ulong_t fst_ino;
+  fio_mode_t  fst_mode;
+  fio_ulong_t fst_nlink;
+  fio_uint_t  fst_uid;
+  fio_uint_t  fst_gid;
+  fio_ulong_t fst_rdev;
+  fio_ulong_t fst_size;
+  fio_ulong_t fst_blksize;
+  fio_ulong_t fst_blocks;
+  fio_ulong_t fst_atime;
+  fio_ulong_t fst_mtime;
+  fio_ulong_t fst_ctime;
+};
+
 struct fio_timeval
 {
   fio_time_t  ftv_sec;
@@ -179,19 +204,27 @@ host_to_bigendian (LONGEST num, char *buf, int bytes)
     buf[i] = (num >> (8 * (bytes - i - 1))) & 0xff;
 }
 
-/* Pack a host-format integer into an fio_uint_t.  */
+/* Pack a host-format integer into an fio_uint_t, warning if the value
+   does not fit.  */
 
 static inline void
 host_to_fileio_uint (long num, fio_uint_t fnum)
 {
+  if ((ULONGEST) num > 0xffffffff)
+    warning (_("file-i/o: value %s does not fit in 32 bits and will be "
+	       "truncated"), plongest (num));
   host_to_bigendian ((LONGEST) num, (char *) fnum, 4);
 }
 
-/* Pack a host-format time_t into an fio_time_t.  */
+/* Pack a host-format time_t into an fio_time_t, warning if the value
+   does not fit.  */
 
 static inline void
 host_to_fileio_time (time_t num, fio_time_t fnum)
 {
+  if ((ULONGEST) num > 0xffffffff)
+    warning (_("file-i/o: time value %s does not fit in 32 bits and "
+	       "will be truncated"), plongest (num));
   host_to_bigendian ((LONGEST) num, (char *) fnum, 4);
 }
 
@@ -199,4 +232,9 @@ host_to_fileio_time (time_t num, fio_time_t fnum)
 
 extern void host_to_fileio_stat (struct stat *st, struct fio_stat *fst);
 
+/* Pack a host-format struct stat into a struct fio_stat_wide.  */
+
+extern void host_to_fileio_stat_wide (struct stat *st,
+				      struct fio_stat_wide *fst);
+
 #endif /* GDBSUPPORT_FILEIO_H */
-- 
2.51.1


  reply	other threads:[~2026-10-29  9:22 UTC|newest]

Thread overview: 3+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-10-29  9:21 [PATCH v4 0/2] Widen the stat fields in the remote protocol Abhay Kandpal
2026-10-29  9:21 ` Abhay Kandpal [this message]
2026-10-29  9:21 ` [PATCH v4 2/2] gdb: add stat64 and fstat64 to the F-packet file-i/o protocol Abhay Kandpal

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20261029092124.233055-2-abhay@linux.ibm.com \
    --to=abhay@linux.ibm.com \
    --cc=Ulrich.Weigand@de.ibm.com \
    --cc=abhay.k@ibm.com \
    --cc=aburgess@redhat.com \
    --cc=cel@linux.ibm.com \
    --cc=eliz@gnu.org \
    --cc=gdb-patches@sourceware.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox