From: Abhay Kandpal <abhay@linux.ibm.com>
To: gdb-patches@sourceware.org
Cc: aburgess@redhat.com, eliz@gnu.org, cel@linux.ibm.com,
abhay.k@ibm.com, Ulrich Weigand <Ulrich.Weigand@de.ibm.com>
Subject: Re: [PATCH v2] gdbserver: widen the stat fields returned by the vFile packets
Date: Mon, 5 Oct 2026 15:04:18 +0530 [thread overview]
Message-ID: <92b8913a-c0c6-4357-891d-851943c6dbe3@linux.ibm.com> (raw)
In-Reply-To: <d492cef5-72bc-4321-8bdc-86ced0750642@linux.ibm.com>
[-- Attachment #1: Type: text/plain, Size: 33569 bytes --]
Hi Andrew,
Ping.
Eli has given Reviewed-By on the documentation, with his comments incorporated.
The remote protocol side still needs your review.
Thanks,
Abhay
On 16/09/26 18:52, Abhay Kandpal wrote:
> Hi Andrew,
> Ping. Let me know if the vFile-only scope looks right to you.
> Thanks,
> Abhay
>
>
> On 04/09/26 14:02, Abhay Kandpal wrote:
>> 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.
>>
>> Only the vFile packets are changed. The F-packet file-i/o protocol
>> uses the same struct, but writes it directly into inferior memory,
>> where the target reads it as the layout documented in the manual under
>> "struct stat"; that layout is left alone.
>>
>> 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>
>> ---
>> This patch is reg tested.
>>
>> 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 222f38e3d52..7c1a09752a9 100644
>> --- a/gdb/NEWS
>> +++ b/gdb/NEWS
>> @@ -3,6 +3,19 @@
>>
>> *** Changes since GDB 18
>>
>> +* 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 0030698dcee..355153212f0 100644
>> --- a/gdb/doc/gdb.texinfo
>> +++ b/gdb/doc/gdb.texinfo
>> @@ -46112,6 +46112,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
>> @@ -47358,6 +47363,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
>> @@ -47365,6 +47373,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}
>> @@ -47376,6 +47387,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
>> @@ -48570,6 +48584,7 @@ protocol.
>> * Pointer Values::
>> * Memory Transfer::
>> * struct stat::
>> +* struct stat64::
>> * struct timeval::
>> @end menu
>>
>> @@ -48696,6 +48711,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 76cf6b5234f..03cb8a074b7 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
>> @@ -6199,6 +6204,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 },
>> @@ -6309,6 +6316,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+"); @@ -13663,29 +13674,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; } @@ -17039,6 +17056,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 */
[-- Attachment #2: Type: text/html, Size: 34854 bytes --]
prev parent reply other threads:[~2026-10-05 9:35 UTC|newest]
Thread overview: 3+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-09-04 8:32 Abhay Kandpal
2026-09-16 13:22 ` Abhay Kandpal
2026-10-05 9:34 ` Abhay Kandpal [this message]
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=92b8913a-c0c6-4357-891d-851943c6dbe3@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