From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from simark.ca by simark.ca with LMTP id 5QKNIYSCmmrW5CcAWB0awg (envelope-from ) for ; Fri, 04 Sep 2026 04:34:12 -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=poiVsjX/; dkim-atps=neutral Received: by simark.ca (Postfix, from userid 112) id 455AC1E167; Fri, 04 Sep 2026 04:34:12 -0400 (EDT) X-Spam-Checker-Version: SpamAssassin 4.0.1 (2024-03-25) on simark.ca X-Spam-Level: X-Spam-Status: No, score=-3.0 required=5.0 tests=ARC_SIGNED,ARC_VALID,BAYES_00, DKIM_SIGNED,DKIM_VALID,MAILING_LIST_MULTI 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 080AF1E09B for ; Fri, 04 Sep 2026 04:33:49 -0400 (EDT) Received: from vm01.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id 0BC014BB58EF for ; Fri, 4 Sep 2026 08:33:48 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 0BC014BB58EF 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=poiVsjX/ Received: from mx0a-001b2d01.pphosted.com (mx0a-001b2d01.pphosted.com [148.163.156.1]) by sourceware.org (Postfix) with ESMTPS id 23DEC4BB58C8 for ; Fri, 4 Sep 2026 08:33:01 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org 23DEC4BB58C8 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 23DEC4BB58C8 Authentication-Results: sourceware.org; arc=none smtp.remote-ip=148.163.156.1 ARC-Seal: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1788510781; cv=none; b=EBaEg6DVgTCrrnZoYCDLCYxdPXATFrASYdpsDYK8+tnf0vse79CnUDUbeDVaH9dFwSPQdfG5wjEMHmR5hj2MJfLpRwDfO+0EM4rCwclmmOcGl+KFcNzL/zsXS9ws/9zfN9ZiAcmhEEUOn6jgdsZjJmh7HVV7yTeamo0CXdI4eUE= ARC-Message-Signature: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1788510781; c=relaxed/simple; bh=+OEbD3ukiVZNDROL4O7R8esL2B0ehCc4bos12/wNUBw=; h=DKIM-Signature:From:To:Subject:Date:Message-ID:MIME-Version; b=ggZfuwru0gxipGCMj45cnMEFqroym6I6QsSQpBjmIT9q8gQHNIzUzitLNKESkFd0Z/dCAv/QlMPytNifn3ZfKQFqS3/rrO4V079fiiN3qL6d3wBsQLG1inDmXI+AIOb52wCB/u7sQRQbOmb5LJy3lNdz9ezY/ttosQmsjOnPBJw= 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=poiVsjX/ DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 23DEC4BB58C8 Received: from pps.filterd (m0360083.ppops.net [127.0.0.1]) by mx0a-001b2d01.pphosted.com (8.18.1.11/8.18.1.11) with ESMTP id 68464G0T936760; Fri, 4 Sep 2026 08:32:53 GMT DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=ibm.com; h=cc :content-transfer-encoding:date:from:message-id:mime-version :subject:to; s=pp1; bh=ZqE/it6KsY3VilIHcrUhexD75mY2RYciLmPAbxpFw QU=; b=poiVsjX/gKrimZEO6jwLzTwZcoKebKlZzKRC2Cq2Dcbg5vwa+Kyk9f7JL xS+PC24Q6uTxYF5eRCHK4VaGstooXn1Qtk8j9VudjPMI37JCrZCvWsTKs/XF6ik8 a+pfA6j7p4meq2mPY2d0BTqJWFYMXjuY4TYprmZ9a2Ue/ARzgUCBSSaXt7nEiVTd 4O5xjOVxSc1lZlOiJXlrGWjadelDXGiTd6rPsi+u2dKKnQ/lCoHOQHrIn4AHjDFa AoBkWibxZHtx+T88XvGCoylOiz1qqTi1Vkxne1k3oTxy0clDFwFftb//6lpp9fZe Qhhnsmd1XvXrtpHFZsCBXi3mSDEGg== 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 4gbpx61n8e-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT); Fri, 04 Sep 2026 08:32:52 +0000 (GMT) Received: from pps.filterd (ppma13.dal12v.mail.ibm.com [127.0.0.1]) by ppma13.dal12v.mail.ibm.com (8.18.1.7/8.18.1.7) with ESMTP id 6848QIAr017438; Fri, 4 Sep 2026 08:32:51 GMT Received: from smtprelay01.fra02v.mail.ibm.com ([9.218.2.227]) by ppma13.dal12v.mail.ibm.com (PPS) with ESMTPS id 4gcbyguw2s-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT); Fri, 04 Sep 2026 08:32:51 +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 6848Wknl39715222 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-GCM-SHA384 bits=256 verify=OK); Fri, 4 Sep 2026 08:32:47 GMT Received: from smtpav05.fra02v.mail.ibm.com (unknown [127.0.0.1]) by IMSVA (Postfix) with ESMTP id B54BC2004B; Fri, 4 Sep 2026 08:32:46 +0000 (GMT) Received: from smtpav05.fra02v.mail.ibm.com (unknown [127.0.0.1]) by IMSVA (Postfix) with ESMTP id A6F562004E; Fri, 4 Sep 2026 08:32:45 +0000 (GMT) Received: from kubota.pok.stglabs.ibm.com (unknown [9.114.39.181]) by smtpav05.fra02v.mail.ibm.com (Postfix) with ESMTP; Fri, 4 Sep 2026 08:32:45 +0000 (GMT) From: Abhay Kandpal To: gdb-patches@sourceware.org Cc: aburgess@redhat.com, eliz@gnu.org, cel@linux.ibm.com, abhay.k@ibm.com, Abhay Kandpal Subject: [PATCH v2] gdbserver: widen the stat fields returned by the vFile packets Date: Fri, 4 Sep 2026 03:32:40 -0500 Message-ID: <20260904083240.3395228-1-abhay@linux.ibm.com> X-Mailer: git-send-email 2.52.0 MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-TM-AS-GCONF: 00 X-Authority-Analysis: v=2.4 cv=PPc/P/qC c=1 sm=1 tr=0 ts=6a9a8234 cx=c_pps a=AfN7/Ok6k8XGzOShvHwTGQ==:117 a=AfN7/Ok6k8XGzOShvHwTGQ==:17 a=VdqzKS8jKosA:10 a=VkNPw1HP01LnGYTKEx00:22 a=RnoormkPH1_aCDwRdu11:22 a=iQ6ETzBq9ecOQQE5vZCe:22 a=CCpqsmhAAAAA:8 a=mDV3o1hIAAAA:8 a=ZJZWeoccTWe8qxORPgAA:9 a=3ZKOabzyN94A:10 a=ul9cdbp4aOFLsgKbc677:22 X-Proofpoint-GUID: veLzA_yqd0COfj-0xacNgAVsvZnXXS-y X-Proofpoint-ORIG-GUID: veLzA_yqd0COfj-0xacNgAVsvZnXXS-y X-Proofpoint-Spam-Info: AW1haW4tMjYwOTA0MDA3MyBTYWx0ZWRfX7ZUXCliVYIUG 1UWOQ7xKW/CM/cFz6hkdbArNANPiG5tElCHMzPRWfny8zRWSaiZwT+6A8v3RI6PYCL0uQPlHjcm xLecihKOuWStgfPU+pEg/2dBIakOU7k= X-Proofpoint-Spam-Details-Enc: AW1haW4tMjYwOTA0MDA3MyBTYWx0ZWRfX/B2Y1SPdUET7 9IgW21TzPEM/zWqAhQkmNKXKorZeUuZwiKB3P6Uvx7aDmRHkAhoBNPyRkP8m/tVnhLWeQN7yTdC jgF5AgpbuGBxlWH3Zg6H0Z+NBZPe3jwvwUVICHigZHf2m6K2lkPqkB5o6KdQ7+cWElZpZtP943+ UzqgXKayDn6FGj7DZQwebOI7BdaWDpVT5/LEHplU8zLZBQBpiwuAnV2UD1LBPBn+8yvAqnKn20L /0H993MmAn7xMGmLGUw/WNRqaeZpB33GvBOZyCYdz54o7hFZzGGRYgflpHrMGXPSiuAGFtEypxq /AK+dYNQ9p7IZpidoV5vb/bw7Rah+kvOd/TS2w8rsq9PXsV/qH/hTfGZGFlUZnze+uK8dYX8R1x si6L/nRakUQfyhK1QJ58FikLEvHS1W7K6VtScWHOaFivI452BXcW9lwYMM6EU/aCb/UsDfWY5Dp Kku+QuaHioz95VkzAQw== 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-09-04_02,2026-09-03_01,2025-10-01_01 X-Proofpoint-Spam-Details: rule=outbound_notspam policy=outbound score=0 clxscore=1015 phishscore=0 adultscore=0 suspectscore=0 bulkscore=0 spamscore=0 priorityscore=1501 impostorscore=0 malwarescore=0 lowpriorityscore=0 classifier=typeunknown authscore=0 authtc= authcc= route=outbound adjust=0 reason=mlx scancount=1 engine=8.22.0-2606150000 definitions=main-2609040073 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. 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 */ -- 2.52.0