From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from simark.ca by simark.ca with LMTP id kWH+N7/0x2qVkRgAWB0awg (envelope-from ) for ; Thu, 08 Oct 2026 15:53:35 -0400 Authentication-Results: simark.ca; dkim=pass (2048-bit key; unprotected) header.d=sifive.com header.i=@sifive.com header.a=rsa-sha256 header.s=google header.b=iPW+arCO; dkim-atps=neutral Received: by simark.ca (Postfix, from userid 112) id DE1001E051; Thu, 08 Oct 2026 15:53:35 -0400 (EDT) X-Spam-Checker-Version: SpamAssassin 4.0.1 (2024-03-25) on simark.ca X-Spam-Level: X-Spam-Status: No, score=-2.4 required=5.0 tests=ARC_SIGNED,ARC_VALID,BAYES_00, DKIM_SIGNED,DKIM_VALID,DKIM_VALID_AU,MAILING_LIST_MULTI, MIME_QP_LONG_LINE,RCVD_IN_DNSWL_MED,RCVD_IN_VALIDITY_CERTIFIED_BLOCKED, RCVD_IN_VALIDITY_RPBL_BLOCKED,RCVD_IN_VALIDITY_SAFE_BLOCKED autolearn=ham autolearn_force=no version=4.0.1 Received: from vm01.sourceware.org (vm01.sourceware.org [38.145.34.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 071291E04E for ; Thu, 08 Oct 2026 15:53:31 -0400 (EDT) Received: from vm01.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id 894204BA2E0D for ; Thu, 8 Oct 2026 19:53:30 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 894204BA2E0D Authentication-Results: sourceware.org; dkim=pass (2048-bit key, unprotected) header.d=sifive.com header.i=@sifive.com header.a=rsa-sha256 header.s=google header.b=iPW+arCO Received: from mail-dy1-x132c.google.com (mail-dy1-x132c.google.com [IPv6:2607:f8b0:4864:20::132c]) by sourceware.org (Postfix) with ESMTPS id 9E1B74BA540B for ; Thu, 8 Oct 2026 19:52:54 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org 9E1B74BA540B Authentication-Results: sourceware.org; dmarc=pass (p=reject dis=none) header.from=sifive.com Authentication-Results: sourceware.org; spf=pass smtp.mailfrom=sifive.com ARC-Filter: OpenARC Filter v1.0.0 sourceware.org 9E1B74BA540B Authentication-Results: sourceware.org; arc=none smtp.remote-ip=2607:f8b0:4864:20::132c ARC-Seal: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1791489175; cv=none; b=R/4XNxIfXArvFs+5j3TOCvZ1AWD6KLTSqbTdXbMMs91vJEEty8w6y4UfRortWKO3pRUDxNV0IRQMtRp7SeHnY717QGJboZBSip6HkZVGsV6Wc+rJNOn3C1d04rQWp3ftbcLfAXkViEzkgWEZFb0T+clUUOR/+USGuIC465K7Ht8= ARC-Message-Signature: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1791489175; c=relaxed/simple; bh=0N8yc9ff+7dgnR0X1OLbLwlypVyhvBmUhMOgGFqkB70=; h=DKIM-Signature:From:Mime-Version:Subject:Date:Message-Id:To; b=t9hMcv6wH4YThR2f21gcBJzgWV1u49VNbSNGEpJ1oh4i57mSRUtJnXCiACqLuj2yT/HDf1aCnso1fKW/IPaFcNvcMppvHok4CEQ1H9XZyl9vi4aB8EwneLfz4riX/nbyqM7pxdMTFIWnkZTByogjqPcSteEIjDqDChXbxn83eGc= ARC-Authentication-Results: i=1; sourceware.org; dkim=pass (2048-bit key, unprotected) header.d=sifive.com header.i=@sifive.com header.a=rsa-sha256 header.s=google header.b=iPW+arCO DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 9E1B74BA540B Received: by mail-dy1-x132c.google.com with SMTP id 5a478bee46e88-35115b52125so4543328eec.1 for ; Thu, 08 Oct 2026 12:52:54 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=sifive.com; s=google; t=1791489174; x=1792093974; darn=sourceware.org; h=to:in-reply-to:cc:references:message-id:date:subject:mime-version :from:content-transfer-encoding:content-type:from:to:cc:subject:date :message-id:reply-to:content-type; bh=TAEFA5Kxvjve4CVvP8zo1ntso26Ca8eEXG/KtLUR3/I=; b=iPW+arCOzI/GybQ+ih90yl1KTsMOgDsp+xyO0hgx2DIy33NPab8jDmp4P0IPXZMwFp 8qUINGiRyuOUmNRjXy2bmMwquWuFvNUiP1tt9RwKM/bCDR61BPhx62ZbeoCtVq32m2L8 +pJ2flGqRaKYGK0S1+mJfoFsgW7o3pr6ZLuoJh7eba/7CYYsfC2xvYyMh30toRBKXl6J HKI8v19mSRuSkCP6qhv/vq/SQ2eOChOy6g+ZNnbzLa1eRleDpuG8SWk+b027Sp6wD4xI 2xSuX0gMHJq6A/Gvfh1pUSOLrg+2iGdYoep7sIotQFhmSSRdYUCcunKgiBSQ7HfAMeUr dVKw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20260707; t=1791489174; x=1792093974; h=to:in-reply-to:cc:references:message-id:date:subject:mime-version :from:content-transfer-encoding:content-type:x-gm-gg :x-gm-message-state:from:to:cc:subject:date:message-id:reply-to :content-type; bh=TAEFA5Kxvjve4CVvP8zo1ntso26Ca8eEXG/KtLUR3/I=; b=0q2aQIMFoEGx4ySVyiJILTneFFWnwHmzGlSKz7q019cZrcdyd3b5jb7m6GD5qr2q03 X8Yo2EZHZAhup5MTyWeUddW6/Nv9p3Qtmx4pq3nQpyCEbki7fZwlsj0J7ggxZryzi7KL 6d+vW2cDmwoCi/Ibb8DzPE43PW3oTJx2G23+eSP9FhaOoSLUAPW1rYsK0xQF7lErXO6U wodWaGtUlDC3bu9PKs+2Qa7LqyZAm+WWRC7m3ABf5+Zc+NuVmmWKreaq4JmLGP5kzr1j 29ZfI9TUAai5Kx8T8EYZIwrzIThlQnfIx1TZxaGpdeu+/VJSiJFX94AmbtJ3QbPiMfsr 8FXg== X-Forwarded-Encrypted: i=1; AKwUvByfg3+OIBCJpSBacEwMtZ3zLrvZH/Ve9Vyg6jFjF4+P2L43dJScRIJGyEYyrIO24gBacNV1P5sq+ZGHQw==@sourceware.org X-Gm-Message-State: AFq9FYLdmk2IpTt9AVMBqzKfYIHKwGdm6ZthWyMwq0y7DnI3QZKiY6YD MOwdtk3+rwdIFwOafVGayCasdUYeqBQcnmqkCJ0Vkdyuad0UMHFXfjyV8iKkLUJAmao= X-Gm-Gg: AYBFou1FyMW7lKwe4GWmVGSf4TcpA89b5DuM2VIwj4vxXl4bU2R7F3lRUOKTNhux3qF /gZkrQoA1x8tKu2peXF5MmF3NpUU4N648hntDsTpM8Zv4h6TNrSrOuqoUXTJknrdthjow1vGzWc oVbgNoe2yvLsqj/S7NBy5ePAVQQODQcgwWKDnmytB/XF72WGhJOIMDIQqerW699Q2SN8lHTbaJC eAFX1Ti6USq4pvO4F2LvCtlVT+Gn2XAolKbhdo9D8O4UJmzrjTaxLYnkTc6fBC9pOXkoVXYLmyw vY8rX/illL5o7Ty+eV1bBEnzoAbg/6bwU0vuhSA2TVfBsA6F3kdgV5ia3B7qiBaxt7nap+S7f0I zbdXROabCAkZzgW4QtZ6bLb1PWAzho5z4ASkVhLFXNj2G0oyZ9cBdCDwhYBdEEr/UI523JxKIJG lYaKE3E5Ai3kh67znkDpQvUHWYO0vMPygovnUC3EXFxHSwZNN+pbsaiGJOJlNYikyx+1EG9EnDH A27akssiWO7TBlPHuZXfc0zxnGqYmljsRVpzSha X-Received: by 2002:a05:7300:fd12:b0:351:8cde:a29a with SMTP id 5a478bee46e88-3518cdeb06fmr4149753eec.41.1791489172895; Thu, 08 Oct 2026 12:52:52 -0700 (PDT) Received: from smtpclient.apple ([219.69.235.123]) by smtp.gmail.com with ESMTPSA id 5a478bee46e88-3537cab27d5sm232514eec.17.2026.10.08.12.52.51 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 08 Oct 2026 12:52:52 -0700 (PDT) Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: quoted-printable From: Jerry Zhang Jian Mime-Version: 1.0 (1.0) Subject: Re: [PATCH v2 1/3] RISC-V Vector Extension Support Date: Fri, 9 Oct 2026 03:52:39 +0800 Message-Id: References: <87tsmwt1tb.fsf@redhat.com> Cc: Radkin Kirill , gdb-patches@sourceware.org, Bergner Peter , Matyukevich Sergey , Schuchardt Heinrich , Palmer Dabbelt In-Reply-To: <87tsmwt1tb.fsf@redhat.com> To: Burgess Andrew X-Mailer: iPhone Mail (24A446) 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 Hi Andrew I=E2=80=99ll also use our RISCV server to test it this weekend. BRs Jerry > Andrew Burgess =E6=96=BC 2026=E5=B9=B410=E6=9C=889=E6= =97=A5 03:44 =E5=AF=AB=E9=81=93=EF=BC=9A >=20 > =EF=BB=BFKirill Radkin writes: >=20 >> This patch adds support for the RISC-V Vector Extension (RVV) and the RIS= C-V >> Vector ABI to GDB, for both gdb and gdbserver (so, it's available for cro= ss and >> native debugging). It is now possible to inspect and modify vector regist= ers >> directly. Furthermore, GDB supports evaluating variables with RISC-V vect= or >> types (such as vint32m4_t) and calling functions that take vector argumen= ts >> using the print and call GDB commands. Patch also includes tests targetin= g RVV >> support, tested on targets with different vlen (64, 128, 1024). Implement= ation >> is tested on system QEMU (Linux) and on OpenOCD + spike configuration. >=20 > Hi, >=20 > Thanks for working on this. I took a first pass through and pointed out > some minor styling nits. I intend to setup QEMU (or try to, it's been a > while) to give this a real build and test, hopefully next week. >=20 > If someone else wants to review this properly before then, that's fine > with me, but otherwise, I do intend to take a real look at this soon. >=20 >> --- >> gdb/arch/riscv.c | 9 +- >> gdb/arch/riscv.h | 18 +- >> gdb/features/riscv/rvv.c | 113 +++++ >> gdb/gdbtypes.c | 41 ++ >> gdb/nat/riscv-linux-ptrace.h | 31 ++ >> gdb/nat/riscv-linux-tdesc.c | 35 ++ >> gdb/riscv-linux-nat.c | 164 +++++++ >> gdb/riscv-regs.h | 79 ++++ >> gdb/riscv-tdep.c | 876 ++++++++++++++++++++++++++++++++--- >> gdb/riscv-tdep.h | 63 +-- >> gdbserver/linux-riscv-low.cc | 129 ++++-- >> gdbsupport/common-utils.h | 22 + >> 12 files changed, 1422 insertions(+), 158 deletions(-) >> create mode 100644 gdb/features/riscv/rvv.c >> create mode 100644 gdb/nat/riscv-linux-ptrace.h >> create mode 100644 gdb/riscv-regs.h >>=20 >> diff --git a/gdb/arch/riscv.c b/gdb/arch/riscv.c >> index c0e6c6aec63..96a68bf1654 100644 >> --- a/gdb/arch/riscv.c >> +++ b/gdb/arch/riscv.c >> @@ -22,6 +22,7 @@ >> #include "../features/riscv/64bit-cpu.c" >> #include "../features/riscv/32bit-fpu.c" >> #include "../features/riscv/64bit-fpu.c" >> +#include "../features/riscv/rvv.c" >> #include "../features/riscv/rv32e-xregs.c" >>=20 >> #ifndef GDBSERVER >> @@ -82,11 +83,9 @@ riscv_create_target_description (const struct riscv_gd= barch_features features) >> else if (features.flen =3D=3D 8) >> regnum =3D create_feature_riscv_64bit_fpu (tdesc.get (), regnum); >>=20 >> - /* Currently GDB only supports vector features coming from remote >> - targets. We don't support creating vector features on native targe= ts >> - (yet). */ >> - if (features.vlen !=3D 0) >> - error (_("unable to create vector feature")); >> + if (features.vlenb !=3D 0) >> + regnum =3D create_feature_riscv_rvv (tdesc.get (), features.vlenb, >> + features.xlen); >>=20 >> return tdesc; >> } >> diff --git a/gdb/arch/riscv.h b/gdb/arch/riscv.h >> index 1443bc20a7d..0261d4d0f9e 100644 >> --- a/gdb/arch/riscv.h >> +++ b/gdb/arch/riscv.h >> @@ -51,7 +51,7 @@ struct riscv_gdbarch_features >> target should be 16 and 4 for an embedded subset compliant target (w= ith >> 'Zve32*' extension), but GDB doesn't currently mind, and will accept= any >> vector size. */ >> - int vlen =3D 0; >> + int vlenb =3D 0; >>=20 >> /* When true this target is RV32E. */ >> bool embedded =3D false; >> @@ -68,9 +68,8 @@ struct riscv_gdbarch_features >> /* Equality operator. */ >> bool operator=3D=3D (const struct riscv_gdbarch_features &rhs) const >> { >> - return (xlen =3D=3D rhs.xlen && flen =3D=3D rhs.flen >> - && embedded =3D=3D rhs.embedded && vlen =3D=3D rhs.vlen >> - && has_fflags_reg =3D=3D rhs.has_fflags_reg >> + return (xlen =3D=3D rhs.xlen && flen =3D=3D rhs.flen && embedded =3D= =3D rhs.embedded >> + && vlenb =3D=3D rhs.vlenb && has_fflags_reg =3D=3D rhs.has_fflag= s_reg >> && has_frm_reg =3D=3D rhs.has_frm_reg >> && has_fcsr_reg =3D=3D rhs.has_fcsr_reg); >> } >> @@ -84,13 +83,10 @@ struct riscv_gdbarch_features >> /* Used by std::unordered_map to hash feature sets. */ >> std::size_t hash () const noexcept >> { >> - std::size_t val =3D ((embedded ? 1 : 0) << 10 >> - | (has_fflags_reg ? 1 : 0) << 11 >> - | (has_frm_reg ? 1 : 0) << 12 >> - | (has_fcsr_reg ? 1 : 0) << 13 >> - | (xlen & 0x1f) << 5 >> - | (flen & 0x1f) << 0 >> - | (vlen & 0x3fff) << 14); >> + std::size_t val >> + =3D ((embedded ? 1 : 0) << 10 | (has_fflags_reg ? 1 : 0) << 11 >> + | (has_frm_reg ? 1 : 0) << 12 | (has_fcsr_reg ? 1 : 0) << 13 >> + | (xlen & 0x1f) << 5 | (flen & 0x1f) << 0 | (vlenb & 0x3fff) << 14)= ; >> return val; >> } >> }; >> diff --git a/gdb/features/riscv/rvv.c b/gdb/features/riscv/rvv.c >> new file mode 100644 >> index 00000000000..060cb5a44f2 >> --- /dev/null >> +++ b/gdb/features/riscv/rvv.c >> @@ -0,0 +1,113 @@ >> +/* Copyright (C) 2026 Free Software Foundation, Inc. >> + >> + This file is part of GDB. >> + >> + This program is free software; you can redistribute it and/or modify >> + it under the terms of the GNU General Public License as published by >> + the Free Software Foundation; either version 3 of the License, or >> + (at your option) any later version. >> + >> + This program is distributed in the hope that it will be useful, >> + but WITHOUT ANY WARRANTY; without even the implied warranty of >> + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the >> + GNU General Public License for more details. >> + >> + You should have received a copy of the GNU General Public License >> + along with this program. If not, see .= */ >> + >> +#include "gdbsupport/gdb_assert.h" >> +#include "gdbsupport/tdesc.h" >> +#include "gdb/riscv-regs.h" >> +#include >> + >> +/* This file is NOT auto generated from xml. >> + 'create_feature_riscv_rvv' creates a RISCV Vector Extension feature. >> + 'vlenb' is a vector register size in bytes */ >> + >> +struct vector_field_type_info >> +{ >> + const char *element_type_name; >> + const char *vector_type_name; >> + int element_count; >> +}; >> + >> +static void >> +create_vector_register_type (tdesc_feature *feature, >> + std::vector &types_info, >> + const char *type_name) >> +{ >> + tdesc_type *element_type; >> + >> + for (auto &&type_info : types_info) >> + { >> + if (type_info.element_count =3D=3D -1) >> + continue; >> + element_type =3D tdesc_named_type (feature, type_info.element_type= _name); >> + tdesc_create_vector (feature, type_info.vector_type_name, element_= type, >> + type_info.element_count); >> + } >> + >> + tdesc_type_with_fields *type_with_fields =3D tdesc_create_union (featu= re, >> + type_name); >> + >> + for (auto &&type_info : types_info) >> + { >> + if (type_info.element_count =3D=3D -1) >> + continue; >> + element_type =3D tdesc_named_type (feature, type_info.vector_type_= name); >> + tdesc_add_field (type_with_fields, type_info.vector_type_name, >> + element_type); >> + } >> +} >> + >> +static int >> +create_feature_riscv_rvv (target_desc *result, int vlenb, int xlen) >> +{ >> + gdb_assert (result); >> + gdb_assert (xlen =3D=3D 4 || xlen =3D=3D 8); >> + gdb_assert (vlenb >=3D 4 && ((vlenb & (vlenb - 1)) =3D=3D 0)); >> + >> + int v_bitsize =3D 8 * vlenb; >> + int x_bitsize =3D 8 * xlen; >> + >> + tdesc_feature *csr_feature =3D tdesc_create_feature (result, >> + "org.gnu.gdb.riscv.csr"); >> + tdesc_create_reg (csr_feature, "vstart", RISCV_CSR_VSTART_REGNUM, 1, N= ULL, >> + x_bitsize, "int"); >=20 > GDB now uses 'nullptr' instead of 'NULL', you'll need to change these > throughout this patch. >=20 >> + tdesc_create_reg (csr_feature, "vcsr", RISCV_CSR_VCSR_REGNUM, 1, NULL,= >> + x_bitsize, "int"); >> + tdesc_create_reg (csr_feature, "vl", RISCV_CSR_VL_REGNUM, 1, NULL, x_b= itsize, >> + "int"); >> + tdesc_create_reg (csr_feature, "vtype", RISCV_CSR_VTYPE_REGNUM, 1, NUL= L, >> + x_bitsize, "int"); >> + tdesc_create_reg (csr_feature, "vlenb", RISCV_CSR_VLENB_REGNUM, 1, NUL= L, >> + x_bitsize, "int"); >> + >> + tdesc_feature *vector_feature >> + =3D tdesc_create_feature (result, "org.gnu.gdb.riscv.vector"); >> + >> + std::vector elements_types_info >> + =3D { { "int8", "i8", vlenb }, >> + { "int16", "i16", vlenb / 2 }, >> + { "int32", "i32", vlenb / 4 }, >> + { "int64", "i64", (vlenb >=3D 8) ? vlenb / 8 : -1 }, >> + { "ieee_half", "half", vlenb / 2 }, >> + { "ieee_single", "f32", vlenb / 4 }, >> + { "ieee_double", "f64", (vlenb >=3D 8) ? vlenb / 8 : -1 } }; >> + >> + create_vector_register_type (vector_feature, elements_types_info, "rvv= "); >> + >> + int regnum =3D RISCV_V0_REGNUM; >> + >> + constexpr const char *vec_reg_names[] >> + =3D { "v0", "v1", "v2", "v3", "v4", "v5", "v6", "v7", >> + "v8", "v9", "v10", "v11", "v12", "v13", "v14", "v15", >> + "v16", "v17", "v18", "v19", "v20", "v21", "v22", "v23", >> + "v24", "v25", "v26", "v27", "v28", "v29", "v30", "v31" }; >> + >> + for (int i =3D 0; i < 32; ++i) >> + tdesc_create_reg (vector_feature, vec_reg_names[i], regnum++, 1, NUL= L, >> + v_bitsize, "rvv"); >> + >> + return regnum; >> +} >> diff --git a/gdb/gdbtypes.c b/gdb/gdbtypes.c >> index 4b6c01910f4..34581d65bb4 100644 >> --- a/gdb/gdbtypes.c >> +++ b/gdb/gdbtypes.c >> @@ -1977,6 +1977,21 @@ is_dynamic_type_internal_1 (struct type *type, >> } >> } >> break; >> + >> + case TYPE_CODE_FUNC: >> + { >> + /* If the type of value returned by function is dynamic, we should m= ark >> + func as dynamic to later resolve this dynamic type */ >=20 > Comment missing full stop. >=20 >> + if (type->target_type () >> + && is_dynamic_type_internal_1 (type->target_type (), false)) >> + return true; >> + >> + /* Same for function arguments */ >=20 > Comment missing full stop. >=20 >> + for (int i =3D 0; i < type->num_fields (); ++i) >> + if (is_dynamic_type_internal_1 (type->field (i).type (), false)) >> + return true; >> + } >> + break; >> } >>=20 >> return false; >> @@ -2742,6 +2757,25 @@ resolve_dynamic_struct (struct type *type, >> return resolved_type; >> } >>=20 >> +/* Resolve dynamic function's arguments/returned value types */ >=20 > Comment missing full stop. Plus we usually leave a blank line between > header comments and the function definition. >=20 >> +static struct type * >> +resolve_dynamic_func (struct type *type, const property_addr_info *addr_= stack, >> + const frame_info_ptr &frame, bool top_level) >> +{ >> + gdb_assert (type->code () =3D=3D TYPE_CODE_FUNC); >> + >> + struct type *resolved_type =3D copy_type (type); >> + >> + resolved_type->set_target_type (resolve_dynamic_type_internal ( >> + type->target_type (), addr_stack, frame, top_level)); >> + >> + for (int i =3D 0; i < resolved_type->num_fields (); i++) >> + resolved_type->field (i).set_type (resolve_dynamic_type_internal ( >> + resolved_type->field (i).type (), addr_stack, frame, top_level)); >> + >> + return resolved_type; >> +} >> + >> /* Worker for resolved_dynamic_type. */ >>=20 >> static struct type * >> @@ -2840,6 +2874,13 @@ resolve_dynamic_type_internal (struct type *type, >> case TYPE_CODE_STRUCT: >> resolved_type =3D resolve_dynamic_struct (type, addr_stack, frame); >> break; >> + >> + case TYPE_CODE_FUNC: >> + /* If func was marked as dynamic, that means that it have dynamic >> + arguments or returned value*/ >=20 > Comment missing full stop. >=20 >> + resolved_type =3D resolve_dynamic_func (type, addr_stack, frame, >> + top_level); >> + break; >> } >> } >>=20 >> diff --git a/gdb/nat/riscv-linux-ptrace.h b/gdb/nat/riscv-linux-ptrace.h >> new file mode 100644 >> index 00000000000..f021b263844 >> --- /dev/null >> +++ b/gdb/nat/riscv-linux-ptrace.h >> @@ -0,0 +1,31 @@ >> +/* Copyright (C) 2026 Free Software Foundation, Inc. >> + >> + This file is part of GDB. >> + >> + This program is free software; you can redistribute it and/or modify >> + it under the terms of the GNU General Public License as published by >> + the Free Software Foundation; either version 3 of the License, or >> + (at your option) any later version. >> + >> + This program is distributed in the hope that it will be useful, >> + but WITHOUT ANY WARRANTY; without even the implied warranty of >> + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the >> + GNU General Public License for more details. >> + >> + You should have received a copy of the GNU General Public License >> + along with this program. If not, see .= */ >> + >> +#ifndef NAT_RISCV_LINUX_HW_PTRACE_H >> +#define NAT_RISCV_LINUX_HW_PTRACE_H >> + >> +struct __riscv_v_regset_state >> +{ >> + unsigned long vstart; >> + unsigned long vl; >> + unsigned long vtype; >> + unsigned long vcsr; >> + unsigned long vlenb; >> + char vreg[]; >> +}; >> + >> +#endif // NAT_RISCV_LINUX_HW_PTRACE_H >=20 > GDB doesn't use '//' style comments. There are a number of these in > this patch and they all need changing to /* ... */ style comments. >=20 >> diff --git a/gdb/nat/riscv-linux-tdesc.c b/gdb/nat/riscv-linux-tdesc.c >> index 1cb3129ba6d..a3e0fe383bb 100644 >> --- a/gdb/nat/riscv-linux-tdesc.c >> +++ b/gdb/nat/riscv-linux-tdesc.c >> @@ -30,6 +30,27 @@ >> # define NFPREG 33 >> #endif >>=20 >> +/* RISC-V Hardware Probing Syscall Number. */ >> +#ifndef NR_riscv_hwprobe >> +#ifndef NR_arch_specific_syscall >> +#define NR_arch_specific_syscall 244 >> +#endif >> +#define NR_riscv_hwprobe (NR_arch_specific_syscall + 14) >> +#endif >> + >> +#ifndef RISCV_HWPROBE_KEY_IMA_EXT_0 >> +/* A bitmask containing the supported extensions. */ >> +#define RISCV_HWPROBE_KEY_IMA_EXT_0 4 >> +/* Bit that indicate RISC-V Vector extension support in Linux. */ >> +#define RISCV_HWPROBE_EXT_ZVE32X (1ULL << 37) >> +#endif >> + >> +struct riscv_hwprobe >> +{ >> + int64_t key; >> + uint64_t value; >> +}; >> + >> /* See nat/riscv-linux-tdesc.h. */ >>=20 >> struct riscv_gdbarch_features >> @@ -78,5 +99,19 @@ riscv_linux_read_features (int tid) >> break; >> } >>=20 >> + features.vlenb =3D 0; >> + >> + static struct riscv_hwprobe query[] =3D { { RISCV_HWPROBE_KEY_IMA_EXT_= 0, 0 } }; >=20 > Is there a benefit to having this be static? Isn't the syscall and the > read of the result done on every call to this function? >=20 >> + >> + /* All possible vector extensions depends on Zve32x, and it's availabi= lity is >> + a minimum requirement. */ >> + if ((syscall (NR_riscv_hwprobe, query, 1, 0, NULL, 0) =3D=3D 0) >> + && (query[0].value & RISCV_HWPROBE_EXT_ZVE32X)) >> + { >> + int reg =3D 0; >> + asm volatile ("csrr %[vlenb], vlenb" : [vlenb] "=3Dr"(reg)); >=20 > Space missing before '(reg)'. >=20 >> + features.vlenb =3D reg; >> + } >> + >> return features; >> } >> diff --git a/gdb/riscv-linux-nat.c b/gdb/riscv-linux-nat.c >> index e1e81ad50c4..aecb777b7ce 100644 >> --- a/gdb/riscv-linux-nat.c >> +++ b/gdb/riscv-linux-nat.c >> @@ -24,6 +24,7 @@ >>=20 >> #include "elf/common.h" >>=20 >> +#include "nat/riscv-linux-ptrace.h" >> #include "nat/riscv-linux-tdesc.h" >>=20 >> #include >> @@ -132,6 +133,64 @@ supply_fpregset (struct regcache *regcache, const pr= fpregset_t *fpregs) >> supply_fpregset_regnum (regcache, fpregs, -1); >> } >>=20 >> +static void >> +supply_vecregset_regnum (regcache *regcache, >> + const __riscv_v_regset_state *vecregs, int regnum) >> +{ >> + gdb_assert (vecregs->vlenb > 0); >> + if ((regnum >=3D RISCV_V0_REGNUM && regnum <=3D RISCV_V31_REGNUM)) >> + { >> + regcache->raw_supply (regnum, >> + vecregs->vreg >> + + vecregs->vlenb * (regnum - RISCV_V0_REGNUM)); >> + return; >> + } >> + >> + if (regnum =3D=3D RISCV_CSR_VSTART_REGNUM) >> + { >> + regcache->raw_supply (regnum, &vecregs->vstart); >> + return; >> + } >> + >> + if (regnum =3D=3D RISCV_CSR_VCSR_REGNUM) >> + { >> + regcache->raw_supply (regnum, &vecregs->vcsr); >> + return; >> + } >> + >> + if (regnum =3D=3D RISCV_CSR_VL_REGNUM) >> + { >> + regcache->raw_supply (regnum, &vecregs->vl); >> + return; >> + } >> + >> + if (regnum =3D=3D RISCV_CSR_VTYPE_REGNUM) >> + { >> + regcache->raw_supply (regnum, &vecregs->vtype); >> + return; >> + } >> + >> + if (regnum =3D=3D RISCV_CSR_VLENB_REGNUM) >> + { >> + regcache->raw_supply (regnum, &vecregs->vlenb); >> + return; >> + } >> + >> + if (regnum =3D=3D -1) >> + { >> + regcache->raw_supply (RISCV_CSR_VSTART_REGNUM, &vecregs->vstart); >> + regcache->raw_supply (RISCV_CSR_VCSR_REGNUM, &vecregs->vcsr); >> + regcache->raw_supply (RISCV_CSR_VL_REGNUM, &vecregs->vl); >> + regcache->raw_supply (RISCV_CSR_VTYPE_REGNUM, &vecregs->vtype); >> + regcache->raw_supply (RISCV_CSR_VLENB_REGNUM, &vecregs->vlenb); >> + >> + for (int i =3D RISCV_V0_REGNUM; i <=3D RISCV_V31_REGNUM; i++) >> + regcache->raw_supply (i, vecregs->vreg >> + + vecregs->vlenb * (i - RISCV_V0_REGNUM)); >> + return; >> + } >> +} >> + >> /* Copy general purpose register REGNUM (or all gp regs if REGNUM =3D=3D -= 1) >> from REGCACHE into regset GREGS. */ >>=20 >> @@ -195,6 +254,64 @@ fill_fpregset (const struct regcache *regcache, prfp= regset_t *fpregs, >> } >> } >>=20 >> +static void >> +fill_vecregset_regnum (regcache *regcache, __riscv_v_regset_state *vecre= gs, >> + int regnum) >> +{ >> + if ((regnum >=3D RISCV_V0_REGNUM && regnum <=3D RISCV_V31_REGNUM)) >> + { >> + regcache->raw_collect (regnum, >> + vecregs->vreg >> + + vecregs->vlenb * (regnum - RISCV_V0_REGNUM)); >> + return; >> + } >> + >> + if (regnum =3D=3D RISCV_CSR_VSTART_REGNUM) >> + { >> + regcache->raw_collect (regnum, &vecregs->vstart); >> + return; >> + } >> + >> + if (regnum =3D=3D RISCV_CSR_VCSR_REGNUM) >> + { >> + regcache->raw_collect (regnum, &vecregs->vcsr); >> + return; >> + } >> + >> + if (regnum =3D=3D RISCV_CSR_VL_REGNUM) >> + { >> + regcache->raw_collect (regnum, &vecregs->vl); >> + return; >> + } >> + >> + if (regnum =3D=3D RISCV_CSR_VTYPE_REGNUM) >> + { >> + regcache->raw_collect (regnum, &vecregs->vtype); >> + return; >> + } >> + >> + if (regnum =3D=3D RISCV_CSR_VLENB_REGNUM) >> + { >> + regcache->raw_collect (regnum, &vecregs->vlenb); >> + return; >> + } >> + >> + if (regnum =3D=3D -1) >> + { >> + regcache->raw_collect (RISCV_CSR_VSTART_REGNUM, &vecregs->vstart);= >> + regcache->raw_collect (RISCV_CSR_VCSR_REGNUM, &vecregs->vcsr); >> + regcache->raw_collect (RISCV_CSR_VL_REGNUM, &vecregs->vl); >> + regcache->raw_collect (RISCV_CSR_VTYPE_REGNUM, &vecregs->vtype); >> + regcache->raw_collect (RISCV_CSR_VLENB_REGNUM, &vecregs->vlenb); >> + >> + for (int i =3D RISCV_V0_REGNUM; i <=3D RISCV_V31_REGNUM; i++) >> + regcache->raw_collect (i, vecregs->vreg >> + + vecregs->vlenb * (i - RISCV_V0_REGNUM)); >> + >> + return; >> + } >> +} >> + >> /* Return a target description for the current target. */ >>=20 >> const struct target_desc * >> @@ -261,6 +378,29 @@ riscv_linux_nat_target::fetch_registers (struct regc= ache *regcache, int regnum) >> regcache->raw_supply_zeroed (RISCV_CSR_MISA_REGNUM); >> } >>=20 >> + if (riscv_is_vpr_or_vcsr (regnum) || (regnum =3D=3D -1)) >> + { >> + int vecreg_size =3D register_size (regcache->arch (), RISCV_V0_REG= NUM); >> + std::vector vregs_buff (sizeof (__riscv_v_regset_state) >> + + vecreg_size * 32); >> + >> + __riscv_v_regset_state *vregs_state >> + =3D (__riscv_v_regset_state *) vregs_buff.data (); >> + >> + iovec iov; >> + iov.iov_base =3D vregs_state; >> + iov.iov_len =3D sizeof (struct __riscv_v_regset_state) + 32 * vecr= eg_size; >> + >> + if (ptrace (PTRACE_GETREGSET, tid, NT_RISCV_VECTOR, >> + (PTRACE_TYPE_ARG3) &iov) >> + =3D=3D 0 >> + && vregs_state->vlenb > 0) >> + { >> + gdb_assert (vregs_state->vlenb =3D=3D vecreg_size); >> + supply_vecregset_regnum (regcache, vregs_state, regnum); >> + } >> + } >> + >> /* Access to other CSRs has potential security issues, don't support th= em for >> now. */ >> } >> @@ -323,6 +463,30 @@ riscv_linux_nat_target::store_registers (struct regc= ache *regcache, int regnum) >> } >> } >>=20 >> + if (riscv_is_vpr_or_vcsr (regnum) || (regnum =3D=3D -1)) >> + { >> + int vecreg_size =3D register_size (regcache->arch (), RISCV_V0_REG= NUM); >> + std::vector vregs_buff (sizeof (__riscv_v_regset_state) >> + + vecreg_size * 32); >> + >> + __riscv_v_regset_state *vregs_state >> + =3D (__riscv_v_regset_state *) vregs_buff.data (); >> + >> + iovec iov; >> + iov.iov_base =3D vregs_state; >> + iov.iov_len =3D sizeof (struct __riscv_v_regset_state) + 32 * vecr= eg_size; >> + >> + if (ptrace (PTRACE_GETREGSET, tid, NT_RISCV_VECTOR, >> + (PTRACE_TYPE_ARG3) &iov) >> + =3D=3D 0) >> + { >> + fill_vecregset_regnum (regcache, vregs_state, regnum); >> + >> + ptrace (PTRACE_SETREGSET, tid, NT_RISCV_VECTOR, >> + (PTRACE_TYPE_ARG3) &iov); >> + } >> + } >> + >> /* Access to CSRs has potential security issues, don't support them for= >> now. */ >> } >> diff --git a/gdb/riscv-regs.h b/gdb/riscv-regs.h >> new file mode 100644 >> index 00000000000..76810d3ef4b >> --- /dev/null >> +++ b/gdb/riscv-regs.h >> @@ -0,0 +1,79 @@ >> +/* Target-dependent header for the RISC-V architecture, for GDB, the >> + GNU Debugger. >> + >> + Copyright (C) 2026 Free Software Foundation, Inc. >> + >> + This file is part of GDB. >> + >> + This program is free software; you can redistribute it and/or modify >> + it under the terms of the GNU General Public License as published by >> + the Free Software Foundation; either version 3 of the License, or >> + (at your option) any later version. >> + >> + This program is distributed in the hope that it will be useful, >> + but WITHOUT ANY WARRANTY; without even the implied warranty of >> + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the >> + GNU General Public License for more details. >> + >> + You should have received a copy of the GNU General Public License >> + along with this program. If not, see .= */ >> + >> +#ifndef GDB_RISCV_REGS_H >> +#define GDB_RISCV_REGS_H >> + >> +/* RiscV register numbers. */ >> +enum >> +{ >> + RISCV_ZERO_REGNUM =3D 0, /* Read-only register, always 0. */ >> + RISCV_RA_REGNUM =3D 1, /* Return Address. */ >> + RISCV_SP_REGNUM =3D 2, /* Stack Pointer. */ >> + RISCV_GP_REGNUM =3D 3, /* Global Pointer. */ >> + RISCV_TP_REGNUM =3D 4, /* Thread Pointer. */ >> + RISCV_FP_REGNUM =3D 8, /* Frame Pointer. */ >> + RISCV_A0_REGNUM =3D 10, /* First argument. */ >> + RISCV_A1_REGNUM =3D 11, /* Second argument. */ >> + RISCV_A2_REGNUM =3D 12, /* Third argument. */ >> + RISCV_A3_REGNUM =3D 13, /* Forth argument. */ >> + RISCV_A4_REGNUM =3D 14, /* Fifth argument. */ >> + RISCV_A5_REGNUM =3D 15, /* Sixth argument. */ >> + RISCV_A7_REGNUM =3D 17, /* Register to pass syscall number. */ >> + RISCV_PC_REGNUM =3D 32, /* Program Counter. */ >> + >> + RISCV_NUM_INTEGER_REGS =3D 32, >> + >> + RISCV_FIRST_FP_REGNUM =3D 33, /* First Floating Point Register */ >> + RISCV_FA0_REGNUM =3D 43, >> + RISCV_FA1_REGNUM =3D RISCV_FA0_REGNUM + 1, >> + RISCV_LAST_FP_REGNUM =3D 64, /* Last Floating Point Register */ >> + >> + RISCV_FIRST_CSR_REGNUM =3D 65, /* First CSR */ >> +#define DECLARE_CSR(name, num, class, define_version, abort_version) \ >> + RISCV_##num##_REGNUM =3D RISCV_FIRST_CSR_REGNUM + num, >> +#include "opcode/riscv-opc.h" >> +#undef DECLARE_CSR >> + RISCV_LAST_CSR_REGNUM =3D 4160, >> + RISCV_CSR_LEGACY_MISA_REGNUM =3D 0xf10 + RISCV_FIRST_CSR_REGNUM, >> + >> + RISCV_PRIV_REGNUM =3D 4161, >> + >> + RISCV_V0_REGNUM, >> + >> + RISCV_V31_REGNUM =3D RISCV_V0_REGNUM + 31, >> + >> + RISCV_LAST_REGNUM =3D RISCV_V31_REGNUM >> +}; >> + >> +/* RiscV DWARF register numbers. */ >> +enum >> +{ >> + RISCV_DWARF_REGNUM_X0 =3D 0, >> + RISCV_DWARF_REGNUM_X31 =3D 31, >> + RISCV_DWARF_REGNUM_F0 =3D 32, >> + RISCV_DWARF_REGNUM_F31 =3D 63, >> + RISCV_DWARF_REGNUM_V0 =3D 96, >> + RISCV_DWARF_REGNUM_V31 =3D 127, >> + RISCV_DWARF_FIRST_CSR =3D 4096, >> + RISCV_DWARF_LAST_CSR =3D 8191, >> +}; >> + >> +#endif /* GDB_RISCV_REGS_H */ >> diff --git a/gdb/riscv-tdep.c b/gdb/riscv-tdep.c >> index 100a44cddf3..12bc51beb38 100644 >> --- a/gdb/riscv-tdep.c >> +++ b/gdb/riscv-tdep.c >> @@ -57,6 +57,12 @@ >> #include "record-full.h" >> #include "riscv-ravenscar-thread.h" >>=20 >> +#include >> +#include >> +#include >> +#include >> +#include >> +#include >> #include >>=20 >> /* The stack must be 16-byte aligned. */ >> @@ -660,10 +666,16 @@ struct riscv_vector_feature : public riscv_register= _feature >> RISCV_V0_REGNUM + 31. */ >> const char *register_name (int regnum) const >> { >> - gdb_assert (regnum >=3D RISCV_V0_REGNUM >> - && regnum <=3D RISCV_V0_REGNUM + 31); >> - regnum -=3D RISCV_V0_REGNUM; >> - return m_registers[regnum].names[0]; >> + gdb_assert (regnum >=3D RISCV_V0_REGNUM && regnum <=3D RISCV_V0_REGN= UM + 31); >> + >> + const auto reg_info_it =3D std::find_if (m_registers.begin (), >> + m_registers.end (), >> + [regnum] (const auto ®_info) { >> + return reg_info.regnum =3D=3D regnum; >> + }); >> + if (reg_info_it =3D=3D m_registers.end ()) >> + gdb_assert_not_reached ("Incorrect vector register number %d", reg= num); >> + return reg_info_it->names.front (); >> } >>=20 >> /* Check this feature within TDESC, record the registers from this >> @@ -679,7 +691,7 @@ struct riscv_vector_feature : public riscv_register_f= eature >> feature set and return. */ >> if (feature_vector =3D=3D nullptr) >> { >> - features->vlen =3D 0; >> + features->vlenb =3D 0; >> return true; >> } >>=20 >> @@ -696,6 +708,9 @@ struct riscv_vector_feature : public riscv_register_f= eature >> int vector_bitsize =3D -1; >> for (const auto ® : m_registers) >> { >> + if (reg.regnum < RISCV_V0_REGNUM || reg.regnum > RISCV_V31_REGNUM) >> + continue; >> + >> int reg_bitsize =3D -1; >> for (const char *name : reg.names) >> { >> @@ -712,7 +727,7 @@ struct riscv_vector_feature : public riscv_register_f= eature >> return false; >> } >>=20 >> - features->vlen =3D (vector_bitsize / 8); >> + features->vlenb =3D (vector_bitsize / 8); >> return true; >> } >> }; >> @@ -793,6 +808,58 @@ riscv_abi_xlen (struct gdbarch *gdbarch) >>=20 >> /* See riscv-tdep.h. */ >>=20 >> +int >> +riscv_isa_vlenb (struct gdbarch *gdbarch) >> +{ >> + riscv_gdbarch_tdep *tdep =3D gdbarch_tdep (gdbarch= ); >> + return tdep->isa_features.vlenb; >> +} >> + >> +/* Return true if the target for GDBARCH has vector hardware. */ >> + >> +static bool >> +riscv_has_vector_regs (struct gdbarch *gdbarch) >> +{ >> + return (riscv_isa_vlenb (gdbarch) > 0); >> +} >> + >> +/* Return true if REGNO is a vector GPR. */ >> + >> +static bool >> +riscv_is_vector_gpr (int regno) >> +{ >> + return (regno >=3D RISCV_V0_REGNUM && regno <=3D RISCV_V31_REGNUM); >> +} >> + >> +/* Return true if REGNO is a vector CSR. */ >> + >> +static bool >> +riscv_is_vector_rw_csr (int regno) >> +{ >> + return (regno =3D=3D RISCV_CSR_VSTART_REGNUM || regno =3D=3D RISCV_CSR= _VCSR_REGNUM >> + || regno =3D=3D RISCV_CSR_VL_REGNUM || regno =3D=3D RISCV_CSR_VTYP= E_REGNUM); >> +} >> + >> +/* Return true if REGNO is a vector GPR or CSR. */ >> + >> +static bool >> +riscv_is_vector_save_restore_regno (int regno) >> +{ >> + return riscv_is_vector_gpr (regno) || riscv_is_vector_rw_csr (regno); >> +} >> + >> +/* Return true if GDBARCH is using vector hardware ABI. */ >> + >> +static bool >> +riscv_has_vector_abi (struct gdbarch *gdbarch) >> +{ >> + gdb_assert (gdbarch); >> + riscv_gdbarch_tdep *tdep =3D gdbarch_tdep (gdbarch= ); >> + return tdep->abi_features.vlenb > 0; >> +} >> + >> +/* See riscv-tdep.h. */ >> + >> int >> riscv_isa_flen (struct gdbarch *gdbarch) >> { >> @@ -1052,7 +1119,7 @@ riscv_pseudo_register_write (struct gdbarch *gdbarc= h, >> static bool >> riscv_cannot_store_register (struct gdbarch *gdbarch, int regnum) >> { >> - return regnum =3D=3D RISCV_ZERO_REGNUM; >> + return regnum =3D=3D RISCV_ZERO_REGNUM || regnum =3D=3D RISCV_CSR_VLEN= B_REGNUM; >> } >>=20 >> /* Construct a type for 64-bit FP registers. */ >> @@ -1200,7 +1267,7 @@ riscv_print_one_register_info (struct gdbarch *gdba= rch, >> { >> riscv_gdbarch_tdep *tdep =3D gdbarch_tdep (gdba= rch); >>=20 >> - /* Print the register in hex. */ >> + /* Print the register in hex, exclude vector registers. */ >> value_print_options opts =3D get_formatted_print_options ('x'); >> opts.deref_ref =3D true; >> common_val_print (val, file, 0, opts, current_language); >> @@ -1330,17 +1397,46 @@ riscv_print_one_register_info (struct gdbarch *gd= barch, >> else >> gdb_printf (file, "\tprv:%d [INVALID]", priv); >> } >> - else >> + else if (regnum =3D=3D RISCV_CSR_VTYPE_REGNUM) >> { >> - /* If not a vector register, print it also according to its >> - natural format. */ >> - if (regtype->is_vector () =3D=3D 0) >> - { >> - opts =3D get_user_print_options (); >> - opts.deref_ref =3D true; >> - gdb_printf (file, "\t"); >> - common_val_print (val, file, 0, opts, current_language); >> - } >> + LONGEST d =3D value_as_long (val); >> + // Values are decoded according to RISC-V Vector Specification= >> + unsigned lmul_val =3D d & 0x7; >> + const char *decoded_lmul_variants[] >> + =3D { "1", "2", "4", "8", "Reserved", "1/8", "1/4", "1/2" }; >> + unsigned sew_val =3D (d >> 3) & 0x7; >> + const char *decoded_sew_variants[] =3D { "e8", "e16", >> + "e32", "e64", >> + "Reserved", "Reserved", >> + "Reserved", "Reserved" }; >> + unsigned vta =3D (d >> 6) & 0x1; >> + const char *decoded_vta_variants[] =3D { "tu", "ta" }; >> + unsigned vma =3D (d >> 7) & 0x1; >> + const char *decoded_vma_variants[] =3D { "mu", "ma" }; >> + int size =3D register_size (gdbarch, regnum); >> + unsigned xlen =3D size * 8; >> + unsigned vill =3D (d >> (xlen - 1)) & 0x1; >> + gdb_printf (file, >> + "\tLMUL:%u (%s) SEW:%u (%s) vta:%u (%s) vma:%u " >> + "(%s) vill:%u", >> + lmul_val, decoded_lmul_variants[lmul_val], sew_val, >> + decoded_sew_variants[sew_val], vta, >> + decoded_vta_variants[vta], vma, >> + decoded_vma_variants[vma], vill); >> + } >> + else if (regnum =3D=3D RISCV_CSR_VCSR_REGNUM) >> + { >> + LONGEST d =3D value_as_long (val); >> + unsigned vxsat =3D d & 1; >> + unsigned vxrm =3D (d >> 1) & 0b11; >> + gdb_printf (file, "\tVXSAT:%u VXRM:%u", vxsat, vxrm); >> + } >> + else if (regtype->is_vector () =3D=3D 0) >> + { >> + opts =3D get_user_print_options (); >> + opts.deref_ref =3D true; >> + gdb_printf (file, "\t"); >> + common_val_print (val, file, 0, opts, current_language); >> } >> } >> } >> @@ -1433,21 +1529,22 @@ riscv_register_reggroup_p (struct gdbarch *gdbar= ch, int regnum, >> return false; >> } >> else if (reggroup =3D=3D float_reggroup) >> - return (riscv_is_fp_regno_p (regnum) >> - || regnum =3D=3D RISCV_CSR_FCSR_REGNUM >> - || regnum =3D=3D tdep->fflags_regnum >> - || regnum =3D=3D tdep->frm_regnum); >> + return (riscv_is_fp_regno_p (regnum) || regnum =3D=3D RISCV_CSR_FCSR= _REGNUM >> + || regnum =3D=3D tdep->fflags_regnum || regnum =3D=3D tdep->frm_= regnum); >> else if (reggroup =3D=3D general_reggroup) >> return regnum < RISCV_FIRST_FP_REGNUM; >> else if (reggroup =3D=3D restore_reggroup || reggroup =3D=3D save_reggr= oup) >> { >> if (riscv_has_fp_regs (gdbarch)) >> - return (regnum <=3D RISCV_LAST_FP_REGNUM >> - || regnum =3D=3D RISCV_CSR_FCSR_REGNUM >> - || regnum =3D=3D tdep->fflags_regnum >> - || regnum =3D=3D tdep->frm_regnum); >> - else >> - return regnum < RISCV_FIRST_FP_REGNUM; >> + if (riscv_is_fp_regno_p (regnum) || regnum =3D=3D RISCV_CSR_FCSR_REG= NUM >> + || regnum =3D=3D tdep->fflags_regnum || regnum =3D=3D tdep->frm_= regnum) >> + return 1; >> + >> + if (riscv_has_vector_regs (gdbarch) >> + && riscv_is_vector_save_restore_regno (regnum)) >> + return 1; >> + >> + return regnum < RISCV_FIRST_FP_REGNUM; >> } >> else if (reggroup =3D=3D system_reggroup || reggroup =3D=3D csr_reggrou= p) >> { >> @@ -1460,7 +1557,7 @@ riscv_register_reggroup_p (struct gdbarch *gdbarch= , int regnum, >> return false; >> } >> else if (reggroup =3D=3D vector_reggroup) >> - return (regnum >=3D RISCV_V0_REGNUM && regnum <=3D RISCV_V31_REGNUM)= ; >> + return riscv_is_vpr_or_vcsr (regnum); >> else >> return false; >> } >> @@ -2645,18 +2742,25 @@ struct riscv_arg_info >> { >> /* What type of location this is. */ >> enum location_type >> - { >> - /* Argument passed in a register. */ >> - in_reg, >> + { >> + /* Argument passed in a register. */ >> + in_reg, >> + >> + /* Argument passed in several regs. (For now, used for Vector regi= sters.) >> + The first register in the sequence of registers (used for passing >> + arguments) is passed through the first location (see the comment ab= ove >> + struct location), and the last one is passed through the second >> + location. */ >> + in_several_regs, >>=20 >> - /* Argument passed as an on stack argument. */ >> - on_stack, >> + /* Argument passed as an on stack argument. */ >> + on_stack, >>=20 >> - /* Argument passed by reference. The second location is always >> - valid for a BY_REF argument, and describes where the address >> - of the BY_REF argument should be placed. */ >> - by_ref >> - } loc_type; >> + /* Argument passed by reference. The second location is always >> + valid for a BY_REF argument, and describes where the address >> + of the BY_REF argument should be placed. */ >> + by_ref >> + } loc_type; >>=20 >> /* Information that depends on the location type. */ >> union >> @@ -2712,6 +2816,90 @@ struct riscv_arg_reg >> int last_regnum; >> }; >>=20 >> +struct riscv_vector_arg_reg_interval >> +{ >> + int first; >> + int last; >> +}; >> + >> +struct riscv_vector_arg_reg >> +{ >> + riscv_vector_arg_reg (int first, int last) >> + : available_intervals { { first, last } } >> + { >> + /* Nothing. */ >> + } >> + >> + int get_interval_start (int count, int NFIELDS =3D 1) >> + { >> + gdb_assert (count % NFIELDS =3D=3D 0); >> + >> + int LMUL =3D count / NFIELDS; >> + for (auto cur_interval =3D available_intervals.begin (); >> + cur_interval !=3D available_intervals.end (); ++cur_interval) >> + { >> + int cur_first =3D cur_interval->first; >> + int cur_last =3D cur_interval->last; >> + if ((cur_first - RISCV_V0_REGNUM) % LMUL >> + !=3D 0) /* According to RISC-V Vector ABI, >> + first register number should be >> + a multiple of LMUL */ >> + { >> + cur_first -=3D (cur_first - RISCV_V0_REGNUM) % LMUL; >> + cur_first +=3D LMUL; >> + } >> + >> + if ((cur_last - cur_first + 1) >=3D count) >> + { >> + if (cur_first > cur_interval->first) >> + { >> + available_intervals.insert (cur_interval, >> + { cur_interval->first, >> + cur_first - 1 }); >> + } >> + >> + cur_interval->first =3D cur_first + count; >> + >> + return cur_first; >> + } >> + } >> + >> + return -1; >> + } >> + >> + int try_use_v0 () >> + { >> + if (is_v0_used) >> + return get_interval_start (1); >> + else >> + { >> + is_v0_used =3D true; >> + return RISCV_V0_REGNUM; >> + } >> + } >> + >> + bool is_v0_used =3D false; >> + >> + std::list available_intervals; >> + >> + /* =46rom RISCV-ABI, Standard Vector Calling Convention Variant: >> + The rules for passing vector arguments are as follows: >> + 1. For the first vector mask argument, use v0 to pass it. >> + 2. For vector data arguments or rest vector mask arguments, startin= g >> + from the v8 register, if a vector register group between v8-v23 tha= t has >> + not been allocated can be found and the first register number is a >> + multiple of LMUL, then allocate this vector register group to the a= rgument >> + and mark these registers as allocated. Otherwise, pass it by refere= nce and >> + are replaced in the 12 argument list with the address. >> + 3. For tuple vector data arguments, starting from the v8 register, i= f >> + NFIELDS consecutive vector register groups between v8-v23 that have= not >> + been allocated can be found and the first register number is a mult= iple of >> + LMUL, then allocate these vector register groups to the argument an= d mark >> + these registers as allocated. Otherwise, pass it by reference and a= re >> + replaced in the argument list with the address >> + */ >> +}; >> + >> /* Arguments can be passed as on stack arguments, or by reference. The >> on stack arguments must be in a continuous region starting from $sp, >> while the by reference arguments can be anywhere, but we'll put them >> @@ -2749,10 +2937,16 @@ struct riscv_call_info >> { >> riscv_call_info (struct gdbarch *gdbarch) >> : int_regs (RISCV_A0_REGNUM, RISCV_A0_REGNUM + 7), >> - float_regs (RISCV_FA0_REGNUM, RISCV_FA0_REGNUM + 7) >> + float_regs (RISCV_FA0_REGNUM, RISCV_FA0_REGNUM + 7), >> + vector_regs (RISCV_V0_REGNUM + 8, RISCV_V0_REGNUM + 23) >> { >> xlen =3D riscv_abi_xlen (gdbarch); >> flen =3D riscv_abi_flen (gdbarch); >> + /* According to the RVV specification, a binary file does not requir= e >> + any particular vlenb value. However, a target vlenb value is >> + required to place arguments correctly. For this purpose, we save >> + the riscv_isa_vlenb value here. */ >> + vlenb =3D riscv_isa_vlenb (gdbarch); >>=20 >> /* Reduce the number of integer argument registers when using the >> embedded abi (i.e. rv32e). */ >> @@ -2762,6 +2956,10 @@ struct riscv_call_info >> /* Disable use of floating point registers if needed. */ >> if (!riscv_has_fp_abi (gdbarch)) >> float_regs.next_regnum =3D float_regs.last_regnum + 1; >> + >> + /* Disable use of vector registers if needed. */ >> + if (!riscv_has_vector_abi (gdbarch)) >> + vector_regs.available_intervals.clear (); >> } >>=20 >> /* Track the memory areas used for holding in-memory arguments to a >> @@ -2776,10 +2974,15 @@ struct riscv_call_info >> passing an argument. */ >> struct riscv_arg_reg float_regs; >>=20 >> + /* Holds information about the next vector register to use for >> + passing an argument. */ >> + struct riscv_vector_arg_reg vector_regs; >> + >> /* The XLEN and FLEN are copied in to this structure for convenience, a= nd >> are just the results of calling RISCV_ABI_XLEN and RISCV_ABI_FLEN. *= / >> int xlen; >> int flen; >> + int vlenb; >> }; >>=20 >> /* Return the number of registers available for use as parameters in the >> @@ -2821,6 +3024,410 @@ riscv_assign_reg_location (struct riscv_arg_info:= :location *loc, >> return false; >> } >>=20 >> +struct rvv_type_info >> +{ >> + /* Selected Element Width. For RVV_BOOL types, this field holds EEW/EM= UL >> + value, encoded into the type. */ >> + enum class rvv_sew_t : int >> + { >> + SEW8 =3D 8, >> + SEW16 =3D 16, >> + SEW32 =3D 32, >> + SEW64 =3D 64, >> + SEW_UNKNOWN, >> + } sew =3D rvv_sew_t::SEW_UNKNOWN; >> + >> + /* Length Multiplier, amount of registers used for this type. */ >> + enum class rvv_lmul_t : int >> + { >> + LMUL1 =3D 1, >> + LMUL2 =3D 2, >> + LMUL4 =3D 4, >> + LMUL8 =3D 8, >> + LMUL_UNKNOWN, >> + } lmul =3D rvv_lmul_t::LMUL_UNKNOWN; >> + >> + /* For non-tuple types, nfield =3D 1. */ >> + enum class rvv_nfield_t : int >> + { >> + NFIELD1 =3D 1, >> + NFIELD2, >> + NFIELD3, >> + NFIELD4, >> + NFIELD5, >> + NFIELD6, >> + NFIELD7, >> + NFIELD8, >> + NFIELD_UNKNOWN, >> + } nfield =3D rvv_nfield_t::NFIELD_UNKNOWN; >> + >> + enum class rvv_elem_t : char >> + { >> + RVV_INT, >> + RVV_UINT, >> + RVV_FLOAT, >> + RVV_BOOL, >> + RVV_UNKNOWN, >> + } element_type =3D rvv_elem_t::RVV_UNKNOWN; >> + >> + /* is_fractional_lmul means, that used only part of a vector >> + register. For example, if lmul =3D 2 and is_fractional_lmul =3D >> + true it means that used a half of a register. */ >> + bool is_fractional_lmul =3D false; >> +}; >> + >> +struct rvv_type_name_mapping_t >> +{ >> + const char *name; >> + rvv_type_info::rvv_elem_t type; >> +}; >> + >> +static constexpr std::array rvv_type_names =3D= { >> + rvv_type_name_mapping_t { "int", rvv_type_info::rvv_elem_t::RVV_INT },= >> + rvv_type_name_mapping_t { "uint", rvv_type_info::rvv_elem_t::RVV_UINT }= , >> + rvv_type_name_mapping_t { "float", rvv_type_info::rvv_elem_t::RVV_FLOA= T }, >> + rvv_type_name_mapping_t { "bool", rvv_type_info::rvv_elem_t::RVV_BOOL }= >> +}; >> + >> +static bool >> +supported_fractional_sew_lmul (rvv_type_info::rvv_lmul_t lmul, >> + rvv_type_info::rvv_sew_t sew) >> +{ >> + gdb_assert (lmul !=3D rvv_type_info::rvv_lmul_t::LMUL_UNKNOWN); >> + gdb_assert (sew !=3D rvv_type_info::rvv_sew_t::SEW_UNKNOWN); >> + /* More info in RISC-V C Intrinsic Specification Type >> + * System 7.1, 7.2, 7.3, 7.4. */ >> + return static_cast (lmul) * static_cast (sew) <=3D 64; >> +} >> + >> +/* verify_rvv_type() verify RVV types according to specification. */ >> +static bool >> +verify_rvv_type (const rvv_type_info &type_info) >> +{ >> + if (type_info.lmul =3D=3D rvv_type_info::rvv_lmul_t::LMUL1 >> + && type_info.is_fractional_lmul) >> + return false; >> + >> + /* Restriction from RISC-V Vector Specification: LMUL * NFIELDS <=3D 8= . */ >> + if (!type_info.is_fractional_lmul >> + && (static_cast (type_info.lmul) >> + * static_cast (type_info.nfield) >> + > 8)) >> + return false; >> + >> + switch (type_info.element_type) >> + { >> + case rvv_type_info::rvv_elem_t::RVV_FLOAT: >> + /* For float types at least SEW16 is required. */ >> + if (type_info.sew !=3D rvv_type_info::rvv_sew_t::SEW16 >> + && type_info.sew !=3D rvv_type_info::rvv_sew_t::SEW32 >> + && type_info.sew !=3D rvv_type_info::rvv_sew_t::SEW64) >> + return false; >> + >> + /* For float types at least LMUL =3D 1/4 is required. */ >> + if (type_info.lmul =3D=3D rvv_type_info::rvv_lmul_t::LMUL8 >> + && type_info.is_fractional_lmul) >> + return false; >> + >> + /* rvv_spec_requirement condition applies only to types with fract= ional >> + LMUL. */ >> + if (!type_info.is_fractional_lmul) >> + return true; >> + >> + return supported_fractional_sew_lmul (type_info.lmul, type_info.se= w); >> + >> + case rvv_type_info::rvv_elem_t::RVV_INT: >> + case rvv_type_info::rvv_elem_t::RVV_UINT: >> + /* For int/uint types at least SEW8 is required. */ >> + if (type_info.sew !=3D rvv_type_info::rvv_sew_t::SEW8 >> + && type_info.sew !=3D rvv_type_info::rvv_sew_t::SEW16 >> + && type_info.sew !=3D rvv_type_info::rvv_sew_t::SEW32 >> + && type_info.sew !=3D rvv_type_info::rvv_sew_t::SEW64) >> + return false; >> + >> + /* rvv_spec_requirement condition applies only to types with fract= ional >> + LMUL. */ >> + if (!type_info.is_fractional_lmul) >> + return true; >> + >> + return supported_fractional_sew_lmul (type_info.lmul, type_info.se= w); >> + >> + case rvv_type_info::rvv_elem_t::RVV_BOOL: >> + /* These restrictions do not follow from the specification, but fr= om the >> + internal constraints of the structure of rvv_type_info. */ >> + return (type_info.lmul =3D=3D rvv_type_info::rvv_lmul_t::LMUL1 >> + && type_info.nfield =3D=3D rvv_type_info::rvv_nfield_t::NFIELD= 1 >> + && !type_info.is_fractional_lmul); >> + >> + default: >> + return false; >> + } >> +} >> + >> +static std::regex >> +get_rvv_type_regex () >> +{ >> + /* According to specification, RVV type names don't start with __rvv_ (= like >> + vint64m1_t), but in GCC and Clang they are aliases (__rvv_int64m1_t= ). */ >> + auto pipe_fold =3D [] (const std::string &a, >> + const rvv_type_name_mapping_t &b) { >> + return a + "|" + std::string (b.name); >> + }; >> + std::string accumulator >> + =3D std::accumulate (std::next (rvv_type_names.begin ()), >> + rvv_type_names.end (), >> + std::string (rvv_type_names[0].name), pipe_fold); >> + return std::regex ("__rvv_(" + accumulator >> + + ")(1|2|4|8|16|32|64)((m|mf)([1248]))?(x([2-8]))?_t"); >> +} >> + >> +struct parsed_rvv_type_t >> +{ >> + enum class group >> + { >> + name =3D 1, >> + sew, >> + lmul_str, >> + lmul_type, >> + lmul_val, >> + nfield_str, >> + nfield_val >> + }; >> + >> + static std::optional parse (std::string_view name) >> + { >> + parsed_rvv_type_t res; >> + if (std::regex_search (name.begin (), name.end (), res.matches, >> + rvv_type_regex)) >> + return res; >> + return std::nullopt; >> + } >> + >> + std::string_view get (group g) const >> + { >> + long unsigned index =3D static_cast (g); >> + const auto &sm =3D matches[index]; >> + return std::string_view (sm.first, sm.length ()); >> + } >> + >> +private: >> + parsed_rvv_type_t () =3D default; >> + std::cmatch matches; >> + inline static const std::regex rvv_type_regex =3D get_rvv_type_regex (= ); >> +}; >> + >> +static std::optional >> +get_rvv_type_info_unverified (struct type *type) >> +{ >> + if (!type) >> + return std::nullopt; >> + >> + type =3D check_typedef (type); >> + >> + if (!type->name ()) >> + { >> + riscv_infcall_debug_printf ( >> + "The type name is missing, unable to get RVV type info."); >> + return std::nullopt; >> + } >> + >> + if (type->code () !=3D TYPE_CODE_ARRAY && type->code () !=3D TYPE_CODE= _STRUCT) >> + { >> + riscv_infcall_debug_printf ("Incorrect type_code: %d. Expected %d "= >> + "(TYPE_CODE_ARRAY) or %d (TYPE_CODE_STRUCT)", >> + type->code (), TYPE_CODE_ARRAY, >> + TYPE_CODE_STRUCT); >> + return std::nullopt; >> + } >> + >> + auto parsed_rvv_type_holder =3D parsed_rvv_type_t::parse (type->name (= )); >> + if (!parsed_rvv_type_holder.has_value ()) >> + { >> + riscv_infcall_debug_printf ("Failed to match RVV type name: %s", >> + type->name ()); >> + return std::nullopt; >> + } >> + parsed_rvv_type_t parsed_rvv_type =3D parsed_rvv_type_holder.value ();= >> + rvv_type_info res; >> + >> + auto it =3D std::find_if ( >> + rvv_type_names.begin (), rvv_type_names.end (), >> + [parsed_rvv_type] (const rvv_type_name_mapping_t &type_name) { >> + return parsed_rvv_type.get (parsed_rvv_type_t::group::name) >> + .compare (type_name.name) >> + =3D=3D 0; >> + }); >> + if (it =3D=3D rvv_type_names.end ()) >> + { >> + riscv_infcall_debug_printf ( >> + "Unable to find RVV element type in type name %s.", type->name ()); >> + return std::nullopt; >> + } >> + res.element_type =3D it->type; >> + >> + if (auto sew_val =3D parse_integer ( >> + parsed_rvv_type.get (parsed_rvv_type_t::group::sew))) >> + { >> + res.sew =3D static_cast (sew_val.value (= )); >> + } >> + else >> + { >> + std::string_view sew_str >> + =3D parsed_rvv_type.get (parsed_rvv_type_t::group::sew); >> + riscv_infcall_debug_printf ( >> + "Failed to convert SEW string (%.*s) to unsigned", >> + static_cast (sew_str.size ()), sew_str.data ()); >> + return std::nullopt; >> + } >> + >> + if (!parsed_rvv_type.get (parsed_rvv_type_t::group::lmul_str).empty ()= ) >> + { >> + if (parsed_rvv_type.get (parsed_rvv_type_t::group::lmul_type) >> + .compare ("mf") >> + =3D=3D 0) >> + res.is_fractional_lmul =3D true; >> + else >> + res.is_fractional_lmul =3D false; >> + >> + if (auto lmul_val =3D parse_integer ( >> + parsed_rvv_type.get (parsed_rvv_type_t::group::lmul_val))) >> + { >> + res.lmul >> + =3D static_cast (lmul_val.value ()); >> + } >> + else >> + { >> + std::string_view lmul_str >> + =3D parsed_rvv_type.get (parsed_rvv_type_t::group::lmul_val); >> + riscv_infcall_debug_printf ( >> + "Failed to convert LMUL string (%.*s) to unsigned", >> + static_cast (lmul_str.size ()), lmul_str.data ()); >> + return std::nullopt; >> + } >> + } >> + else >> + { >> + res.lmul =3D rvv_type_info::rvv_lmul_t::LMUL1; >> + res.is_fractional_lmul =3D false; >> + } >> + >> + if (!parsed_rvv_type.get (parsed_rvv_type_t::group::nfield_str).empty (= )) >> + { >> + if (auto nfield_val =3D parse_integer ( >> + parsed_rvv_type.get (parsed_rvv_type_t::group::nfield_val))) >> + { >> + res.nfield >> + =3D static_cast (nfield_val.value (= )); >> + } >> + else >> + { >> + std::string_view nfield_str >> + =3D parsed_rvv_type.get (parsed_rvv_type_t::group::nfield_val); >> + riscv_infcall_debug_printf ( >> + "Failed to convert NFIELD string (%.*s) to unsigned", >> + static_cast (nfield_str.size ()), nfield_str.data ()); >> + return std::nullopt; >> + } >> + } >> + else >> + res.nfield =3D rvv_type_info::rvv_nfield_t::NFIELD1; >> + >> + return res; >> +} >> + >> +static std::optional >> +get_rvv_type_info (struct type *type) >> +{ >> + std::optional res =3D get_rvv_type_info_unverified (typ= e); >> + >> + if (res.has_value () && verify_rvv_type (res.value ())) >> + return res; >> + >> + return std::nullopt; >> +} >> + >> +static bool >> +is_rvv_type (struct type *type) >> +{ >> + return get_rvv_type_info (type).has_value (); >> +} >> + >> +static bool >> +riscv_assign_vec_reg_location (struct riscv_arg_info *ainfo, >> + struct riscv_vector_arg_reg *reg, >> + struct type *func_arg_type, int vlenb) >> +{ >> + int data_length =3D vlenb; /* Amount of data that is stored on one reg= ister */ >> + >> + struct riscv_arg_info::location *loc0 =3D &ainfo->argloc[0]; >> + struct riscv_arg_info::location *loc1 =3D &ainfo->argloc[1]; >> + >> + rvv_type_info arg_type_info; >> + if (std::optional res =3D get_rvv_type_info (func_arg_t= ype)) >> + arg_type_info =3D res.value (); >> + else >> + gdb_assert_not_reached ("Incorrect type %s", func_arg_type->name ())= ; >> + >> + riscv_infcall_debug_printf ( >> + "rvv_type_info of %s: element_type =3D %d, sew =3D %u, lmul =3D %u (= %s " >> + "fractional), nfield =3D %u", >> + func_arg_type->name (), static_cast (arg_type_info.element_type= ), >> + static_cast (arg_type_info.sew), >> + static_cast (arg_type_info.lmul), >> + (arg_type_info.is_fractional_lmul ? "is" : "is not"), >> + static_cast (arg_type_info.nfield)); >> + >> + int num_required_regs =3D ((arg_type_info.is_fractional_lmul) >> + ? 1 >> + : static_cast (arg_type_info.lmul)) >> + * static_cast (arg_type_info.nfield); >> + >> + if (arg_type_info.is_fractional_lmul) >> + { >> + num_required_regs =3D static_cast (arg_type_info.nfield); >> + data_length =3D data_length / static_cast (arg_type_info.lmul= ); >> + } >> + >> + int first_regnum =3D -1; >> + >> + /* Representation of vector segmented types, like vint32m4x2_t, >> + is different in Clang and GCC. >> + In Clang, all types are arrays. >> + In GCC, segmented types are struct's, other vector types are arrays= . */ >> + if (ainfo->type->code () =3D=3D TYPE_CODE_ARRAY) >> + { >> + if (ainfo->type->target_type ()->code () =3D=3D TYPE_CODE_BOOL) >> + first_regnum =3D reg->try_use_v0 (); >> + else >> + first_regnum >> + =3D reg->get_interval_start (num_required_regs, >> + static_cast (arg_type_info.nfield)); >> + } >> + else if (ainfo->type->code () =3D=3D TYPE_CODE_STRUCT) >> + { >> + first_regnum >> + =3D reg->get_interval_start (num_required_regs, >> + static_cast (arg_type_info.nfield)); >> + } >> + >> + if (first_regnum =3D=3D -1) >> + return false; >> + >> + int last_regnum =3D first_regnum + num_required_regs - 1; >> + >> + loc0->loc_type =3D riscv_arg_info::location::in_several_regs; >> + loc0->loc_data.regno =3D first_regnum; >> + loc0->c_length =3D data_length; >> + loc0->c_offset =3D 0; >> + >> + loc1->loc_type =3D riscv_arg_info::location::in_several_regs; >> + loc1->loc_data.regno =3D last_regnum; >> + loc1->c_length =3D 0; >> + loc1->c_offset =3D 0; >> + >> + return true; >> +} >> + >> /* Assign LOC a location as the next stack parameter, and update MEMORY t= o >> record that an area of stack has been used to hold the parameter >> described by LOC. >> @@ -3229,21 +3836,44 @@ riscv_call_arg_struct (struct riscv_arg_info *ain= fo, >> riscv_call_arg_scalar_int (ainfo, cinfo); >> } >>=20 >> +static void >> +riscv_call_arg_vector (struct riscv_arg_info *ainfo, >> + struct riscv_call_info *cinfo, >> + struct type *func_arg_type) >> +{ >> + if (!riscv_assign_vec_reg_location (ainfo, &cinfo->vector_regs, >> + func_arg_type, cinfo->vlenb)) >> + { >> + // Try to pass value by reference >> + ainfo->argloc[0].loc_type =3D riscv_arg_info::location::by_ref; >> + cinfo->memory.ref_offset =3D align_up (cinfo->memory.ref_offset, >> + ainfo->align); >> + ainfo->argloc[0].loc_data.offset =3D cinfo->memory.ref_offset; >> + cinfo->memory.ref_offset +=3D ainfo->length; >> + ainfo->argloc[0].c_length =3D ainfo->length; >> + >> + if (!riscv_assign_reg_location (&ainfo->argloc[1], &cinfo->int_reg= s, >> + cinfo->xlen, 0)) >> + riscv_assign_stack_location (&ainfo->argloc[1], &cinfo->memory, >> + cinfo->xlen, cinfo->xlen); >> + } >> +} >> + >> /* Assign a location to call (or return) argument AINFO, the location is >> selected from CINFO which holds information about what call argument >> locations are available for use next. The TYPE is the type of the >> argument being passed, this information is recorded into AINFO (along >> with some additional information derived from the type). IS_UNNAMED >> is true if this is an unnamed (stdarg) argument, this info is also >> - recorded into AINFO. >> + recorded into AINFO. FUNC_ARG_TYPE is the type of the function parame= ter in >> + its declaration. >>=20 >> After assigning a location to AINFO, CINFO will have been updated. */= >>=20 >> static void >> -riscv_arg_location (struct gdbarch *gdbarch, >> - struct riscv_arg_info *ainfo, >> - struct riscv_call_info *cinfo, >> - struct type *type, bool is_unnamed) >> +riscv_arg_location (struct gdbarch *gdbarch, struct riscv_arg_info *ainf= o, >> + struct riscv_call_info *cinfo, struct type *type, >> + struct type *func_arg_type, bool is_unnamed) >> { >> ainfo->type =3D type; >> ainfo->length =3D ainfo->type->length (); >> @@ -3253,6 +3883,12 @@ riscv_arg_location (struct gdbarch *gdbarch, >> ainfo->argloc[0].c_length =3D 0; >> ainfo->argloc[1].c_length =3D 0; >>=20 >> + if (is_rvv_type (func_arg_type)) /* for RISC_V vector registers */ >=20 > GDB doesn't use trailing comments like this, the comment needs placing > on the line before the 'if', and the comment needs to be a proper > sentence, capital letter and full stop. >=20 >> + { >> + riscv_call_arg_vector (ainfo, cinfo, func_arg_type); >> + return; >> + } >> + >> switch (ainfo->type->code ()) >> { >> case TYPE_CODE_INT: >> @@ -3375,6 +4011,14 @@ riscv_print_arg_location (ui_file *stream, struct g= dbarch *gdbarch, >> } >> break; >>=20 >> + case riscv_arg_info::location::in_several_regs: >> + gdb_printf (stream, ", registers from %s to %s", >> + gdbarch_register_name (gdbarch, >> + info->argloc[0].loc_data.regno), >> + gdbarch_register_name (gdbarch, >> + info->argloc[1].loc_data.regno)); >> + break; >> + >> default: >> gdb_assert_not_reached ("unknown argument location type"); >> } >> @@ -3389,15 +4033,13 @@ static void >> riscv_regcache_cooked_write (int regnum, const gdb_byte *data, int len, >> struct regcache *regcache, int flen) >> { >> - gdb_byte tmp [sizeof (ULONGEST)]; >> - >> + int regsize =3D register_size (regcache->arch (), regnum); >> + std::vector tmp (regsize); >> /* FP values in FP registers must be NaN-boxed. */ >> if (riscv_is_fp_regno_p (regnum) && len < flen) >> - memset (tmp, -1, sizeof (tmp)); >> - else >> - memset (tmp, 0, sizeof (tmp)); >> - memcpy (tmp, data, len); >> - regcache->cooked_write (regnum, tmp); >> + memset (tmp.data (), -1, tmp.size ()); >> + memcpy (tmp.data (), data, len); >> + regcache->cooked_write (regnum, tmp.data ()); >> } >>=20 >> /* Implement the push dummy call gdbarch callback. */ >> @@ -3437,16 +4079,21 @@ riscv_push_dummy_call (struct gdbarch *gdbarch, >> { >> struct value *arg_value; >> struct type *arg_type; >> + struct type *func_arg_type; >> struct riscv_arg_info *info =3D &arg_info[i]; >>=20 >> arg_value =3D args[i]; >> arg_type =3D check_typedef (arg_value->type ()); >>=20 >> - riscv_arg_location (gdbarch, info, &call_info, arg_type, >> + func_arg_type =3D (i < ftype->num_fields ()) ? ftype->field (i).ty= pe () >> + : nullptr; >> + >> + riscv_arg_location (gdbarch, info, &call_info, arg_type, func_arg_= type, >> ftype->has_varargs () && i >=3D ftype->num_fields ()); >>=20 >> if (info->type !=3D arg_type) >> arg_value =3D value_cast (info->type, arg_value); >> + >> info->contents =3D arg_value->contents ().data (); >> } >>=20 >> @@ -3458,13 +4105,17 @@ riscv_push_dummy_call (struct gdbarch *gdbarch, >> { >> RISCV_INFCALL_SCOPED_DEBUG_START_END ("dummy call args"); >> riscv_infcall_debug_printf ("floating point ABI %s in use", >> - (riscv_has_fp_abi (gdbarch) >> - ? "is" : "is not")); >> + (riscv_has_fp_abi (gdbarch) ? "is" >> + : "is not")); >> + riscv_infcall_debug_printf ("vector ABI %s in use", >> + (riscv_has_vector_abi (gdbarch) ? "is" >> + : "is not")); >> riscv_infcall_debug_printf ("xlen: %d", call_info.xlen); >> riscv_infcall_debug_printf ("flen: %d", call_info.flen); >> + riscv_infcall_debug_printf ("vlenb: %d", call_info.vlenb); >> if (return_method =3D=3D return_method_struct) >> - riscv_infcall_debug_printf >> - ("[**] struct return pointer in register $A0"); >> + riscv_infcall_debug_printf ( >> + "[**] struct return pointer in register $A0"); >> for (i =3D 0; i < nargs; ++i) >> { >> struct riscv_arg_info *info =3D &arg_info [i]; >> @@ -3538,6 +4189,22 @@ riscv_push_dummy_call (struct gdbarch *gdbarch, >> second_arg_data =3D (gdb_byte *) &dst; >> break; >>=20 >> + case riscv_arg_info::location::in_several_regs: >> + { >> + const gdb_byte *cur_contents =3D info->contents; >> + int cur_c_length =3D info->argloc[0].c_length; >> + for (int cur_regno =3D info->argloc[0].loc_data.regno; >> + cur_regno <=3D info->argloc[1].loc_data.regno; cur_regno++) >> + { >> + riscv_regcache_cooked_write (cur_regno, cur_contents, >> + cur_c_length, regcache, >> + call_info.flen); >> + cur_contents +=3D cur_c_length; >> + } >> + second_arg_length =3D 0; >> + } >> + break; >> + >> default: >> gdb_assert_not_reached ("unknown argument location type"); >> } >> @@ -3568,6 +4235,8 @@ riscv_push_dummy_call (struct gdbarch *gdbarch, >> } >>=20 >> case riscv_arg_info::location::by_ref: >> + case riscv_arg_info::location:: >> + in_several_regs: /* We shouldn't get here for this case*/ >=20 > Another trailing comment. Plus it's not really clear what this means. > If we really shouldn't get here then there's gdb_assert_not_reached > which maybe you could use? >=20 >> default: >> /* The second location should never be a reference, any >> argument being passed by reference just places its address >> @@ -3606,9 +4275,14 @@ riscv_return_value (struct gdbarch *gdbarch, >> struct riscv_call_info call_info (gdbarch); >> struct riscv_arg_info info; >> struct type *arg_type; >> + struct type *func_retval_type; >>=20 >> arg_type =3D check_typedef (type); >> - riscv_arg_location (gdbarch, &info, &call_info, arg_type, false); >> + func_retval_type =3D (function && function->type ()) >> + ? function->type ()->target_type () >> + : nullptr; >> + riscv_arg_location (gdbarch, &info, &call_info, arg_type, func_retval_= type, >> + false); >>=20 >> if (riscv_debug_infcall) >> { >> @@ -3761,6 +4435,38 @@ riscv_return_value (struct gdbarch *gdbarch, >> } >> break; >>=20 >> + case riscv_arg_info::location::in_several_regs: >> + { >> + int first_regnum =3D info.argloc[0].loc_data.regno; >> + int last_regnum =3D info.argloc[1].loc_data.regno; >> + >> + gdb_byte *tmp_readbuf =3D readbuf; >> + const gdb_byte *tmp_writebuf =3D writebuf; >> + >> + for (int cur_regnum =3D first_regnum; cur_regnum <=3D last_regnu= m; >> + cur_regnum++) >> + { >> + if (readbuf) >> + { >> + gdb_byte *ptr =3D tmp_readbuf + info.argloc[0].c_offset; >> + regcache->cooked_read_part (cur_regnum, 0, >> + info.argloc[0].c_length, ptr); >> + tmp_readbuf +=3D info.argloc[0].c_length; >> + } >> + >> + if (writebuf) >> + { >> + const gdb_byte *ptr =3D tmp_writebuf >> + + info.argloc[0].c_offset; >> + riscv_regcache_cooked_write (cur_regnum, ptr, >> + info.argloc[0].c_length, >> + regcache, call_info.flen); >> + tmp_writebuf +=3D info.argloc[0].c_length; >> + } >> + } >> + } >> + break; >> + >> case riscv_arg_info::location::on_stack: >> default: >> error (_("invalid argument location")); >> @@ -3795,6 +4501,7 @@ riscv_return_value (struct gdbarch *gdbarch, >> switch (info.argloc[0].loc_type) >> { >> case riscv_arg_info::location::in_reg: >> + case riscv_arg_info::location::in_several_regs: >> return RETURN_VALUE_REGISTER_CONVENTION; >> case riscv_arg_info::location::by_ref: >> return RETURN_VALUE_ABI_PRESERVES_ADDRESS; >> @@ -3923,6 +4630,17 @@ static const struct frame_unwind_legacy riscv_fram= e_unwind ( >> /*.prev_arch =3D*/ NULL >> ); >>=20 >> +static bool >> +riscv_search_extension_in_march (std::string_view march, >> + std::string_view extension) >> +{ >> + std::string regex_string =3D "_" + std::string (extension) >> + + "(_|$|[1-9]?\\d+p[1-9]?\\d)"; >> + std::regex regexp_for_extension (regex_string); >> + return std::regex_search (march.begin (), march.end (), >> + regexp_for_extension); >> +} >> + >> /* Extract a set of required target features out of ABFD. If ABFD is >> nullptr then a RISCV_GDBARCH_FEATURES is returned in its default state= . */ >>=20 >> @@ -3963,6 +4681,31 @@ riscv_features_from_bfd (const bfd *abfd) >> } >> features.embedded =3D true; >> } >> + >> + obj_attribute *obj_attr =3D elf_known_obj_attributes_proc (abfd); >> + const char *march =3D obj_attr[Tag_RISCV_arch].s; >> + if (march) >> + { >> + /* According to the RVV specification, a binary file does not requ= ire >> + any particular vlenb value. Therefore, we used minimal vlenb va= lue >> + to indicate that the vector ABI is in use. Additionally, a vali= d >> + vlenb value is required here, as it will be used later to creat= e a >> + default target description. */ >> + std::string_view march_str (march); >> + if (riscv_search_extension_in_march (march_str, "v")) >> + features.vlenb =3D 16; >> + else if (riscv_search_extension_in_march (march_str, "zve64x") >> + || riscv_search_extension_in_march (march_str, "zve64f") >> + || riscv_search_extension_in_march (march_str, "zve64d")) >> + features.vlenb =3D 8; >> + else if (riscv_search_extension_in_march (march_str, "zve32x") >> + || riscv_search_extension_in_march (march_str, "zve32f")) >> + features.vlenb =3D 4; >> + else >> + features.vlenb =3D 0; >> + } >> + else >> + features.vlenb =3D 0; >> } >>=20 >> return features; >> @@ -4265,6 +5008,13 @@ riscv_gdbarch_init (struct gdbarch_info info, >> error (_("bfd requires flen %d, but target has flen %d"), >> abi_features.flen, features.flen); >>=20 >> + /* Look at riscv_features_from_bfd*/ >=20 > Comment missing full stop. >=20 >> + if ((abi_features.vlenb > 0) && (features.vlenb =3D=3D 0)) >> + { >> + warning (_ ("bfd requires non-zero vlenb, but target has vlenb =3D= 0, " >=20 > The one place where GDB doesn't use space between function and argument > string is for '_', it should be _("bfd requires ..."). It just adds to > the fun :) >=20 >> + "vector registers unsupported")); >> + } >> + >> /* Find a candidate among the list of pre-declared architectures. */ >> for (arches =3D gdbarch_list_lookup_by_info (arches, &info); >> arches !=3D NULL; >> @@ -5468,3 +6218,13 @@ riscv_process_record (struct gdbarch *gdbarch, str= uct regcache *regcache, >>=20 >> return 0; >> } >> + >> +bool >> +riscv_is_vpr_or_vcsr (unsigned regnum) >> +{ >> + return (regnum >=3D RISCV_V0_REGNUM && regnum <=3D RISCV_V0_REGNUM + 3= 1) >> + || regnum =3D=3D RISCV_CSR_VSTART_REGNUM >> + || regnum =3D=3D RISCV_CSR_VCSR_REGNUM || regnum =3D=3D RISCV_CSR_V= L_REGNUM >> + || regnum =3D=3D RISCV_CSR_VTYPE_REGNUM >> + || regnum =3D=3D RISCV_CSR_VLENB_REGNUM; >> +} >> diff --git a/gdb/riscv-tdep.h b/gdb/riscv-tdep.h >> index 344a995a680..a6fd89c9646 100644 >> --- a/gdb/riscv-tdep.h >> +++ b/gdb/riscv-tdep.h >> @@ -23,61 +23,7 @@ >>=20 >> #include "arch/riscv.h" >> #include "gdbarch.h" >> - >> -/* RiscV register numbers. */ >> -enum >> -{ >> - RISCV_ZERO_REGNUM =3D 0, /* Read-only register, always 0. */ >> - RISCV_RA_REGNUM =3D 1, /* Return Address. */ >> - RISCV_SP_REGNUM =3D 2, /* Stack Pointer. */ >> - RISCV_GP_REGNUM =3D 3, /* Global Pointer. */ >> - RISCV_TP_REGNUM =3D 4, /* Thread Pointer. */ >> - RISCV_FP_REGNUM =3D 8, /* Frame Pointer. */ >> - RISCV_A0_REGNUM =3D 10, /* First argument. */ >> - RISCV_A1_REGNUM =3D 11, /* Second argument. */ >> - RISCV_A2_REGNUM =3D 12, /* Third argument. */ >> - RISCV_A3_REGNUM =3D 13, /* Forth argument. */ >> - RISCV_A4_REGNUM =3D 14, /* Fifth argument. */ >> - RISCV_A5_REGNUM =3D 15, /* Sixth argument. */ >> - RISCV_A7_REGNUM =3D 17, /* Register to pass syscall number. */= >> - RISCV_PC_REGNUM =3D 32, /* Program Counter. */ >> - >> - RISCV_NUM_INTEGER_REGS =3D 32, >> - >> - RISCV_FIRST_FP_REGNUM =3D 33, /* First Floating Point Register */ >> - RISCV_FA0_REGNUM =3D 43, >> - RISCV_FA1_REGNUM =3D RISCV_FA0_REGNUM + 1, >> - RISCV_LAST_FP_REGNUM =3D 64, /* Last Floating Point Register */ >> - >> - RISCV_FIRST_CSR_REGNUM =3D 65, /* First CSR */ >> -#define DECLARE_CSR(name, num, class, define_version, abort_version) \ >> - RISCV_ ## num ## _REGNUM =3D RISCV_FIRST_CSR_REGNUM + num, >> -#include "opcode/riscv-opc.h" >> -#undef DECLARE_CSR >> - RISCV_LAST_CSR_REGNUM =3D 4160, >> - RISCV_CSR_LEGACY_MISA_REGNUM =3D 0xf10 + RISCV_FIRST_CSR_REGNUM, >> - >> - RISCV_PRIV_REGNUM =3D 4161, >> - >> - RISCV_V0_REGNUM, >> - >> - RISCV_V31_REGNUM =3D RISCV_V0_REGNUM + 31, >> - >> - RISCV_LAST_REGNUM =3D RISCV_V31_REGNUM >> -}; >> - >> -/* RiscV DWARF register numbers. */ >> -enum >> -{ >> - RISCV_DWARF_REGNUM_X0 =3D 0, >> - RISCV_DWARF_REGNUM_X31 =3D 31, >> - RISCV_DWARF_REGNUM_F0 =3D 32, >> - RISCV_DWARF_REGNUM_F31 =3D 63, >> - RISCV_DWARF_REGNUM_V0 =3D 96, >> - RISCV_DWARF_REGNUM_V31 =3D 127, >> - RISCV_DWARF_FIRST_CSR =3D 4096, >> - RISCV_DWARF_LAST_CSR =3D 8191, >> -}; >> +#include "riscv-regs.h" >>=20 >> /* RISC-V specific per-architecture information. */ >> struct riscv_gdbarch_tdep : gdbarch_tdep_base >> @@ -135,6 +81,8 @@ extern int riscv_isa_xlen (struct gdbarch *gdbarch); >> single, double or quad floating point support is available. */ >> extern int riscv_isa_flen (struct gdbarch *gdbarch); >>=20 >> +extern int riscv_isa_vlenb (struct gdbarch *gdbarch); >> + >> /* Return the width in bytes of the general purpose register abi for >> GDBARCH. This can be equal to, or less than RISCV_ISA_XLEN and reflec= ts >> how the binary was compiled rather than the hardware that is available= . >> @@ -158,6 +106,8 @@ extern int riscv_abi_flen (struct gdbarch *gdbarch); >> argument registers. */ >> extern bool riscv_abi_embedded (struct gdbarch *gdbarch); >>=20 >> +extern int riscv_abi_vlenb (struct gdbarch *gdbarch); >=20 > This function is never defined, please delete this declaration. >=20 > Thanks, > Andrew >=20