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 > --- > 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); > } > - > + > +/* 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 > #include > #include > -#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 > #include > +#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 */