From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from simark.ca by simark.ca with LMTP id ScFKKRJKz2reqAcAWB0awg (envelope-from ) for ; Wed, 14 Oct 2026 05:23:30 -0400 Authentication-Results: simark.ca; dkim=pass (2048-bit key; unprotected) header.d=ibm.com header.i=@ibm.com header.a=rsa-sha256 header.s=pp1 header.b=VlF8tqX4; dkim-atps=neutral Received: by simark.ca (Postfix, from userid 112) id 9891C1E06B; Wed, 14 Oct 2026 05:23:30 -0400 (EDT) X-Spam-Checker-Version: SpamAssassin 4.0.1 (2024-03-25) on simark.ca X-Spam-Level: X-Spam-Status: No, score=-5.3 required=5.0 tests=ARC_SIGNED,ARC_VALID,BAYES_00, DKIM_SIGNED,DKIM_VALID,MAILING_LIST_MULTI,RCVD_IN_DNSWL_MED autolearn=ham autolearn_force=no version=4.0.1 Received: from vm01.sourceware.org (vm01.sourceware.org [IPv6:2620:52:6:3111::32]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange x25519 server-signature ECDSA (prime256v1) server-digest SHA256) (No client certificate requested) by simark.ca (Postfix) with ESMTPS id D8AB01E047 for ; Wed, 14 Oct 2026 05:23:26 -0400 (EDT) Received: from vm01.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id DCC6E4BA2E3F for ; Wed, 14 Oct 2026 09:23:24 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org DCC6E4BA2E3F Authentication-Results: sourceware.org; dkim=pass (2048-bit key, unprotected) header.d=ibm.com header.i=@ibm.com header.a=rsa-sha256 header.s=pp1 header.b=VlF8tqX4 Received: from mx0b-001b2d01.pphosted.com (mx0b-001b2d01.pphosted.com [148.163.158.5]) by sourceware.org (Postfix) with ESMTPS id 6D0D64BA2E39 for ; Wed, 14 Oct 2026 09:22:21 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org 6D0D64BA2E39 Authentication-Results: sourceware.org; dmarc=none (p=none dis=none) header.from=linux.ibm.com Authentication-Results: sourceware.org; spf=pass smtp.mailfrom=linux.ibm.com ARC-Filter: OpenARC Filter v1.0.0 sourceware.org 6D0D64BA2E39 Authentication-Results: sourceware.org; arc=none smtp.remote-ip=148.163.158.5 ARC-Seal: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1791969741; cv=none; b=c+bosUdhAe5JGPATxh7SoYcOyA4Vw5HCKKxtB291BZz4gio0eL3wOmGw5TzwZVNvM0ijN45isBUUE6SdAI9R5a3IuoThBw1bfxV1wSCwaEXIXKV10cmq8CVb5YqK9GwLpQVAH98fkpPF6wMe6s6v38zpCHJZPZBfEiVyuKODhT8= ARC-Message-Signature: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1791969741; c=relaxed/simple; bh=lOmapUfSr8L3PrbX70EsiS1xHtR+n6sbWRGy/5HJyPE=; h=DKIM-Signature:From:To:Subject:Date:Message-ID:MIME-Version; b=N7T1RIzaj9K9pH0Vxo6eRrptK6vhSqx2MN7rZGwE1lXBfMfKFlD1fTE/6oa113AqQjZ+2MDZP71MJLXiL1RfrXShSKCS6m1WFbtmUkWG2ggzSPQMmYfe5pAndQDoZm7dWdFojw+tPuUU14qLQXPHg3cTcNfvr9oUNSIO7+WsAbk= ARC-Authentication-Results: i=1; sourceware.org; dkim=pass (2048-bit key, unprotected) header.d=ibm.com header.i=@ibm.com header.a=rsa-sha256 header.s=pp1 header.b=VlF8tqX4 DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 6D0D64BA2E39 Received: from pps.filterd (m0360072.ppops.net [127.0.0.1]) by mx0a-001b2d01.pphosted.com (8.18.1.11/8.18.1.11) with ESMTP id 69DKT5RL1931731; Wed, 14 Oct 2026 09:22:02 GMT DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=ibm.com; h=cc :content-transfer-encoding:date:from:in-reply-to:message-id :mime-version:references:subject:to; s=pp1; bh=c9PLL4h+04MV+sG3C Z7bMvQ9cmzbPsVz1F1FUIyfCq8=; b=VlF8tqX4k0KAMPd9iGPn4eNjUew0tm1mY PbqCkLz8IoNIMpHzDCXtGe+E2CktGzVVo5rUIcxRDZC2Xtiw7VZp2UzRn3xR/DtK JjCFM5AyJoylaeKEv0DSG9bxa7dtvtorlavz0AZ7wi8j7+l/RvonLUdDMwUFdPqU 2q/M6Rah/2xvWEamfiGXVUEkodGvGb3s9fM1IvX7+vZVBamYPcaRHqJHaej9Yy+b LXPzuj3vEjj/rhdAjfxt5kKL2ajhI78b942a3XWGtpI9wSRZ0+uHlDAnfOsxyqBl XBLUd/+hM6qALNLRA6iriEzkpzgzak/ZWEVHY6t2WzKqRbxWMCwVw== Received: from ppma13.dal12v.mail.ibm.com (dd.9e.1632.ip4.static.sl-reverse.com [50.22.158.221]) by mx0a-001b2d01.pphosted.com (PPS) with ESMTPS id 4h7e1way29-1 (version=TLSv1.3 cipher=TLS_AES_256_GCM_SHA384 bits=256 verify=NOT); Wed, 14 Oct 2026 09:22:02 +0000 (GMT) Received: from pps.filterd (ppma13.dal12v.mail.ibm.com [127.0.0.1]) by ppma13.dal12v.mail.ibm.com (8.18.1.11/8.18.1.11) with ESMTP id 69E8oG1c2585786; Wed, 14 Oct 2026 09:22:01 GMT Received: from smtprelay01.fra02v.mail.ibm.com ([9.218.2.227]) by ppma13.dal12v.mail.ibm.com (PPS) with ESMTPS id 4h9wvg1wg2-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT); Wed, 14 Oct 2026 09:22:01 +0000 (GMT) Received: from smtpav05.fra02v.mail.ibm.com (smtpav05.fra02v.mail.ibm.com [10.20.54.104]) by smtprelay01.fra02v.mail.ibm.com (8.14.9/8.14.9/NCO v10.0) with ESMTP id 69E9LsTo45154786 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-GCM-SHA384 bits=256 verify=OK); Wed, 14 Oct 2026 09:21:54 GMT Received: from smtpav05.fra02v.mail.ibm.com (unknown [127.0.0.1]) by IMSVA (Postfix) with ESMTP id B56CE20043; Wed, 14 Oct 2026 09:21:54 +0000 (GMT) Received: from smtpav05.fra02v.mail.ibm.com (unknown [127.0.0.1]) by IMSVA (Postfix) with ESMTP id AE64720040; Wed, 14 Oct 2026 09:21:53 +0000 (GMT) Received: from kubota.pok.stglabs.ibm.com (unknown [9.114.39.181]) by smtpav05.fra02v.mail.ibm.com (Postfix) with ESMTP; Wed, 14 Oct 2026 09:21:53 +0000 (GMT) From: Abhay Kandpal To: gdb-patches@sourceware.org Cc: aburgess@redhat.com, Ulrich.Weigand@de.ibm.com, eliz@gnu.org, cel@linux.ibm.com, abhay.k@ibm.com, Abhay Kandpal Subject: [PATCH v3 1/2] gdbserver: widen the stat fields returned by the vFile packets Date: Wed, 14 Oct 2026 04:21:38 -0500 Message-ID: <20261014092139.399322-2-abhay@linux.ibm.com> X-Mailer: git-send-email 2.52.0 In-Reply-To: <20261014092139.399322-1-abhay@linux.ibm.com> References: <20261014092139.399322-1-abhay@linux.ibm.com> MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-TM-AS-GCONF: 00 X-Proofpoint-Spam-Info: AW1haW4tMjYxMDE0MDAzNiBTYWx0ZWRfX/ndkngAAUjU+ TUSX1nFLuRQqXqcnw8yoYZ22CNmlPbs0kMtI9KtwJESMNBAf2vYqfLnZ19MuUDnMUlUs7Mi21Ku 3AW5o6tEEsaG0z8DfKzaVwCiIFUJieU= X-Proofpoint-Spam-Details-Enc: AW1haW4tMjYxMDE0MDAzNiBTYWx0ZWRfXxENuqe64UPej ZwkcTyAMjsygQxsbrEskv8uUPC0sRVwySUqwiP4D8gqU0a8qWLP7oubpqlex/8JfE5xYm6e4PEp Kt6DPydcpjcUFjNwIHtb1lYhW9nTu/I8T3HhI01H2WcKtnVuwHaJxl7AB8MMJfEonr/L7BViFgM J9vXiqmtAXgTMpzLNXPCI3KOzvpPowjDEaRg0xp+7xvJmZT9igTzlVMuRkIwQmqcQu4FNDvQwgg t3Tj2GF0/UsyWHhM3LQ/McLzBdpY3SbolMYb7xdp2kzcm/izTjxhbNoi5d1sekR57aNSeJCcyz5 s31r8YSCzuQUqkVbc8wfW3A04lJpLquzPBvl1CLOScdlC7r/WRYtB+rP6YmOfnLqZEVX5OqBNpQ 2C6PsNnCFtWqybWGPPuaYUHiRrMk1OsqcyvTANtZA2tNCoge+6F1ucoCsM54irhyrO02it74qWx /QXJCFQrTvwsAOeMxDQ== X-Authority-Analysis: v=2.4 cv=E6pYNqdl c=1 sm=1 tr=0 ts=6acf49ba cx=c_pps a=AfN7/Ok6k8XGzOShvHwTGQ==:117 a=AfN7/Ok6k8XGzOShvHwTGQ==:17 a=660iZSQnnn4A:10 a=VkNPw1HP01LnGYTKEx00:22 a=RnoormkPH1_aCDwRdu11:22 a=RzCfie-kr_QcCd8fBx8p:22 a=CCpqsmhAAAAA:8 a=mDV3o1hIAAAA:8 a=ZJZWeoccTWe8qxORPgAA:9 a=3ZKOabzyN94A:10 a=ul9cdbp4aOFLsgKbc677:22 X-Proofpoint-ORIG-GUID: yhWAFijtBNd_ukx64UGW1CAQjNl8ExBd X-Proofpoint-GUID: yhWAFijtBNd_ukx64UGW1CAQjNl8ExBd X-Proofpoint-Virus-Version: vendor=baseguard engine=ICAP:2.0.293,Aquarius:18.0.1176,Hydra:6.1.134,FMLib:17.12.100.49 definitions=2026-10-13_01,2026-10-09_01,2025-10-01_01 X-Proofpoint-Spam-Details: rule=outbound_notspam policy=outbound score=0 impostorscore=0 phishscore=0 clxscore=1015 bulkscore=0 priorityscore=1501 spamscore=0 adultscore=0 suspectscore=0 malwarescore=0 lowpriorityscore=0 classifier=typeunknown authscore=0 authtc= authcc= route=outbound adjust=0 reason=mlx scancount=1 engine=8.22.0-2610080000 definitions=main-2610140036 X-BeenThere: gdb-patches@sourceware.org X-Mailman-Version: 2.1.30 Precedence: list List-Id: Gdb-patches mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: gdb-patches-bounces~public-inbox=simark.ca@sourceware.org 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 --- 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); } - + +/* 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 #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 */ -- 2.52.0