Mirror of the gdb-patches mailing list
 help / color / mirror / Atom feed
* [PATCH v3 0/2] Widen the stat fields in the remote protocol
@ 2026-10-14  9:21 Abhay Kandpal
  2026-10-14  9:21 ` [PATCH v3 1/2] gdbserver: widen the stat fields returned by the vFile packets Abhay Kandpal
  2026-10-14  9:21 ` [PATCH v3 2/2] gdb: add stat64 and fstat64 to the F-packet file-i/o protocol Abhay Kandpal
  0 siblings, 2 replies; 9+ messages in thread
From: Abhay Kandpal @ 2026-10-14  9:21 UTC (permalink / raw)
  To: gdb-patches; +Cc: aburgess, Ulrich.Weigand, eliz, cel, abhay.k, Abhay Kandpal

The struct fio_stat used by the remote protocol declares st_dev,
st_ino, st_nlink, st_rdev and the three timestamps as 4 bytes, so
those values are truncated on a 64-bit host.  On a large xfs
filesystem this makes gdb.server/fileio-packets.exp fail.  PR 34567.

The struct is used in two directions, and the two need different
fixes:

  1/2  vFile packets (GDB asking gdbserver): a new 'stat64'
       qSupported feature selects a wide struct.  This is v2,
       rebased, with only the commit message adjusted.

  2/2  F-packet file-i/o calls (the target asking GDB): new
       Fstat64 and Ffstat64 calls write the wide struct.  An older
       GDB replies ENOSYS, so a target can fall back to Fstat.

Changes in v3:
- Add 2/2, covering the F-packet direction as Andrew asked.
  Thanks to Ulrich for suggesting the new-syscall approach.
- 1/2 is unchanged apart from the commit message.

Abhay Kandpal (2):
  gdbserver: widen the stat fields returned by the vFile packets
  gdb: add stat64 and fstat64 to the F-packet file-i/o protocol

 gdb/NEWS                                   |  22 +++++
 gdb/doc/gdb.texinfo                        |  96 +++++++++++++++++++
 gdb/remote-fileio.c                        | 102 +++++++++++++++++---
 gdb/remote-fileio.h                        |   4 +
 gdb/remote.c                               |  36 +++++--
 gdb/testsuite/gdb.server/fileio-packets.py |  59 +++++++-----
 gdbserver/hostio.cc                        | 106 +++++++++++++++------
 gdbserver/server.cc                        |   4 +-
 gdbserver/server.h                         |   5 +
 gdbsupport/fileio.cc                       |  70 ++++++++++++++
 gdbsupport/fileio.h                        |  54 ++++++++++-
 11 files changed, 480 insertions(+), 78 deletions(-)

-- 
2.52.0


^ permalink raw reply	[flat|nested] 9+ messages in thread

* [PATCH v3 1/2] gdbserver: widen the stat fields returned by the vFile packets
  2026-10-14  9:21 [PATCH v3 0/2] Widen the stat fields in the remote protocol Abhay Kandpal
@ 2026-10-14  9:21 ` Abhay Kandpal
  2026-10-27 17:27   ` Ulrich Weigand
  2026-10-27 22:16   ` Andrew Burgess
  2026-10-14  9:21 ` [PATCH v3 2/2] gdb: add stat64 and fstat64 to the F-packet file-i/o protocol Abhay Kandpal
  1 sibling, 2 replies; 9+ messages in thread
From: Abhay Kandpal @ 2026-10-14  9:21 UTC (permalink / raw)
  To: gdb-patches; +Cc: aburgess, Ulrich.Weigand, eliz, cel, abhay.k, Abhay Kandpal

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 six too-narrow fields are 8 bytes; otherwise the existing
struct fio_stat is used, exactly as before.

Internally both GDB and gdbserver now work with the wide struct, and
the conversion happens at the wire boundary: gdbserver narrows the
result before sending it if the feature was not negotiated, and GDB
selects the unpacker by the length of the reply.  Narrowing a value
which does not fit now produces a warning rather than truncating
silently.

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.

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 unexpected failures in the full testsuite.

gdb/
	* NEWS: Mention the stat64 feature.
	* doc/gdb.texinfo (General Query Packets): Document the stat64
	feature.
	(Host I/O Packets): Mention the wide reply format.
	(struct stat64): New node.
	* remote-fileio.c (remote_fileio_to_host_ulong8): New function.
	(remote_fileio_wide_to_host_stat): New function.
	* remote-fileio.h (remote_fileio_wide_to_host_stat): Declare.
	* remote.c (PACKET_stat64_feature): New enum value.
	(remote_features::stat64_feature): New method.
	(remote_protocol_features): Add stat64.
	(remote_target::remote_query_supported): Send stat64+.
	(fileio_process_fstat_and_lstat_reply): Handle both formats.
	(INIT_GDB_FILE): Add the stat64-feature packet command.
	* testsuite/gdb.server/fileio-packets.py (decode_stat_reply):
	Handle both the narrow and wide reply formats.

gdbserver/
	* hostio.cc (handle_fstat, handle_stat, handle_lstat): Send the
	wide struct when the feature is negotiated.
	* server.cc (handle_query): Handle and report stat64.
	* server.h (client_state::stat64_feature): New member.

gdbsupport/
	* fileio.cc (host_to_fileio_stat_wide): New function.
	(narrow_field, fileio_stat_wide_to_narrow): New functions.
	* fileio.h (struct fio_stat_wide): New struct.
	(bigendian_to_host): New function.
	(host_to_fileio_stat_wide, fileio_stat_wide_to_narrow): Declare.

Bug: https://sourceware.org/bugzilla/show_bug.cgi?id=34567
Reviewed-By: Eli Zaretskii <eliz@gnu.org>
---
 gdb/NEWS                                   |  13 +++
 gdb/doc/gdb.texinfo                        |  50 ++++++++++
 gdb/remote-fileio.c                        |  35 ++++++-
 gdb/remote-fileio.h                        |   4 +
 gdb/remote.c                               |  36 +++++--
 gdb/testsuite/gdb.server/fileio-packets.py |  59 +++++++-----
 gdbserver/hostio.cc                        | 106 +++++++++++++++------
 gdbserver/server.cc                        |   4 +-
 gdbserver/server.h                         |   5 +
 gdbsupport/fileio.cc                       |  70 ++++++++++++++
 gdbsupport/fileio.h                        |  54 ++++++++++-
 11 files changed, 370 insertions(+), 66 deletions(-)

diff --git a/gdb/NEWS b/gdb/NEWS
index 5d0c4745653..16c81b02e5a 100644
--- a/gdb/NEWS
+++ b/gdb/NEWS
@@ -79,6 +79,19 @@ 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 as before.  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 4bd5357c587..84f3143ce5e 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..76deb80d10a 100644
--- a/gdb/remote-fileio.c
+++ b/gdb/remote-fileio.c
@@ -1220,7 +1220,40 @@ remote_fileio_to_host_stat (struct fio_stat *fst, struct stat *st)
   st->st_mtime = remote_fileio_to_host_time (fst->fst_mtime);
   st->st_ctime = remote_fileio_to_host_time (fst->fst_ctime);
 }
-\f
+
+/* Unpack an 8-byte protocol field.  */
+
+static ULONGEST
+remote_fileio_to_host_ulong8 (const char *fnum)
+{
+  return extract_unsigned_integer ((const gdb_byte *) fnum, 8,
+				   BFD_ENDIAN_BIG);
+}
+
+/* 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_ulong8 (fst->fst_dev);
+  st->st_ino = remote_fileio_to_host_ulong8 (fst->fst_ino);
+  st->st_mode = remote_fileio_to_host_mode (fst->fst_mode);
+  st->st_nlink = remote_fileio_to_host_ulong8 (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_ulong8 (fst->fst_rdev);
+  st->st_size = remote_fileio_to_host_ulong8 (fst->fst_size);
+#ifdef HAVE_STRUCT_STAT_ST_BLKSIZE
+  st->st_blksize = remote_fileio_to_host_ulong8 (fst->fst_blksize);
+#endif
+#if HAVE_STRUCT_STAT_ST_BLOCKS
+  st->st_blocks = remote_fileio_to_host_ulong8 (fst->fst_blocks);
+#endif
+  st->st_atime = remote_fileio_to_host_ulong8 (fst->fst_atime);
+  st->st_mtime = remote_fileio_to_host_ulong8 (fst->fst_mtime);
+  st->st_ctime = remote_fileio_to_host_ulong8 (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..95fb042fc9d 100644
--- a/gdb/remote-fileio.h
+++ b/gdb/remote-fileio.h
@@ -44,4 +44,8 @@ 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..30959a09044 100644
--- a/gdb/remote.c
+++ b/gdb/remote.c
@@ -389,6 +389,8 @@ enum {
      packets and the tag violation stop replies.  */
   PACKET_memory_tagging_feature,
 
+  PACKET_stat64_feature,
+
   /* Support for the qIsAddressTagged packet.  */
   PACKET_qIsAddressTagged,
 
@@ -844,6 +846,9 @@ struct remote_features
   bool remote_memory_tagging_p () const
   { return packet_support (PACKET_memory_tagging_feature) == PACKET_ENABLE; }
 
+  bool stat64_feature () const
+  { return packet_support (PACKET_stat64_feature) == PACKET_ENABLE; }
+
   /* Returns true if there is support for sending vRun inferior arguments
      as a single string.  */
   bool remote_vrun_single_arg_p () const
@@ -6188,6 +6193,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 +6305,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,29 +13667,35 @@ 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,
 				      int attachment_len,
 				      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 +17049,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..2d06edcdbf7 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..34def5d22da 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
 {
@@ -465,7 +464,7 @@ handle_fstat (char *own_buf, int *new_packet_len)
   int fd, bytes_sent;
   char *p;
   struct stat st;
-  struct fio_stat fst;
+  client_state &cs = get_client_state ();
 
   p = own_buf + strlen ("vFile:fstat:");
 
@@ -483,16 +482,31 @@ 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);
+  struct fio_stat_wide wide;
+  host_to_fileio_stat_wide (&st, &wide);
 
-  /* 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);
+  /* Send the wide form if GDB understands it, otherwise narrow the
+     result first.  */
+  if (cs.stat64_feature)
+    {
+      bytes_sent = hostio_reply_with_data (own_buf, (char *) &wide,
+					   sizeof (wide), 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 (wide))
+	write_enn (own_buf);
+    }
+  else
+    {
+      struct fio_stat narrow;
+      fileio_stat_wide_to_narrow (&wide, &narrow);
+      bytes_sent = hostio_reply_with_data (own_buf, (char *) &narrow,
+					   sizeof (narrow), 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 (narrow))
+	write_enn (own_buf);
+    }
 }
 
 static void
@@ -501,8 +515,8 @@ 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];
+  client_state &cs = get_client_state ();
 
   p = own_buf + strlen ("vFile:stat:");
 
@@ -519,16 +533,31 @@ 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);
+  struct fio_stat_wide wide;
+  host_to_fileio_stat_wide (&st, &wide);
 
-  /* 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);
+  /* Send the wide form if GDB understands it, otherwise narrow the
+     result first.  */
+  if (cs.stat64_feature)
+    {
+      bytes_sent = hostio_reply_with_data (own_buf, (char *) &wide,
+					   sizeof (wide), 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 (wide))
+	write_enn (own_buf);
+    }
+  else
+    {
+      struct fio_stat narrow;
+      fileio_stat_wide_to_narrow (&wide, &narrow);
+      bytes_sent = hostio_reply_with_data (own_buf, (char *) &narrow,
+					   sizeof (narrow), 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 (narrow))
+	write_enn (own_buf);
+    }
 }
 
 static void
@@ -537,8 +566,8 @@ handle_lstat (char *own_buf, int *new_packet_len)
   int ret, bytes_sent;
   char *p;
   struct stat st;
-  struct fio_stat fst;
   char filename[HOSTIO_PATH_MAX];
+  client_state &cs = get_client_state ();
 
   p = own_buf + strlen ("vFile:lstat:");
 
@@ -560,16 +589,31 @@ 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);
+  struct fio_stat_wide wide;
+  host_to_fileio_stat_wide (&st, &wide);
 
-  /* 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);
+  /* Send the wide form if GDB understands it, otherwise narrow the
+     result first.  */
+  if (cs.stat64_feature)
+    {
+      bytes_sent = hostio_reply_with_data (own_buf, (char *) &wide,
+					   sizeof (wide), 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 (wide))
+	write_enn (own_buf);
+    }
+  else
+    {
+      struct fio_stat narrow;
+      fileio_stat_wide_to_narrow (&wide, &narrow);
+      bytes_sent = hostio_reply_with_data (own_buf, (char *) &narrow,
+					   sizeof (narrow), 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 (narrow))
+	write_enn (own_buf);
+    }
 }
 
 static void
diff --git a/gdbserver/server.cc b/gdbserver/server.cc
index a208e24d09f..dfa24617847 100644
--- a/gdbserver/server.cc
+++ b/gdbserver/server.cc
@@ -2746,6 +2746,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.  */
@@ -2762,7 +2764,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 ())
diff --git a/gdbserver/server.h b/gdbserver/server.h
index bbba3650de7..cf811f228fa 100644
--- a/gdbserver/server.h
+++ b/gdbserver/server.h
@@ -192,6 +192,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 narrows the
+     result to struct fio_stat before sending it.  */
+  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..bab2c4c8efe 100644
--- a/gdbsupport/fileio.cc
+++ b/gdbsupport/fileio.cc
@@ -20,6 +20,7 @@
 #include "fileio.h"
 #include <sys/stat.h>
 #include <fcntl.h>
+#include "gdbsupport/errors.h"
 
 /* See fileio.h.  */
 
@@ -305,3 +306,72 @@ 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_bigendian ((LONGEST) st->st_dev, (char *) fst->fst_dev, 8);
+  host_to_bigendian ((LONGEST) st->st_ino, (char *) fst->fst_ino, 8);
+  host_to_fileio_mode (st->st_mode, fst->fst_mode);
+  host_to_bigendian ((LONGEST) st->st_nlink, (char *) fst->fst_nlink, 8);
+  host_to_fileio_uint ((long) st->st_uid, fst->fst_uid);
+  host_to_fileio_uint ((long) st->st_gid, fst->fst_gid);
+  host_to_bigendian ((LONGEST) st->st_rdev, (char *) fst->fst_rdev, 8);
+  host_to_bigendian ((LONGEST) st->st_size, (char *) fst->fst_size, 8);
+#ifdef HAVE_STRUCT_STAT_ST_BLKSIZE
+  blksize = st->st_blksize;
+#else
+  blksize = 512;
+#endif
+  host_to_bigendian (blksize, (char *) fst->fst_blksize, 8);
+#if HAVE_STRUCT_STAT_ST_BLOCKS
+  host_to_bigendian ((LONGEST) st->st_blocks, (char *) fst->fst_blocks, 8);
+#else
+  host_to_bigendian (((LONGEST) st->st_size + blksize - 1) / blksize,
+		     (char *) fst->fst_blocks, 8);
+#endif
+  host_to_bigendian ((LONGEST) st->st_atime, (char *) fst->fst_atime, 8);
+  host_to_bigendian ((LONGEST) st->st_mtime, (char *) fst->fst_mtime, 8);
+  host_to_bigendian ((LONGEST) st->st_ctime, (char *) fst->fst_ctime, 8);
+}
+
+/* Copy the 8-byte value in FROM into the 4-byte field TO, warning if
+   the value does not fit.  WHAT names the field, for the warning.  */
+
+static void
+narrow_field (const char *from, char *to, const char *what)
+{
+  ULONGEST num = bigendian_to_host (from, 8);
+
+  if (num != (ULONGEST) (uint32_t) num)
+    warning (_("file-i/o: %s value %s does not fit in 32 bits; "
+	       "the value seen by the peer will be truncated"),
+	     what, pulongest (num));
+
+  host_to_bigendian ((LONGEST) num, to, 4);
+}
+
+/* See fileio.h.  */
+
+void
+fileio_stat_wide_to_narrow (const struct fio_stat_wide *wide,
+			    struct fio_stat *narrow)
+{
+  narrow_field (wide->fst_dev, narrow->fst_dev, "st_dev");
+  narrow_field (wide->fst_ino, narrow->fst_ino, "st_ino");
+  memcpy (narrow->fst_mode, wide->fst_mode, 4);
+  narrow_field (wide->fst_nlink, narrow->fst_nlink, "st_nlink");
+  memcpy (narrow->fst_uid, wide->fst_uid, 4);
+  memcpy (narrow->fst_gid, wide->fst_gid, 4);
+  narrow_field (wide->fst_rdev, narrow->fst_rdev, "st_rdev");
+  memcpy (narrow->fst_size, wide->fst_size, 8);
+  memcpy (narrow->fst_blksize, wide->fst_blksize, 8);
+  memcpy (narrow->fst_blocks, wide->fst_blocks, 8);
+  narrow_field (wide->fst_atime, narrow->fst_atime, "st_atime");
+  narrow_field (wide->fst_mtime, narrow->fst_mtime, "st_mtime");
+  narrow_field (wide->fst_ctime, narrow->fst_ctime, "st_ctime");
+}
diff --git a/gdbsupport/fileio.h b/gdbsupport/fileio.h
index c2592cf8c15..fa5de54dd40 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,6 +204,20 @@ host_to_bigendian (LONGEST num, char *buf, int bytes)
     buf[i] = (num >> (8 * (bytes - i - 1))) & 0xff;
 }
 
+/* Unpack an integer of BYTES bytes from BUF, which holds it in
+   big-endian, protocol format.  */
+
+static inline ULONGEST
+bigendian_to_host (const char *buf, int bytes)
+{
+  ULONGEST num = 0;
+  int i;
+
+  for (i = 0; i < bytes; ++i)
+    num = (num << 8) | (unsigned char) buf[i];
+  return num;
+}
+
 /* Pack a host-format integer into an fio_uint_t.  */
 
 static inline void
@@ -199,4 +238,13 @@ 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);
+
+/* Narrow a struct fio_stat_wide into a struct fio_stat, warning if any
+   value does not fit.  */
+extern void fileio_stat_wide_to_narrow (const struct fio_stat_wide *wide,
+					struct fio_stat *narrow);
+
 #endif /* GDBSUPPORT_FILEIO_H */
-- 
2.52.0


^ permalink raw reply	[flat|nested] 9+ messages in thread

* [PATCH v3 2/2] gdb: add stat64 and fstat64 to the F-packet file-i/o protocol
  2026-10-14  9:21 [PATCH v3 0/2] Widen the stat fields in the remote protocol Abhay Kandpal
  2026-10-14  9:21 ` [PATCH v3 1/2] gdbserver: widen the stat fields returned by the vFile packets Abhay Kandpal
@ 2026-10-14  9:21 ` Abhay Kandpal
  2026-10-14 11:47   ` Eli Zaretskii
  2026-10-27 17:47   ` Ulrich Weigand
  1 sibling, 2 replies; 9+ messages in thread
From: Abhay Kandpal @ 2026-10-14  9:21 UTC (permalink / raw)
  To: gdb-patches; +Cc: aburgess, Ulrich.Weigand, eliz, cel, abhay.k, Abhay Kandpal

The previous patch widened the stat fields returned by the vFile
packets, using a qSupported feature to keep old and new GDB and
gdbserver compatible.  The F-packet file-i/o protocol has the same
problem: the Fstat and Ffstat calls write struct fio_stat into target
memory, in which st_dev, st_ino, st_nlink, st_rdev and the three
timestamps are 4 bytes, so those values are truncated on a 64-bit
host.

The F-packet calls cannot use qSupported, since the buffer is read
directly by the target.  But each request names the call it wants, so
add two new calls, Fstat64 and Ffstat64, which are identical to Fstat
and Ffstat except that they write struct fio_stat_wide.  Existing
targets keep using Fstat and Ffstat and see no change.  A GDB which
does not know the new calls already replies with ENOSYS, so a target
can try Fstat64 and fall back to Fstat.

The stat and fstat handlers become remote_fileio_do_stat and
remote_fileio_do_fstat, with a flag selecting the layout, and share a
new remote_fileio_write_stat helper.  The stat handler has always
reported st_dev as zero; that is now done on the struct stat before
packing, which gives the same result in either layout.

The console case in the fstat handler stored 1 into fst_dev, but that
was then overwritten when the struct was packed, so the target always
saw zero.  Drop the dead store; behaviour is unchanged.

gdb/
	* NEWS: Mention the Fstat64 and Ffstat64 calls.
	* doc/gdb.texinfo (List of Supported Calls): Add stat64/fstat64.
	(stat/fstat): Refer to stat64/fstat64.
	(stat64/fstat64): New node.
	(struct stat64): Mention the Fstat64 and Ffstat64 calls.
	* remote-fileio.c (remote_fileio_write_stat): New function.
	(remote_fileio_do_stat): Renamed from remote_fileio_func_stat.
	Add WIDE parameter.
	(remote_fileio_func_stat): Call remote_fileio_do_stat.
	(remote_fileio_func_stat64): New function.
	(remote_fileio_do_fstat): Renamed from remote_fileio_func_fstat.
	Add WIDE parameter.  Remove dead store to fst_dev.
	(remote_fileio_func_fstat): Call remote_fileio_do_fstat.
	(remote_fileio_func_fstat64): New function.
	(remote_fio_func_map): Add stat64 and fstat64.

gdbsupport/
	* fileio.h (struct fio_stat, struct fio_stat_wide): Update
	comments.

Tested on powerpc64le-linux, on an xfs filesystem with inode numbers
above 2^32, using a fake remote stub which issues File-I/O requests
and checks the buffer GDB writes into target memory.  Fstat64 and
Ffstat64 return the full inode number; Fstat and Ffstat return the
same truncated values as before.  An unpatched GDB answers Fstat64
and Ffstat64 with ENOSYS.  gdb.server/fileio-packets.exp continues
to pass.

Bug: https://sourceware.org/bugzilla/show_bug.cgi?id=34567
Suggested-by: Ulrich Weigand <Ulrich.Weigand@de.ibm.com>
---
 gdb/NEWS            |  9 ++++++
 gdb/doc/gdb.texinfo | 52 +++++++++++++++++++++++++++++++++--
 gdb/remote-fileio.c | 67 +++++++++++++++++++++++++++++++++++++--------
 gdbsupport/fileio.h | 14 +++++-----
 4 files changed, 120 insertions(+), 22 deletions(-)

diff --git a/gdb/NEWS b/gdb/NEWS
index 16c81b02e5a..5d53ef1eb9b 100644
--- a/gdb/NEWS
+++ b/gdb/NEWS
@@ -79,6 +79,15 @@ info locals
   The new "-shadowed on|off" option overrides the "set print shadowed"
   setting for a single invocation of the command.
 
+* New remote packets
+
+Fstat64, Ffstat64
+  New File-I/O calls, identical to Fstat and Ffstat except that they
+  fill in the wider struct stat64 layout, in which st_dev, st_ino,
+  st_nlink, st_rdev and the three timestamps are 8 bytes rather than
+  4.  A GDB without these calls replies with ENOSYS, so a target can
+  fall back to Fstat and Ffstat.
+
 * Changed remote packets
 
 stat64 in qSupported
diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo
index 84f3143ce5e..2c13853a1a0 100644
--- a/gdb/doc/gdb.texinfo
+++ b/gdb/doc/gdb.texinfo
@@ -48136,6 +48136,7 @@ is stopped at the user's request.
 * rename::
 * unlink::
 * stat/fstat::
+* stat64/fstat64::
 * gettimeofday::
 * isatty::
 * system::
@@ -48581,6 +48582,49 @@ The call was interrupted by the user.
 
 @end table
 
+The buffer uses the narrow @code{struct stat} layout, in which some
+members may be truncated on a 64-bit host.  @xref{stat64/fstat64}, for
+calls which use a wider layout.
+
+@node stat64/fstat64
+@unnumberedsubsubsec stat64/fstat64
+@cindex fstat64, file-i/o system call
+@cindex stat64, file-i/o system call
+
+@table @asis
+@item Synopsis:
+@smallexample
+int stat64(const char *pathname, struct stat64 *buf);
+int fstat64(int fd, struct stat64 *buf);
+@end smallexample
+
+@item Request:
+@samp{Fstat64,@var{pathnameptr}/@var{len},@var{bufptr}}@*
+@samp{Ffstat64,@var{fd},@var{bufptr}}
+
+These calls are identical to @samp{Fstat} and @samp{Ffstat}
+(@pxref{stat/fstat}), except that the buffer at @var{bufptr} is
+filled in using the wider @code{struct stat64} layout
+(@pxref{struct stat64}), which can hold the values found on a 64-bit
+host without truncation.
+
+A version of @value{GDBN} which does not support these calls replies
+with an @code{ENOSYS} error.  The target can then fall back to
+@samp{Fstat} or @samp{Ffstat}.
+
+@item Return value:
+On success, zero is returned.  On error, -1 is returned.
+
+@item Errors:
+As for @samp{Fstat} and @samp{Ffstat}, and in addition:
+
+@table @code
+@item ENOSYS
+@value{GDBN} does not support this call.
+@end table
+
+@end table
+
 @node gettimeofday
 @unnumberedsubsubsec gettimeofday
 @cindex gettimeofday, file-i/o system call
@@ -48837,7 +48881,9 @@ get truncated on the target.
 
 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:
+packets uses the following representation instead.  The
+@samp{Fstat64} and @samp{Ffstat64} File-I/O calls
+(@pxref{stat64/fstat64}) always use it.
 
 @smallexample
 struct stat64 @{
@@ -48863,8 +48909,8 @@ as in the narrow form (@pxref{struct stat}), but @code{st_dev},
 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}).
+The @samp{Fstat} and @samp{Ffstat} File-I/O calls always use the narrow
+form (@pxref{struct stat}).
 
 @node struct timeval
 @unnumberedsubsubsec struct timeval
diff --git a/gdb/remote-fileio.c b/gdb/remote-fileio.c
index 76deb80d10a..7c1f050c789 100644
--- a/gdb/remote-fileio.c
+++ b/gdb/remote-fileio.c
@@ -791,14 +791,36 @@ remote_fileio_func_unlink (remote_target *remote, char *buf)
     remote_fileio_return_success (remote, ret);
 }
 
+/* Write ST into target memory at ADDR, using the struct fio_stat
+   layout or, if WIDE, the struct fio_stat_wide layout.  Return 0 on
+   success, or an errno value.  */
+
+static int
+remote_fileio_write_stat (CORE_ADDR addr, struct stat *st, bool wide)
+{
+  if (wide)
+    {
+      struct fio_stat_wide fst;
+
+      host_to_fileio_stat_wide (st, &fst);
+      return target_write_memory (addr, (gdb_byte *) &fst, sizeof fst);
+    }
+  else
+    {
+      struct fio_stat fst;
+
+      host_to_fileio_stat (st, &fst);
+      return target_write_memory (addr, (gdb_byte *) &fst, sizeof fst);
+    }
+}
+
 static void
-remote_fileio_func_stat (remote_target *remote, char *buf)
+remote_fileio_do_stat (remote_target *remote, char *buf, bool wide)
 {
   CORE_ADDR statptr, nameptr;
   int ret, namelength;
   LONGEST lnum;
   struct stat st;
-  struct fio_stat fst;
 
   /* 1. Parameter: Ptr to pathname / length incl. trailing zero */
   if (remote_fileio_extract_ptr_w_len (&buf, &nameptr, &namelength))
@@ -839,10 +861,9 @@ remote_fileio_func_stat (remote_target *remote, char *buf)
     }
   if (statptr)
     {
-      host_to_fileio_stat (&st, &fst);
-      host_to_fileio_uint (0, fst.fst_dev);
-
-      errno = target_write_memory (statptr, (gdb_byte *) &fst, sizeof fst);
+      /* The stat call has always reported st_dev as zero.  */
+      st.st_dev = 0;
+      errno = remote_fileio_write_stat (statptr, &st, wide);
       if (errno != 0)
 	{
 	  remote_fileio_return_errno (remote, -1);
@@ -853,14 +874,25 @@ remote_fileio_func_stat (remote_target *remote, char *buf)
 }
 
 static void
-remote_fileio_func_fstat (remote_target *remote, char *buf)
+remote_fileio_func_stat (remote_target *remote, char *buf)
+{
+  remote_fileio_do_stat (remote, buf, false);
+}
+
+static void
+remote_fileio_func_stat64 (remote_target *remote, char *buf)
+{
+  remote_fileio_do_stat (remote, buf, true);
+}
+
+static void
+remote_fileio_do_fstat (remote_target *remote, char *buf, bool wide)
 {
   CORE_ADDR ptrval;
   int fd, ret;
   long target_fd;
   LONGEST lnum;
   struct stat st;
-  struct fio_stat fst;
   struct timeval tv;
 
   /* 1. Parameter: file descriptor */
@@ -885,7 +917,6 @@ remote_fileio_func_fstat (remote_target *remote, char *buf)
 
   if (fd == FIO_FD_CONSOLE_IN || fd == FIO_FD_CONSOLE_OUT)
     {
-      host_to_fileio_uint (1, fst.fst_dev);
       memset (&st, 0, sizeof (st));
       st.st_mode = S_IFCHR | (fd == FIO_FD_CONSOLE_IN ? S_IRUSR : S_IWUSR);
       st.st_nlink = 1;
@@ -917,9 +948,7 @@ remote_fileio_func_fstat (remote_target *remote, char *buf)
     }
   if (ptrval)
     {
-      host_to_fileio_stat (&st, &fst);
-
-      errno = target_write_memory (ptrval, (gdb_byte *) &fst, sizeof fst);
+      errno = remote_fileio_write_stat (ptrval, &st, wide);
       if (errno != 0)
 	{
 	  remote_fileio_return_errno (remote, -1);
@@ -929,6 +958,18 @@ remote_fileio_func_fstat (remote_target *remote, char *buf)
   remote_fileio_return_success (remote, ret);
 }
 
+static void
+remote_fileio_func_fstat (remote_target *remote, char *buf)
+{
+  remote_fileio_do_fstat (remote, buf, false);
+}
+
+static void
+remote_fileio_func_fstat64 (remote_target *remote, char *buf)
+{
+  remote_fileio_do_fstat (remote, buf, true);
+}
+
 static void
 remote_fileio_func_gettimeofday (remote_target *remote, char *buf)
 {
@@ -1062,6 +1103,8 @@ static struct {
   { "unlink", remote_fileio_func_unlink },
   { "stat", remote_fileio_func_stat },
   { "fstat", remote_fileio_func_fstat },
+  { "stat64", remote_fileio_func_stat64 },
+  { "fstat64", remote_fileio_func_fstat64 },
   { "gettimeofday", remote_fileio_func_gettimeofday },
   { "isatty", remote_fileio_func_isatty },
   { "system", remote_fileio_func_system },
diff --git a/gdbsupport/fileio.h b/gdbsupport/fileio.h
index fa5de54dd40..2d7a775918c 100644
--- a/gdbsupport/fileio.h
+++ b/gdbsupport/fileio.h
@@ -121,10 +121,10 @@ using fio_long_t = char[FIO_LONG_LEN];
 using fio_ulong_t = char[FIO_ULONG_LEN];
 
 /* 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.  */
+   F-packet file-i/o stat and fstat calls, 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
 {
@@ -145,9 +145,9 @@ struct fio_stat
 
 /* 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.  */
+   host are widened to 8 bytes.  This layout is used by the vFile stat
+   packets when the stat64 feature has been negotiated with the peer,
+   and by the F-packet file-i/o stat64 and fstat64 calls.  */
 
 struct fio_stat_wide
 {
-- 
2.52.0


^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [PATCH v3 2/2] gdb: add stat64 and fstat64 to the F-packet file-i/o protocol
  2026-10-14  9:21 ` [PATCH v3 2/2] gdb: add stat64 and fstat64 to the F-packet file-i/o protocol Abhay Kandpal
@ 2026-10-14 11:47   ` Eli Zaretskii
  2026-10-27 17:47   ` Ulrich Weigand
  1 sibling, 0 replies; 9+ messages in thread
From: Eli Zaretskii @ 2026-10-14 11:47 UTC (permalink / raw)
  To: Abhay Kandpal; +Cc: gdb-patches, aburgess, Ulrich.Weigand, cel, abhay.k

> From: Abhay Kandpal <abhay@linux.ibm.com>
> 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>
> Date: Wed, 14 Oct 2026 04:21:39 -0500
> 
> The previous patch widened the stat fields returned by the vFile
> packets, using a qSupported feature to keep old and new GDB and
> gdbserver compatible.  The F-packet file-i/o protocol has the same
> problem: the Fstat and Ffstat calls write struct fio_stat into target
> memory, in which st_dev, st_ino, st_nlink, st_rdev and the three
> timestamps are 4 bytes, so those values are truncated on a 64-bit
> host.
> 
> The F-packet calls cannot use qSupported, since the buffer is read
> directly by the target.  But each request names the call it wants, so
> add two new calls, Fstat64 and Ffstat64, which are identical to Fstat
> and Ffstat except that they write struct fio_stat_wide.  Existing
> targets keep using Fstat and Ffstat and see no change.  A GDB which
> does not know the new calls already replies with ENOSYS, so a target
> can try Fstat64 and fall back to Fstat.
> 
> The stat and fstat handlers become remote_fileio_do_stat and
> remote_fileio_do_fstat, with a flag selecting the layout, and share a
> new remote_fileio_write_stat helper.  The stat handler has always
> reported st_dev as zero; that is now done on the struct stat before
> packing, which gives the same result in either layout.
> 
> The console case in the fstat handler stored 1 into fst_dev, but that
> was then overwritten when the struct was packed, so the target always
> saw zero.  Drop the dead store; behaviour is unchanged.
> 
> gdb/
> 	* NEWS: Mention the Fstat64 and Ffstat64 calls.
> 	* doc/gdb.texinfo (List of Supported Calls): Add stat64/fstat64.
> 	(stat/fstat): Refer to stat64/fstat64.
> 	(stat64/fstat64): New node.
> 	(struct stat64): Mention the Fstat64 and Ffstat64 calls.
> 	* remote-fileio.c (remote_fileio_write_stat): New function.
> 	(remote_fileio_do_stat): Renamed from remote_fileio_func_stat.
> 	Add WIDE parameter.
> 	(remote_fileio_func_stat): Call remote_fileio_do_stat.
> 	(remote_fileio_func_stat64): New function.
> 	(remote_fileio_do_fstat): Renamed from remote_fileio_func_fstat.
> 	Add WIDE parameter.  Remove dead store to fst_dev.
> 	(remote_fileio_func_fstat): Call remote_fileio_do_fstat.
> 	(remote_fileio_func_fstat64): New function.
> 	(remote_fio_func_map): Add stat64 and fstat64.
> 
> gdbsupport/
> 	* fileio.h (struct fio_stat, struct fio_stat_wide): Update
> 	comments.
> 
> Tested on powerpc64le-linux, on an xfs filesystem with inode numbers
> above 2^32, using a fake remote stub which issues File-I/O requests
> and checks the buffer GDB writes into target memory.  Fstat64 and
> Ffstat64 return the full inode number; Fstat and Ffstat return the
> same truncated values as before.  An unpatched GDB answers Fstat64
> and Ffstat64 with ENOSYS.  gdb.server/fileio-packets.exp continues
> to pass.
> 
> Bug: https://sourceware.org/bugzilla/show_bug.cgi?id=34567
> Suggested-by: Ulrich Weigand <Ulrich.Weigand@de.ibm.com>
> ---
>  gdb/NEWS            |  9 ++++++
>  gdb/doc/gdb.texinfo | 52 +++++++++++++++++++++++++++++++++--
>  gdb/remote-fileio.c | 67 +++++++++++++++++++++++++++++++++++++--------
>  gdbsupport/fileio.h | 14 +++++-----
>  4 files changed, 120 insertions(+), 22 deletions(-)

Thanks, the documentation parts are approved.

Reviewed-By: Eli Zaretskii <eliz@gnu.org>

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [PATCH v3 1/2] gdbserver: widen the stat fields returned by the vFile packets
  2026-10-14  9:21 ` [PATCH v3 1/2] gdbserver: widen the stat fields returned by the vFile packets Abhay Kandpal
@ 2026-10-27 17:27   ` Ulrich Weigand
  2026-10-27 22:16   ` Andrew Burgess
  1 sibling, 0 replies; 9+ messages in thread
From: Ulrich Weigand @ 2026-10-27 17:27 UTC (permalink / raw)
  To: Abhay Kandpal, gdb-patches; +Cc: Andrew Burgess, eliz, cel, Abhay Kandpal

Abhay Kandpal <abhay@linux.ibm.com> wrote:

>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 six too-narrow fields are 8 bytes; otherwise the existing
>struct fio_stat is used, exactly as before.

This looks all generally reasonable to me.  A couple of minor comments.

>+static ULONGEST
>+remote_fileio_to_host_ulong8 (const char *fnum)
>+{
>+  return extract_unsigned_integer ((const gdb_byte *) fnum, 8,
>+				   BFD_ENDIAN_BIG);
>+}

Why do we need this?  The existing remote_fileio_to_host_ulong
should do the right thing already ...

>-  host_to_fileio_stat (&st, &fst);
>-
>-  bytes_sent = hostio_reply_with_data (own_buf,
>-				       (char *) &fst, sizeof (fst),
>-				       new_packet_len);
>+  struct fio_stat_wide wide;
>+  host_to_fileio_stat_wide (&st, &wide);
> 
>-  /* 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);
>+  /* Send the wide form if GDB understands it, otherwise narrow the
>+     result first.  */
>+  if (cs.stat64_feature)
>+    {
>+      bytes_sent = hostio_reply_with_data (own_buf, (char *) &wide,
>+					   sizeof (wide),
>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 (wide))
>+	write_enn (own_buf);
>+    }
>+  else
>+    {
>+      struct fio_stat narrow;
>+      fileio_stat_wide_to_narrow (&wide, &narrow);

Do we really need the wide_to_narrow conversion routine?
I think it would be preferable to convert from the host struct
directly to the fio_stat_wide in the if path and to fio_stat
in the else path.  Otherwise we end up converting twice.

If we want to emit a warning, maybe that should be done
in host_to_fileio_uint ?

>+      bytes_sent = hostio_reply_with_data (own_buf, (char *) &narrow,
>+					   sizeof (narrow),
>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 (narrow))
>+	write_enn (own_buf);
>+    }

This whole block is now duplicated three times, so it might be
worth a helper routine.

>+void
>+host_to_fileio_stat_wide (struct stat *st, struct fio_stat_wide *fst)
>+{
>+  LONGEST blksize;
>+
>+  host_to_bigendian ((LONGEST) st->st_dev, (char *) fst->fst_dev, 8);
>+  host_to_bigendian ((LONGEST) st->st_ino, (char *) fst->fst_ino, 8);

Again, we should be using the existing host_to_fileio_ulong.

Bye,
Ulrich

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [PATCH v3 2/2] gdb: add stat64 and fstat64 to the F-packet file-i/o protocol
  2026-10-14  9:21 ` [PATCH v3 2/2] gdb: add stat64 and fstat64 to the F-packet file-i/o protocol Abhay Kandpal
  2026-10-14 11:47   ` Eli Zaretskii
@ 2026-10-27 17:47   ` Ulrich Weigand
  2026-10-28 10:42     ` Abhay Kandpal
  1 sibling, 1 reply; 9+ messages in thread
From: Ulrich Weigand @ 2026-10-27 17:47 UTC (permalink / raw)
  To: Abhay Kandpal, gdb-patches; +Cc: Andrew Burgess, eliz, cel, Abhay Kandpal

Abhay Kandpal <abhay@linux.ibm.com> wrote:

>The F-packet calls cannot use qSupported, since the buffer is read
>directly by the target.  But each request names the call it wants, so
>add two new calls, Fstat64 and Ffstat64, which are identical to Fstat
>and Ffstat except that they write struct fio_stat_wide.  Existing
>targets keep using Fstat and Ffstat and see no change.  A GDB which
>does not know the new calls already replies with ENOSYS, so a target
>can try Fstat64 and fall back to Fstat.

This makes sense to me, if support for this is needed.  I'm not
really sure who -if anyone- is using these F-packets; gdbserver
doesn't seem to do so and there's no test in the test suite ...

Andrew, do you have any thoughts on this?


>The console case in the fstat handler stored 1 into fst_dev, but that
>was then overwritten when the struct was packed, so the target always
>saw zero.  Drop the dead store; behaviour is unchanged.

Interesting.  Seems this accidentally changed here:
https://sourceware.org/pipermail/gdb-patches/2015-March/122143.html

which says:
	(remote_fileio_mode_to_target): Moved to common-remote-
fileio.c.
	(remote_fileio_to_fio_mode): Likewise.
	(remote_fileio_to_fio_ulong): Likewise.
	(remote_fileio_to_fio_stat): Likewise.

but in addition to the move, changed:

-static void
-remote_fileio_to_fio_stat (struct stat *st, struct fio_stat *fst)
-{
-  LONGEST blksize;
-
-  /* `st_dev' is set in the calling function.  */
-  remote_fileio_to_fio_uint ((long) st->st_ino, fst->fst_ino);

to:

+void
+remote_fileio_to_fio_stat (struct stat *st, struct fio_stat *fst)
+{
+  LONGEST blksize;
+
+  remote_fileio_to_fio_uint ((long) st->st_dev, fst->fst_dev);
+  remote_fileio_to_fio_uint ((long) st->st_ino, fst->fst_ino);


So up until 2015 fst_dev was indeed 1 for the console and
0 for everything else, and since then it's been 0 always.
Given that long time, it may be fine to keep it at 0 now ...

On the other hand, the documentation still says:

@item st_dev
A value of 0 represents a file, 1 the console.

So we can either fix the code again, or else update the
documentation to match the behavior over the last 10 years.
Thoughts?

Bye,
Ulrich

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [PATCH v3 1/2] gdbserver: widen the stat fields returned by the vFile packets
  2026-10-14  9:21 ` [PATCH v3 1/2] gdbserver: widen the stat fields returned by the vFile packets Abhay Kandpal
  2026-10-27 17:27   ` Ulrich Weigand
@ 2026-10-27 22:16   ` Andrew Burgess
  1 sibling, 0 replies; 9+ messages in thread
From: Andrew Burgess @ 2026-10-27 22:16 UTC (permalink / raw)
  To: Abhay Kandpal, gdb-patches
  Cc: Ulrich.Weigand, eliz, cel, abhay.k, Abhay Kandpal

Abhay Kandpal <abhay@linux.ibm.com> writes:

> 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 six too-narrow fields are 8 bytes; otherwise the existing

Isn't is seven fields?  st_dev, st_ino, st_nlink, st_rdev and the three
timestamps.

> struct fio_stat is used, exactly as before.
>
> Internally both GDB and gdbserver now work with the wide struct, and
> the conversion happens at the wire boundary: gdbserver narrows the
> result before sending it if the feature was not negotiated, and GDB
> selects the unpacker by the length of the reply.  Narrowing a value
> which does not fit now produces a warning rather than truncating
> silently.
>
> 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.
>
> 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 unexpected failures in the full testsuite.
>
> gdb/
> 	* NEWS: Mention the stat64 feature.
> 	* doc/gdb.texinfo (General Query Packets): Document the stat64
> 	feature.
> 	(Host I/O Packets): Mention the wide reply format.
> 	(struct stat64): New node.
> 	* remote-fileio.c (remote_fileio_to_host_ulong8): New function.
> 	(remote_fileio_wide_to_host_stat): New function.
> 	* remote-fileio.h (remote_fileio_wide_to_host_stat): Declare.
> 	* remote.c (PACKET_stat64_feature): New enum value.
> 	(remote_features::stat64_feature): New method.
> 	(remote_protocol_features): Add stat64.
> 	(remote_target::remote_query_supported): Send stat64+.
> 	(fileio_process_fstat_and_lstat_reply): Handle both formats.
> 	(INIT_GDB_FILE): Add the stat64-feature packet command.
> 	* testsuite/gdb.server/fileio-packets.py (decode_stat_reply):
> 	Handle both the narrow and wide reply formats.
>
> gdbserver/
> 	* hostio.cc (handle_fstat, handle_stat, handle_lstat): Send the
> 	wide struct when the feature is negotiated.
> 	* server.cc (handle_query): Handle and report stat64.
> 	* server.h (client_state::stat64_feature): New member.
>
> gdbsupport/
> 	* fileio.cc (host_to_fileio_stat_wide): New function.
> 	(narrow_field, fileio_stat_wide_to_narrow): New functions.
> 	* fileio.h (struct fio_stat_wide): New struct.
> 	(bigendian_to_host): New function.
> 	(host_to_fileio_stat_wide, fileio_stat_wide_to_narrow): Declare.

These style of changelog entries are no longer used in GDB and shouldn't
be included.



> @@ -13656,29 +13667,35 @@ 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

I think you lost the blank line between the comment and the 'static int' line.

>  fileio_process_fstat_and_lstat_reply (const char *attachment,
>  				      int attachment_len,
>  				      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));
>  


> @@ -519,16 +533,31 @@ 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);
> +  struct fio_stat_wide wide;
> +  host_to_fileio_stat_wide (&st, &wide);
>  
> -  /* 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);
> +  /* Send the wide form if GDB understands it, otherwise narrow the
> +     result first.  */
> +  if (cs.stat64_feature)
> +    {
> +      bytes_sent = hostio_reply_with_data (own_buf, (char *) &wide,
> +					   sizeof (wide), 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 (wide))
> +	write_enn (own_buf);
> +    }
> +  else
> +    {
> +      struct fio_stat narrow;
> +      fileio_stat_wide_to_narrow (&wide, &narrow);
> +      bytes_sent = hostio_reply_with_data (own_buf, (char *) &narrow,
> +					   sizeof (narrow), 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 (narrow))
> +	write_enn (own_buf);
> +    }

This pattern is repeated 3 times.  I wonder if you could factor out a
helper function, hostio_send_stat_reply,  to handle this duplication?

>  }
>  
>  static void


> diff --git a/gdbserver/server.h b/gdbserver/server.h
> index bbba3650de7..cf811f228fa 100644
> --- a/gdbserver/server.h
> +++ b/gdbserver/server.h
> @@ -192,6 +192,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 narrows the
> +     result to struct fio_stat before sending it.  */
> +  bool stat64_feature = false;

If you search in gdbserver/server.cc for the comment text 'Be sure we're
out of tfind mode', you'll find a block of code that resets all of these
feature flags.

There is already a bug (introduced by me) for a feature flag that is not
being reset in this block correctly.  But your flag also needs resetting
here too.  Without this, then when we reconnect the feature flag from
the previous connection will remain turned on.

> +
>    /* 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


> @@ -199,4 +238,13 @@ 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);
> +
> +/* Narrow a struct fio_stat_wide into a struct fio_stat, warning if any
> +   value does not fit.  */
> +extern void fileio_stat_wide_to_narrow (const struct fio_stat_wide *wide,
> +					struct fio_stat *narrow);

GDB style leaves a blank line after the comment and before a function
declaration or definition.  Mostly.  We're not perfect.  But that's what
it's supposed to be.  This file looks to be following the style, so it
would be nice if this new code did too please.

There's also a place in gdbserver/hostio.h which should be fixed too
please.

Thanks,
Andrew

> +
>  #endif /* GDBSUPPORT_FILEIO_H */
> -- 
> 2.52.0


^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [PATCH v3 2/2] gdb: add stat64 and fstat64 to the F-packet file-i/o protocol
  2026-10-27 17:47   ` Ulrich Weigand
@ 2026-10-28 10:42     ` Abhay Kandpal
  2026-10-28 14:19       ` Ulrich Weigand
  0 siblings, 1 reply; 9+ messages in thread
From: Abhay Kandpal @ 2026-10-28 10:42 UTC (permalink / raw)
  To: Ulrich Weigand, gdb-patches; +Cc: Andrew Burgess, eliz, cel, Abhay Kandpal

[-- Attachment #1: Type: text/plain, Size: 3173 bytes --]

Hi Ulrich,

Thanks for looking.

On 27/10/26 23:17, Ulrich Weigand wrote:
> Abhay Kandpal<abhay@linux.ibm.com> wrote:
>
>> The F-packet calls cannot use qSupported, since the buffer is read
>> directly by the target.  But each request names the call it wants, so
>> add two new calls, Fstat64 and Ffstat64, which are identical to Fstat
>> and Ffstat except that they write struct fio_stat_wide.  Existing
>> targets keep using Fstat and Ffstat and see no change.  A GDB which
>> does not know the new calls already replies with ENOSYS, so a target
>> can try Fstat64 and fall back to Fstat.
> This makes sense to me, if support for this is needed.  I'm not
> really sure who -if anyone- is using these F-packets; gdbserver
> doesn't seem to do so and there's no test in the test suite ...
>
> Andrew, do you have any thoughts on this?

One user is QEMU: its semihosting code (semihosting/syscalls.c)
sends F-packet requests for every call in the protocol, including
both stat and fstat. I added 2/2 because Andrew preferred both
directions to be fixed, and I'm happy to go either way.

>
>
>> The console case in the fstat handler stored 1 into fst_dev, but that
>> was then overwritten when the struct was packed, so the target always
>> saw zero.  Drop the dead store; behaviour is unchanged.
> Interesting.  Seems this accidentally changed here:
> https://sourceware.org/pipermail/gdb-patches/2015-March/122143.html
>
> which says:
> 	(remote_fileio_mode_to_target): Moved to common-remote-
> fileio.c.
> 	(remote_fileio_to_fio_mode): Likewise.
> 	(remote_fileio_to_fio_ulong): Likewise.
> 	(remote_fileio_to_fio_stat): Likewise.
>
> but in addition to the move, changed:
>
> -static void
> -remote_fileio_to_fio_stat (struct stat *st, struct fio_stat *fst)
> -{
> -  LONGEST blksize;
> -
> -  /* `st_dev' is set in the calling function.  */
> -  remote_fileio_to_fio_uint ((long) st->st_ino, fst->fst_ino);
>
> to:
>
> +void
> +remote_fileio_to_fio_stat (struct stat *st, struct fio_stat *fst)
> +{
> +  LONGEST blksize;
> +
> +  remote_fileio_to_fio_uint ((long) st->st_dev, fst->fst_dev);
> +  remote_fileio_to_fio_uint ((long) st->st_ino, fst->fst_ino);
>
>
> So up until 2015 fst_dev was indeed 1 for the console and
> 0 for everything else, and since then it's been 0 always.
> Given that long time, it may be fine to keep it at 0 now ...
>
> On the other hand, the documentation still says:
>
> @item st_dev
> A value of 0 represents a file, 1 the console.
>
> So we can either fix the code again, or else update the
> documentation to match the behavior over the last 10 years.
> Thoughts?

There is a second mismatch as well. For a regular file, the fstat
handler never sets fst_dev, so the host's real st_dev is passed
through rather than the documented 0. Today only stat matches
the documentation:

stat, file:        documented 0, sends 0
fstat, console:    documented 1, sends 0
fstat, file:       documented 0, sends the host's st_dev

My preference would be to fix the code to match the documentation,
since the 2015 change looks accidental. I'd do that as a separate
patch, so it doesn't depend on the stat64 series.

Thanks
Abhay

>
> Bye,
> Ulrich

[-- Attachment #2: Type: text/html, Size: 4300 bytes --]

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [PATCH v3 2/2] gdb: add stat64 and fstat64 to the F-packet file-i/o protocol
  2026-10-28 10:42     ` Abhay Kandpal
@ 2026-10-28 14:19       ` Ulrich Weigand
  0 siblings, 0 replies; 9+ messages in thread
From: Ulrich Weigand @ 2026-10-28 14:19 UTC (permalink / raw)
  To: Abhay Kandpal, gdb-patches; +Cc: Andrew Burgess, eliz, cel, Abhay Kandpal

Abhay Kandpal <abhay@linux.ibm.com> wrote:

 
>There is a second mismatch as well. For a regular file, the fstat
>handler never sets fst_dev, so the host's real st_dev is passed
>through rather than the documented 0. Today only stat matches
>the documentation:
>
>stat, file:        documented 0, sends 0
>fstat, console:    documented 1, sends 0
>fstat, file:       documented 0, sends the host's st_dev

Ah, right.  That's even more confusing.

>My preference would be to fix the code to match the documentation,
>since the 2015 change looks accidental. I'd do that as a separate
>patch, so it doesn't depend on the stat64 series.

This makes sense to me, yes.

Thanks,
Ulrich


 

^ permalink raw reply	[flat|nested] 9+ messages in thread

end of thread, other threads:[~2026-10-28 14:20 UTC | newest]

Thread overview: 9+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2026-10-14  9:21 [PATCH v3 0/2] Widen the stat fields in the remote protocol Abhay Kandpal
2026-10-14  9:21 ` [PATCH v3 1/2] gdbserver: widen the stat fields returned by the vFile packets Abhay Kandpal
2026-10-27 17:27   ` Ulrich Weigand
2026-10-27 22:16   ` Andrew Burgess
2026-10-14  9:21 ` [PATCH v3 2/2] gdb: add stat64 and fstat64 to the F-packet file-i/o protocol Abhay Kandpal
2026-10-14 11:47   ` Eli Zaretskii
2026-10-27 17:47   ` Ulrich Weigand
2026-10-28 10:42     ` Abhay Kandpal
2026-10-28 14:19       ` Ulrich Weigand

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox