From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from simark.ca by simark.ca with LMTP id a0ZHMsfyx2qohhgAWB0awg (envelope-from ) for ; Thu, 08 Oct 2026 15:45:11 -0400 Authentication-Results: simark.ca; dkim=pass (1024-bit key; unprotected) header.d=redhat.com header.i=@redhat.com header.a=rsa-sha256 header.s=mimecast20190719 header.b=Ig0+pTEu; dkim-atps=neutral Received: by simark.ca (Postfix, from userid 112) id B16C51E04E; Thu, 08 Oct 2026 15:45:11 -0400 (EDT) X-Spam-Checker-Version: SpamAssassin 4.0.1 (2024-03-25) on simark.ca X-Spam-Level: X-Spam-Status: No, score=-6.4 required=5.0 tests=ARC_SIGNED,ARC_VALID,BAYES_00, DKIMWL_WL_HIGH,DKIM_SIGNED,DKIM_VALID,DKIM_VALID_AU,MAILING_LIST_MULTI, RCVD_IN_DNSWL_MED autolearn=ham autolearn_force=no version=4.0.1 Received: from vm01.sourceware.org (vm01.sourceware.org [IPv6:2620:52:6:3111::32]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange x25519 server-signature ECDSA (prime256v1) server-digest SHA256) (No client certificate requested) by simark.ca (Postfix) with ESMTPS id 7DD881E04E for ; Thu, 08 Oct 2026 15:45:08 -0400 (EDT) Received: from vm01.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id 9C7044BA2E0E for ; Thu, 8 Oct 2026 19:45:07 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 9C7044BA2E0E Authentication-Results: sourceware.org; dkim=pass (1024-bit key, unprotected) header.d=redhat.com header.i=@redhat.com header.a=rsa-sha256 header.s=mimecast20190719 header.b=Ig0+pTEu Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.133.124]) by sourceware.org (Postfix) with ESMTP id 172E14BA540B for ; Thu, 8 Oct 2026 19:44:29 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org 172E14BA540B Authentication-Results: sourceware.org; dmarc=pass (p=quarantine dis=none) header.from=redhat.com Authentication-Results: sourceware.org; spf=pass smtp.mailfrom=redhat.com ARC-Filter: OpenARC Filter v1.0.0 sourceware.org 172E14BA540B Authentication-Results: sourceware.org; arc=none smtp.remote-ip=170.10.133.124 ARC-Seal: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1791488669; cv=none; b=KkYcrcKKJcmfDzRPTC1eQjAGIasoZingI7sqRri0B4VN+3GIS6qVw1Cdfd47iH8zh1sNV+J79I0r2CArwxWO4qZjkTxT5I7uE8yPSgmz9xlYOlxlIWk4EOKOJoJtGjDKtPhIXyEuNv2NBJPDS7CqkCwCmKLlHSGFkOT3wO1D9go= ARC-Message-Signature: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1791488669; c=relaxed/simple; bh=2FHpoovwDBXaFXDEnOCk6OiH7UAFjU4L0M6NoA3pdXY=; h=DKIM-Signature:From:To:Subject:Date:Message-ID:MIME-Version; b=nz7tWo6S+tu43fGuMKs5eKX/5h+DKbj/mVQQBspKxLpCXJ7ggemSu/ktQyaRP+1TvicENulrUjsVsnQzCWuglZLCQdUzQIwWesdDAHlAnkQ5Mi/edzkqJTbz6iyz6xDsqpEH0rTq6k/RrmvzWqWim1Ax4ZwIed1ucmPFUkQzc7E= ARC-Authentication-Results: i=1; sourceware.org; dkim=pass (1024-bit key, unprotected) header.d=redhat.com header.i=@redhat.com header.a=rsa-sha256 header.s=mimecast20190719 header.b=Ig0+pTEu DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 172E14BA540B DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1791488668; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: in-reply-to:in-reply-to:references:references; bh=/ejcqZUdx3N3hQBIvxZpBx8XEW2ZlZKh1/sBfna82c0=; b=Ig0+pTEuqR+a6y3u3lAbzV2zUIULOet+AlMbKLqaE13gRPLcxzCCYj96eWVM6QulGGpW0N 3AKV6VJKEYQTSv4mVCiAamjW+N5IFdlEVz0Nl6mG+UF1r6gf8/Um9w3RjINZjROHkIduZC DPu3oRB6wzio4umjhJN1wwtZNDeImKE= Received: from mail-wm1-f70.google.com (mail-wm1-f70.google.com [209.85.128.70]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-624-oKiFkkJ3MpC3l6yzpOVGrw-1; Thu, 08 Oct 2026 15:44:24 -0400 X-MC-Unique: oKiFkkJ3MpC3l6yzpOVGrw-1 X-Mimecast-MFC-AGG-ID: oKiFkkJ3MpC3l6yzpOVGrw_1791488661 Received: by mail-wm1-f70.google.com with SMTP id 5b1f17b1804b1-4a021b1b561so43243665e9.1 for ; Thu, 08 Oct 2026 12:44:24 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20260707; t=1791488661; x=1792093461; h=content-type:mime-version:message-id:date:references:in-reply-to :subject:cc:to:from:x-gm-gg:x-gm-message-state:from:to:cc:subject :date:message-id:reply-to:content-type; bh=/ejcqZUdx3N3hQBIvxZpBx8XEW2ZlZKh1/sBfna82c0=; b=Rtbtzq01a+pg0YZvT/HoOzgWQ/+NeBbUCHK9SWioIL1Gr1PwWekti7KxkIMoPzvUfc NCk5FyFxANK/CdHi2mqFRybw7MPTy579lckP/uXolYBWABdbc5KStUuLfbs6GuqoU4PK i/pYq8/pRmXNZz1i1VyJhHov8z4+VajAqanYRo4lw98Wv3dbF+6fPOHUG3O1ZYkTulwe MRQiNADwgTjYfF8PY1lpsKpKEY3o9eeg9Ew5v57ZbVNXI3k1obTVa4Ucg+mNBBa4QJtK Ct5VE6glsG4mJWPKnqyea5RcDnt4j5q/sYqXi+DImDYmf96qnH3EykxwE0a8G9d3vA/o PfYw== X-Forwarded-Encrypted: i=1; AKwUvBz0ENr/8f0bkH6QnzycinQubMoSjEpUvZBdZLx7sUmgVGA7eQoDWZJkyZdrvGb4DvUojQgTpYN4Y+sasw==@sourceware.org X-Gm-Message-State: AFuF++mNIhSF3VzA6CtNAcn4OByeiTmYDIuvUtQ4UFk7FobTJBVI9gey dGIXJHbQ6avnUVphfH0/8IM8Khj6HNR8pnX6TiNT7fuk6qXVZyKl5ZojePZNhW4Io41Dj+5cxzy 8q6CEXwYrD9NUOFi6V4NOl3zkIie5km92UKYcrHSyi9SygnDu7cHnuD7H1RpyGNo= X-Gm-Gg: AYBFou1njExGcjjLnvxNbtVBtGBuRrk8hmOA9Ek25wPaq0MGuKialMQphZss93IvD4L ceS5pY0q+jx1McMSpILNQWYM4SH/G0f1IBig+dvVxftxTDCMnj/M3YlYmDNXkvGgG2nLn8BYiKw K4YjzNxD9Uh9nHHSCmUR2aGoOLQ04UtTzFasTjHstJjBHRDXTZ4w0LJ571C+NPdvVw5MibQXSL/ tibqNv9fLy3Vgbkbsz7XHrTJ32z93wAskvJipc1qwlOdkvtQ4lD6uDWvsWYViByBcD0AV5PBV6W ZIo+xGx8I13utZpdXie4J+Td0H6ujULeYCYgB7HFzgpjvDm7RrY6DyEHyXRiCXgUx28TSzxMHg3 VJvohwTMhPH+V9w3MP02NDblW X-Received: by 2002:a05:600d:8654:10b0:4a0:2391:6533 with SMTP id 5b1f17b1804b1-4a1815a2080mr79371405e9.21.1791488660738; Thu, 08 Oct 2026 12:44:20 -0700 (PDT) X-Received: by 2002:a05:600d:8654:10b0:4a0:2391:6533 with SMTP id 5b1f17b1804b1-4a1815a2080mr79370975e9.21.1791488659794; Thu, 08 Oct 2026 12:44:19 -0700 (PDT) Received: from localhost (92.40.184.240.threembb.co.uk. [92.40.184.240]) by smtp.gmail.com with ESMTPSA id 5b1f17b1804b1-4a18beacd2csm5401495e9.14.2026.10.08.12.44.18 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 08 Oct 2026 12:44:18 -0700 (PDT) From: Andrew Burgess To: Kirill Radkin , gdb-patches@sourceware.org Cc: Peter Bergner , Sergey Matyukevich , Jerry Zhang Jian , Heinrich Schuchardt , Palmer Dabbelt Subject: Re: [PATCH v2 1/3] RISC-V Vector Extension Support In-Reply-To: <20260925172947.403655-2-hokeygo@gmail.com> References: <20260925172947.403655-1-hokeygo@gmail.com> <20260925172947.403655-2-hokeygo@gmail.com> Date: Thu, 08 Oct 2026 20:44:16 +0100 Message-ID: <87tsmwt1tb.fsf@redhat.com> MIME-Version: 1.0 X-Mimecast-Spam-Score: 0 X-Mimecast-MFC-PROC-ID: akIGT7BWp-lx1rlmuNZ3OjAZ54_60hwLMoU1I4hohmc_1791488661 X-Mimecast-Originator: redhat.com Content-Type: text/plain 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 Kirill Radkin writes: > This patch adds support for the RISC-V Vector Extension (RVV) and the RISC-V > Vector ABI to GDB, for both gdb and gdbserver (so, it's available for cross and > native debugging). It is now possible to inspect and modify vector registers > directly. Furthermore, GDB supports evaluating variables with RISC-V vector > types (such as vint32m4_t) and calling functions that take vector arguments > using the print and call GDB commands. Patch also includes tests targeting RVV > support, tested on targets with different vlen (64, 128, 1024). Implementation > is tested on system QEMU (Linux) and on OpenOCD + spike configuration. Hi, 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. 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. > --- > 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 > > 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" > > #ifndef GDBSERVER > @@ -82,11 +83,9 @@ riscv_create_target_description (const struct riscv_gdbarch_features features) > else if (features.flen == 8) > regnum = create_feature_riscv_64bit_fpu (tdesc.get (), regnum); > > - /* Currently GDB only supports vector features coming from remote > - targets. We don't support creating vector features on native targets > - (yet). */ > - if (features.vlen != 0) > - error (_("unable to create vector feature")); > + if (features.vlenb != 0) > + regnum = create_feature_riscv_rvv (tdesc.get (), features.vlenb, > + features.xlen); > > 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 (with > 'Zve32*' extension), but GDB doesn't currently mind, and will accept any > vector size. */ > - int vlen = 0; > + int vlenb = 0; > > /* When true this target is RV32E. */ > bool embedded = false; > @@ -68,9 +68,8 @@ struct riscv_gdbarch_features > /* Equality operator. */ > bool operator== (const struct riscv_gdbarch_features &rhs) const > { > - return (xlen == rhs.xlen && flen == rhs.flen > - && embedded == rhs.embedded && vlen == rhs.vlen > - && has_fflags_reg == rhs.has_fflags_reg > + return (xlen == rhs.xlen && flen == rhs.flen && embedded == rhs.embedded > + && vlenb == rhs.vlenb && has_fflags_reg == rhs.has_fflags_reg > && has_frm_reg == rhs.has_frm_reg > && has_fcsr_reg == 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 = ((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 > + = ((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 == -1) > + continue; > + element_type = 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 = tdesc_create_union (feature, > + type_name); > + > + for (auto &&type_info : types_info) > + { > + if (type_info.element_count == -1) > + continue; > + element_type = 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 == 4 || xlen == 8); > + gdb_assert (vlenb >= 4 && ((vlenb & (vlenb - 1)) == 0)); > + > + int v_bitsize = 8 * vlenb; > + int x_bitsize = 8 * xlen; > + > + tdesc_feature *csr_feature = tdesc_create_feature (result, > + "org.gnu.gdb.riscv.csr"); > + tdesc_create_reg (csr_feature, "vstart", RISCV_CSR_VSTART_REGNUM, 1, NULL, > + x_bitsize, "int"); GDB now uses 'nullptr' instead of 'NULL', you'll need to change these throughout this patch. > + 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_bitsize, > + "int"); > + tdesc_create_reg (csr_feature, "vtype", RISCV_CSR_VTYPE_REGNUM, 1, NULL, > + x_bitsize, "int"); > + tdesc_create_reg (csr_feature, "vlenb", RISCV_CSR_VLENB_REGNUM, 1, NULL, > + x_bitsize, "int"); > + > + tdesc_feature *vector_feature > + = tdesc_create_feature (result, "org.gnu.gdb.riscv.vector"); > + > + std::vector elements_types_info > + = { { "int8", "i8", vlenb }, > + { "int16", "i16", vlenb / 2 }, > + { "int32", "i32", vlenb / 4 }, > + { "int64", "i64", (vlenb >= 8) ? vlenb / 8 : -1 }, > + { "ieee_half", "half", vlenb / 2 }, > + { "ieee_single", "f32", vlenb / 4 }, > + { "ieee_double", "f64", (vlenb >= 8) ? vlenb / 8 : -1 } }; > + > + create_vector_register_type (vector_feature, elements_types_info, "rvv"); > + > + int regnum = RISCV_V0_REGNUM; > + > + constexpr const char *vec_reg_names[] > + = { "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 = 0; i < 32; ++i) > + tdesc_create_reg (vector_feature, vec_reg_names[i], regnum++, 1, NULL, > + 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 mark > + func as dynamic to later resolve this dynamic type */ Comment missing full stop. > + if (type->target_type () > + && is_dynamic_type_internal_1 (type->target_type (), false)) > + return true; > + > + /* Same for function arguments */ Comment missing full stop. > + for (int i = 0; i < type->num_fields (); ++i) > + if (is_dynamic_type_internal_1 (type->field (i).type (), false)) > + return true; > + } > + break; > } > > return false; > @@ -2742,6 +2757,25 @@ resolve_dynamic_struct (struct type *type, > return resolved_type; > } > > +/* Resolve dynamic function's arguments/returned value types */ Comment missing full stop. Plus we usually leave a blank line between header comments and the function definition. > +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 () == TYPE_CODE_FUNC); > + > + struct type *resolved_type = copy_type (type); > + > + resolved_type->set_target_type (resolve_dynamic_type_internal ( > + type->target_type (), addr_stack, frame, top_level)); > + > + for (int i = 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. */ > > static struct type * > @@ -2840,6 +2874,13 @@ resolve_dynamic_type_internal (struct type *type, > case TYPE_CODE_STRUCT: > resolved_type = 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*/ Comment missing full stop. > + resolved_type = resolve_dynamic_func (type, addr_stack, frame, > + top_level); > + break; > } > } > > 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 GDB doesn't use '//' style comments. There are a number of these in this patch and they all need changing to /* ... */ style comments. > 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 > > +/* 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. */ > > struct riscv_gdbarch_features > @@ -78,5 +99,19 @@ riscv_linux_read_features (int tid) > break; > } > > + features.vlenb = 0; > + > + static struct riscv_hwprobe query[] = { { RISCV_HWPROBE_KEY_IMA_EXT_0, 0 } }; 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? > + > + /* All possible vector extensions depends on Zve32x, and it's availability is > + a minimum requirement. */ > + if ((syscall (NR_riscv_hwprobe, query, 1, 0, NULL, 0) == 0) > + && (query[0].value & RISCV_HWPROBE_EXT_ZVE32X)) > + { > + int reg = 0; > + asm volatile ("csrr %[vlenb], vlenb" : [vlenb] "=r"(reg)); Space missing before '(reg)'. > + features.vlenb = 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 @@ > > #include "elf/common.h" > > +#include "nat/riscv-linux-ptrace.h" > #include "nat/riscv-linux-tdesc.h" > > #include > @@ -132,6 +133,64 @@ supply_fpregset (struct regcache *regcache, const prfpregset_t *fpregs) > supply_fpregset_regnum (regcache, fpregs, -1); > } > > +static void > +supply_vecregset_regnum (regcache *regcache, > + const __riscv_v_regset_state *vecregs, int regnum) > +{ > + gdb_assert (vecregs->vlenb > 0); > + if ((regnum >= RISCV_V0_REGNUM && regnum <= RISCV_V31_REGNUM)) > + { > + regcache->raw_supply (regnum, > + vecregs->vreg > + + vecregs->vlenb * (regnum - RISCV_V0_REGNUM)); > + return; > + } > + > + if (regnum == RISCV_CSR_VSTART_REGNUM) > + { > + regcache->raw_supply (regnum, &vecregs->vstart); > + return; > + } > + > + if (regnum == RISCV_CSR_VCSR_REGNUM) > + { > + regcache->raw_supply (regnum, &vecregs->vcsr); > + return; > + } > + > + if (regnum == RISCV_CSR_VL_REGNUM) > + { > + regcache->raw_supply (regnum, &vecregs->vl); > + return; > + } > + > + if (regnum == RISCV_CSR_VTYPE_REGNUM) > + { > + regcache->raw_supply (regnum, &vecregs->vtype); > + return; > + } > + > + if (regnum == RISCV_CSR_VLENB_REGNUM) > + { > + regcache->raw_supply (regnum, &vecregs->vlenb); > + return; > + } > + > + if (regnum == -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 = RISCV_V0_REGNUM; i <= 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 == -1) > from REGCACHE into regset GREGS. */ > > @@ -195,6 +254,64 @@ fill_fpregset (const struct regcache *regcache, prfpregset_t *fpregs, > } > } > > +static void > +fill_vecregset_regnum (regcache *regcache, __riscv_v_regset_state *vecregs, > + int regnum) > +{ > + if ((regnum >= RISCV_V0_REGNUM && regnum <= RISCV_V31_REGNUM)) > + { > + regcache->raw_collect (regnum, > + vecregs->vreg > + + vecregs->vlenb * (regnum - RISCV_V0_REGNUM)); > + return; > + } > + > + if (regnum == RISCV_CSR_VSTART_REGNUM) > + { > + regcache->raw_collect (regnum, &vecregs->vstart); > + return; > + } > + > + if (regnum == RISCV_CSR_VCSR_REGNUM) > + { > + regcache->raw_collect (regnum, &vecregs->vcsr); > + return; > + } > + > + if (regnum == RISCV_CSR_VL_REGNUM) > + { > + regcache->raw_collect (regnum, &vecregs->vl); > + return; > + } > + > + if (regnum == RISCV_CSR_VTYPE_REGNUM) > + { > + regcache->raw_collect (regnum, &vecregs->vtype); > + return; > + } > + > + if (regnum == RISCV_CSR_VLENB_REGNUM) > + { > + regcache->raw_collect (regnum, &vecregs->vlenb); > + return; > + } > + > + if (regnum == -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 = RISCV_V0_REGNUM; i <= 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. */ > > const struct target_desc * > @@ -261,6 +378,29 @@ riscv_linux_nat_target::fetch_registers (struct regcache *regcache, int regnum) > regcache->raw_supply_zeroed (RISCV_CSR_MISA_REGNUM); > } > > + if (riscv_is_vpr_or_vcsr (regnum) || (regnum == -1)) > + { > + int vecreg_size = register_size (regcache->arch (), RISCV_V0_REGNUM); > + std::vector vregs_buff (sizeof (__riscv_v_regset_state) > + + vecreg_size * 32); > + > + __riscv_v_regset_state *vregs_state > + = (__riscv_v_regset_state *) vregs_buff.data (); > + > + iovec iov; > + iov.iov_base = vregs_state; > + iov.iov_len = sizeof (struct __riscv_v_regset_state) + 32 * vecreg_size; > + > + if (ptrace (PTRACE_GETREGSET, tid, NT_RISCV_VECTOR, > + (PTRACE_TYPE_ARG3) &iov) > + == 0 > + && vregs_state->vlenb > 0) > + { > + gdb_assert (vregs_state->vlenb == vecreg_size); > + supply_vecregset_regnum (regcache, vregs_state, regnum); > + } > + } > + > /* Access to other CSRs has potential security issues, don't support them for > now. */ > } > @@ -323,6 +463,30 @@ riscv_linux_nat_target::store_registers (struct regcache *regcache, int regnum) > } > } > > + if (riscv_is_vpr_or_vcsr (regnum) || (regnum == -1)) > + { > + int vecreg_size = register_size (regcache->arch (), RISCV_V0_REGNUM); > + std::vector vregs_buff (sizeof (__riscv_v_regset_state) > + + vecreg_size * 32); > + > + __riscv_v_regset_state *vregs_state > + = (__riscv_v_regset_state *) vregs_buff.data (); > + > + iovec iov; > + iov.iov_base = vregs_state; > + iov.iov_len = sizeof (struct __riscv_v_regset_state) + 32 * vecreg_size; > + > + if (ptrace (PTRACE_GETREGSET, tid, NT_RISCV_VECTOR, > + (PTRACE_TYPE_ARG3) &iov) > + == 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 = 0, /* Read-only register, always 0. */ > + RISCV_RA_REGNUM = 1, /* Return Address. */ > + RISCV_SP_REGNUM = 2, /* Stack Pointer. */ > + RISCV_GP_REGNUM = 3, /* Global Pointer. */ > + RISCV_TP_REGNUM = 4, /* Thread Pointer. */ > + RISCV_FP_REGNUM = 8, /* Frame Pointer. */ > + RISCV_A0_REGNUM = 10, /* First argument. */ > + RISCV_A1_REGNUM = 11, /* Second argument. */ > + RISCV_A2_REGNUM = 12, /* Third argument. */ > + RISCV_A3_REGNUM = 13, /* Forth argument. */ > + RISCV_A4_REGNUM = 14, /* Fifth argument. */ > + RISCV_A5_REGNUM = 15, /* Sixth argument. */ > + RISCV_A7_REGNUM = 17, /* Register to pass syscall number. */ > + RISCV_PC_REGNUM = 32, /* Program Counter. */ > + > + RISCV_NUM_INTEGER_REGS = 32, > + > + RISCV_FIRST_FP_REGNUM = 33, /* First Floating Point Register */ > + RISCV_FA0_REGNUM = 43, > + RISCV_FA1_REGNUM = RISCV_FA0_REGNUM + 1, > + RISCV_LAST_FP_REGNUM = 64, /* Last Floating Point Register */ > + > + RISCV_FIRST_CSR_REGNUM = 65, /* First CSR */ > +#define DECLARE_CSR(name, num, class, define_version, abort_version) \ > + RISCV_##num##_REGNUM = RISCV_FIRST_CSR_REGNUM + num, > +#include "opcode/riscv-opc.h" > +#undef DECLARE_CSR > + RISCV_LAST_CSR_REGNUM = 4160, > + RISCV_CSR_LEGACY_MISA_REGNUM = 0xf10 + RISCV_FIRST_CSR_REGNUM, > + > + RISCV_PRIV_REGNUM = 4161, > + > + RISCV_V0_REGNUM, > + > + RISCV_V31_REGNUM = RISCV_V0_REGNUM + 31, > + > + RISCV_LAST_REGNUM = RISCV_V31_REGNUM > +}; > + > +/* RiscV DWARF register numbers. */ > +enum > +{ > + RISCV_DWARF_REGNUM_X0 = 0, > + RISCV_DWARF_REGNUM_X31 = 31, > + RISCV_DWARF_REGNUM_F0 = 32, > + RISCV_DWARF_REGNUM_F31 = 63, > + RISCV_DWARF_REGNUM_V0 = 96, > + RISCV_DWARF_REGNUM_V31 = 127, > + RISCV_DWARF_FIRST_CSR = 4096, > + RISCV_DWARF_LAST_CSR = 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" > > +#include > +#include > +#include > +#include > +#include > +#include > #include > > /* 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 >= RISCV_V0_REGNUM > - && regnum <= RISCV_V0_REGNUM + 31); > - regnum -= RISCV_V0_REGNUM; > - return m_registers[regnum].names[0]; > + gdb_assert (regnum >= RISCV_V0_REGNUM && regnum <= RISCV_V0_REGNUM + 31); > + > + const auto reg_info_it = std::find_if (m_registers.begin (), > + m_registers.end (), > + [regnum] (const auto ®_info) { > + return reg_info.regnum == regnum; > + }); > + if (reg_info_it == m_registers.end ()) > + gdb_assert_not_reached ("Incorrect vector register number %d", regnum); > + return reg_info_it->names.front (); > } > > /* Check this feature within TDESC, record the registers from this > @@ -679,7 +691,7 @@ struct riscv_vector_feature : public riscv_register_feature > feature set and return. */ > if (feature_vector == nullptr) > { > - features->vlen = 0; > + features->vlenb = 0; > return true; > } > > @@ -696,6 +708,9 @@ struct riscv_vector_feature : public riscv_register_feature > int vector_bitsize = -1; > for (const auto ® : m_registers) > { > + if (reg.regnum < RISCV_V0_REGNUM || reg.regnum > RISCV_V31_REGNUM) > + continue; > + > int reg_bitsize = -1; > for (const char *name : reg.names) > { > @@ -712,7 +727,7 @@ struct riscv_vector_feature : public riscv_register_feature > return false; > } > > - features->vlen = (vector_bitsize / 8); > + features->vlenb = (vector_bitsize / 8); > return true; > } > }; > @@ -793,6 +808,58 @@ riscv_abi_xlen (struct gdbarch *gdbarch) > > /* See riscv-tdep.h. */ > > +int > +riscv_isa_vlenb (struct gdbarch *gdbarch) > +{ > + riscv_gdbarch_tdep *tdep = 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 >= RISCV_V0_REGNUM && regno <= RISCV_V31_REGNUM); > +} > + > +/* Return true if REGNO is a vector CSR. */ > + > +static bool > +riscv_is_vector_rw_csr (int regno) > +{ > + return (regno == RISCV_CSR_VSTART_REGNUM || regno == RISCV_CSR_VCSR_REGNUM > + || regno == RISCV_CSR_VL_REGNUM || regno == RISCV_CSR_VTYPE_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 = 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 *gdbarch, > static bool > riscv_cannot_store_register (struct gdbarch *gdbarch, int regnum) > { > - return regnum == RISCV_ZERO_REGNUM; > + return regnum == RISCV_ZERO_REGNUM || regnum == RISCV_CSR_VLENB_REGNUM; > } > > /* Construct a type for 64-bit FP registers. */ > @@ -1200,7 +1267,7 @@ riscv_print_one_register_info (struct gdbarch *gdbarch, > { > riscv_gdbarch_tdep *tdep = gdbarch_tdep (gdbarch); > > - /* Print the register in hex. */ > + /* Print the register in hex, exclude vector registers. */ > value_print_options opts = get_formatted_print_options ('x'); > opts.deref_ref = true; > common_val_print (val, file, 0, opts, current_language); > @@ -1330,17 +1397,46 @@ riscv_print_one_register_info (struct gdbarch *gdbarch, > else > gdb_printf (file, "\tprv:%d [INVALID]", priv); > } > - else > + else if (regnum == RISCV_CSR_VTYPE_REGNUM) > { > - /* If not a vector register, print it also according to its > - natural format. */ > - if (regtype->is_vector () == 0) > - { > - opts = get_user_print_options (); > - opts.deref_ref = true; > - gdb_printf (file, "\t"); > - common_val_print (val, file, 0, opts, current_language); > - } > + LONGEST d = value_as_long (val); > + // Values are decoded according to RISC-V Vector Specification > + unsigned lmul_val = d & 0x7; > + const char *decoded_lmul_variants[] > + = { "1", "2", "4", "8", "Reserved", "1/8", "1/4", "1/2" }; > + unsigned sew_val = (d >> 3) & 0x7; > + const char *decoded_sew_variants[] = { "e8", "e16", > + "e32", "e64", > + "Reserved", "Reserved", > + "Reserved", "Reserved" }; > + unsigned vta = (d >> 6) & 0x1; > + const char *decoded_vta_variants[] = { "tu", "ta" }; > + unsigned vma = (d >> 7) & 0x1; > + const char *decoded_vma_variants[] = { "mu", "ma" }; > + int size = register_size (gdbarch, regnum); > + unsigned xlen = size * 8; > + unsigned vill = (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 == RISCV_CSR_VCSR_REGNUM) > + { > + LONGEST d = value_as_long (val); > + unsigned vxsat = d & 1; > + unsigned vxrm = (d >> 1) & 0b11; > + gdb_printf (file, "\tVXSAT:%u VXRM:%u", vxsat, vxrm); > + } > + else if (regtype->is_vector () == 0) > + { > + opts = get_user_print_options (); > + opts.deref_ref = true; > + gdb_printf (file, "\t"); > + common_val_print (val, file, 0, opts, current_language); > } > } > } > @@ -1433,21 +1529,22 @@ riscv_register_reggroup_p (struct gdbarch *gdbarch, int regnum, > return false; > } > else if (reggroup == float_reggroup) > - return (riscv_is_fp_regno_p (regnum) > - || regnum == RISCV_CSR_FCSR_REGNUM > - || regnum == tdep->fflags_regnum > - || regnum == tdep->frm_regnum); > + return (riscv_is_fp_regno_p (regnum) || regnum == RISCV_CSR_FCSR_REGNUM > + || regnum == tdep->fflags_regnum || regnum == tdep->frm_regnum); > else if (reggroup == general_reggroup) > return regnum < RISCV_FIRST_FP_REGNUM; > else if (reggroup == restore_reggroup || reggroup == save_reggroup) > { > if (riscv_has_fp_regs (gdbarch)) > - return (regnum <= RISCV_LAST_FP_REGNUM > - || regnum == RISCV_CSR_FCSR_REGNUM > - || regnum == tdep->fflags_regnum > - || regnum == tdep->frm_regnum); > - else > - return regnum < RISCV_FIRST_FP_REGNUM; > + if (riscv_is_fp_regno_p (regnum) || regnum == RISCV_CSR_FCSR_REGNUM > + || regnum == tdep->fflags_regnum || regnum == 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 == system_reggroup || reggroup == csr_reggroup) > { > @@ -1460,7 +1557,7 @@ riscv_register_reggroup_p (struct gdbarch *gdbarch, int regnum, > return false; > } > else if (reggroup == vector_reggroup) > - return (regnum >= RISCV_V0_REGNUM && regnum <= 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 registers.) > + The first register in the sequence of registers (used for passing > + arguments) is passed through the first location (see the comment above > + struct location), and the last one is passed through the second > + location. */ > + in_several_regs, > > - /* Argument passed as an on stack argument. */ > - on_stack, > + /* Argument passed as an on stack argument. */ > + on_stack, > > - /* 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; > > /* Information that depends on the location type. */ > union > @@ -2712,6 +2816,90 @@ struct riscv_arg_reg > int last_regnum; > }; > > +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 = 1) > + { > + gdb_assert (count % NFIELDS == 0); > + > + int LMUL = count / NFIELDS; > + for (auto cur_interval = available_intervals.begin (); > + cur_interval != available_intervals.end (); ++cur_interval) > + { > + int cur_first = cur_interval->first; > + int cur_last = cur_interval->last; > + if ((cur_first - RISCV_V0_REGNUM) % LMUL > + != 0) /* According to RISC-V Vector ABI, > + first register number should be > + a multiple of LMUL */ > + { > + cur_first -= (cur_first - RISCV_V0_REGNUM) % LMUL; > + cur_first += LMUL; > + } > + > + if ((cur_last - cur_first + 1) >= count) > + { > + if (cur_first > cur_interval->first) > + { > + available_intervals.insert (cur_interval, > + { cur_interval->first, > + cur_first - 1 }); > + } > + > + cur_interval->first = 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 = true; > + return RISCV_V0_REGNUM; > + } > + } > + > + bool is_v0_used = false; > + > + std::list available_intervals; > + > + /* From 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, starting > + from the v8 register, if a vector register group between v8-v23 that 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 argument > + and mark these registers as allocated. Otherwise, pass it by reference and > + are replaced in the 12 argument list with the address. > + 3. For tuple vector data arguments, starting from the v8 register, if > + NFIELDS consecutive vector register groups between v8-v23 that have not > + been allocated can be found and the first register number is a multiple of > + LMUL, then allocate these vector register groups to the argument and mark > + these registers as allocated. Otherwise, pass it by reference and are > + 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 = riscv_abi_xlen (gdbarch); > flen = riscv_abi_flen (gdbarch); > + /* According to the RVV specification, a binary file does not require > + 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 = riscv_isa_vlenb (gdbarch); > > /* 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 = float_regs.last_regnum + 1; > + > + /* Disable use of vector registers if needed. */ > + if (!riscv_has_vector_abi (gdbarch)) > + vector_regs.available_intervals.clear (); > } > > /* 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; > > + /* 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, and > are just the results of calling RISCV_ABI_XLEN and RISCV_ABI_FLEN. */ > int xlen; > int flen; > + int vlenb; > }; > > /* 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; > } > > +struct rvv_type_info > +{ > + /* Selected Element Width. For RVV_BOOL types, this field holds EEW/EMUL > + value, encoded into the type. */ > + enum class rvv_sew_t : int > + { > + SEW8 = 8, > + SEW16 = 16, > + SEW32 = 32, > + SEW64 = 64, > + SEW_UNKNOWN, > + } sew = rvv_sew_t::SEW_UNKNOWN; > + > + /* Length Multiplier, amount of registers used for this type. */ > + enum class rvv_lmul_t : int > + { > + LMUL1 = 1, > + LMUL2 = 2, > + LMUL4 = 4, > + LMUL8 = 8, > + LMUL_UNKNOWN, > + } lmul = rvv_lmul_t::LMUL_UNKNOWN; > + > + /* For non-tuple types, nfield = 1. */ > + enum class rvv_nfield_t : int > + { > + NFIELD1 = 1, > + NFIELD2, > + NFIELD3, > + NFIELD4, > + NFIELD5, > + NFIELD6, > + NFIELD7, > + NFIELD8, > + NFIELD_UNKNOWN, > + } nfield = rvv_nfield_t::NFIELD_UNKNOWN; > + > + enum class rvv_elem_t : char > + { > + RVV_INT, > + RVV_UINT, > + RVV_FLOAT, > + RVV_BOOL, > + RVV_UNKNOWN, > + } element_type = rvv_elem_t::RVV_UNKNOWN; > + > + /* is_fractional_lmul means, that used only part of a vector > + register. For example, if lmul = 2 and is_fractional_lmul = > + true it means that used a half of a register. */ > + bool is_fractional_lmul = false; > +}; > + > +struct rvv_type_name_mapping_t > +{ > + const char *name; > + rvv_type_info::rvv_elem_t type; > +}; > + > +static constexpr std::array rvv_type_names = { > + 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_FLOAT }, > + 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 != rvv_type_info::rvv_lmul_t::LMUL_UNKNOWN); > + gdb_assert (sew != 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) <= 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 == rvv_type_info::rvv_lmul_t::LMUL1 > + && type_info.is_fractional_lmul) > + return false; > + > + /* Restriction from RISC-V Vector Specification: LMUL * NFIELDS <= 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 != rvv_type_info::rvv_sew_t::SEW16 > + && type_info.sew != rvv_type_info::rvv_sew_t::SEW32 > + && type_info.sew != rvv_type_info::rvv_sew_t::SEW64) > + return false; > + > + /* For float types at least LMUL = 1/4 is required. */ > + if (type_info.lmul == rvv_type_info::rvv_lmul_t::LMUL8 > + && type_info.is_fractional_lmul) > + return false; > + > + /* rvv_spec_requirement condition applies only to types with fractional > + LMUL. */ > + if (!type_info.is_fractional_lmul) > + return true; > + > + return supported_fractional_sew_lmul (type_info.lmul, type_info.sew); > + > + 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 != rvv_type_info::rvv_sew_t::SEW8 > + && type_info.sew != rvv_type_info::rvv_sew_t::SEW16 > + && type_info.sew != rvv_type_info::rvv_sew_t::SEW32 > + && type_info.sew != rvv_type_info::rvv_sew_t::SEW64) > + return false; > + > + /* rvv_spec_requirement condition applies only to types with fractional > + LMUL. */ > + if (!type_info.is_fractional_lmul) > + return true; > + > + return supported_fractional_sew_lmul (type_info.lmul, type_info.sew); > + > + case rvv_type_info::rvv_elem_t::RVV_BOOL: > + /* These restrictions do not follow from the specification, but from the > + internal constraints of the structure of rvv_type_info. */ > + return (type_info.lmul == rvv_type_info::rvv_lmul_t::LMUL1 > + && type_info.nfield == rvv_type_info::rvv_nfield_t::NFIELD1 > + && !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 = [] (const std::string &a, > + const rvv_type_name_mapping_t &b) { > + return a + "|" + std::string (b.name); > + }; > + std::string accumulator > + = 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 = 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 = static_cast (g); > + const auto &sm = matches[index]; > + return std::string_view (sm.first, sm.length ()); > + } > + > +private: > + parsed_rvv_type_t () = default; > + std::cmatch matches; > + inline static const std::regex rvv_type_regex = get_rvv_type_regex (); > +}; > + > +static std::optional > +get_rvv_type_info_unverified (struct type *type) > +{ > + if (!type) > + return std::nullopt; > + > + type = 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 () != TYPE_CODE_ARRAY && type->code () != 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 = 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 = parsed_rvv_type_holder.value (); > + rvv_type_info res; > + > + auto it = 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) > + == 0; > + }); > + if (it == 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 = it->type; > + > + if (auto sew_val = parse_integer ( > + parsed_rvv_type.get (parsed_rvv_type_t::group::sew))) > + { > + res.sew = static_cast (sew_val.value ()); > + } > + else > + { > + std::string_view sew_str > + = 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") > + == 0) > + res.is_fractional_lmul = true; > + else > + res.is_fractional_lmul = false; > + > + if (auto lmul_val = parse_integer ( > + parsed_rvv_type.get (parsed_rvv_type_t::group::lmul_val))) > + { > + res.lmul > + = static_cast (lmul_val.value ()); > + } > + else > + { > + std::string_view lmul_str > + = 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 = rvv_type_info::rvv_lmul_t::LMUL1; > + res.is_fractional_lmul = false; > + } > + > + if (!parsed_rvv_type.get (parsed_rvv_type_t::group::nfield_str).empty ()) > + { > + if (auto nfield_val = parse_integer ( > + parsed_rvv_type.get (parsed_rvv_type_t::group::nfield_val))) > + { > + res.nfield > + = static_cast (nfield_val.value ()); > + } > + else > + { > + std::string_view nfield_str > + = 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 = rvv_type_info::rvv_nfield_t::NFIELD1; > + > + return res; > +} > + > +static std::optional > +get_rvv_type_info (struct type *type) > +{ > + std::optional res = get_rvv_type_info_unverified (type); > + > + 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 = vlenb; /* Amount of data that is stored on one register */ > + > + struct riscv_arg_info::location *loc0 = &ainfo->argloc[0]; > + struct riscv_arg_info::location *loc1 = &ainfo->argloc[1]; > + > + rvv_type_info arg_type_info; > + if (std::optional res = get_rvv_type_info (func_arg_type)) > + arg_type_info = 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 = %d, sew = %u, lmul = %u (%s " > + "fractional), nfield = %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 = ((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 = static_cast (arg_type_info.nfield); > + data_length = data_length / static_cast (arg_type_info.lmul); > + } > + > + int first_regnum = -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 () == TYPE_CODE_ARRAY) > + { > + if (ainfo->type->target_type ()->code () == TYPE_CODE_BOOL) > + first_regnum = reg->try_use_v0 (); > + else > + first_regnum > + = reg->get_interval_start (num_required_regs, > + static_cast (arg_type_info.nfield)); > + } > + else if (ainfo->type->code () == TYPE_CODE_STRUCT) > + { > + first_regnum > + = reg->get_interval_start (num_required_regs, > + static_cast (arg_type_info.nfield)); > + } > + > + if (first_regnum == -1) > + return false; > + > + int last_regnum = first_regnum + num_required_regs - 1; > + > + loc0->loc_type = riscv_arg_info::location::in_several_regs; > + loc0->loc_data.regno = first_regnum; > + loc0->c_length = data_length; > + loc0->c_offset = 0; > + > + loc1->loc_type = riscv_arg_info::location::in_several_regs; > + loc1->loc_data.regno = last_regnum; > + loc1->c_length = 0; > + loc1->c_offset = 0; > + > + return true; > +} > + > /* Assign LOC a location as the next stack parameter, and update MEMORY to > 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 *ainfo, > riscv_call_arg_scalar_int (ainfo, cinfo); > } > > +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 = riscv_arg_info::location::by_ref; > + cinfo->memory.ref_offset = align_up (cinfo->memory.ref_offset, > + ainfo->align); > + ainfo->argloc[0].loc_data.offset = cinfo->memory.ref_offset; > + cinfo->memory.ref_offset += ainfo->length; > + ainfo->argloc[0].c_length = ainfo->length; > + > + if (!riscv_assign_reg_location (&ainfo->argloc[1], &cinfo->int_regs, > + 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 parameter in > + its declaration. > > After assigning a location to AINFO, CINFO will have been updated. */ > > 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 *ainfo, > + struct riscv_call_info *cinfo, struct type *type, > + struct type *func_arg_type, bool is_unnamed) > { > ainfo->type = type; > ainfo->length = ainfo->type->length (); > @@ -3253,6 +3883,12 @@ riscv_arg_location (struct gdbarch *gdbarch, > ainfo->argloc[0].c_length = 0; > ainfo->argloc[1].c_length = 0; > > + if (is_rvv_type (func_arg_type)) /* for RISC_V vector registers */ 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. > + { > + 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 gdbarch *gdbarch, > } > break; > > + 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 = 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 ()); > } > > /* 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 = &arg_info[i]; > > arg_value = args[i]; > arg_type = check_typedef (arg_value->type ()); > > - riscv_arg_location (gdbarch, info, &call_info, arg_type, > + func_arg_type = (i < ftype->num_fields ()) ? ftype->field (i).type () > + : nullptr; > + > + riscv_arg_location (gdbarch, info, &call_info, arg_type, func_arg_type, > ftype->has_varargs () && i >= ftype->num_fields ()); > > if (info->type != arg_type) > arg_value = value_cast (info->type, arg_value); > + > info->contents = arg_value->contents ().data (); > } > > @@ -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 == 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 = 0; i < nargs; ++i) > { > struct riscv_arg_info *info = &arg_info [i]; > @@ -3538,6 +4189,22 @@ riscv_push_dummy_call (struct gdbarch *gdbarch, > second_arg_data = (gdb_byte *) &dst; > break; > > + case riscv_arg_info::location::in_several_regs: > + { > + const gdb_byte *cur_contents = info->contents; > + int cur_c_length = info->argloc[0].c_length; > + for (int cur_regno = info->argloc[0].loc_data.regno; > + cur_regno <= 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 += cur_c_length; > + } > + second_arg_length = 0; > + } > + break; > + > default: > gdb_assert_not_reached ("unknown argument location type"); > } > @@ -3568,6 +4235,8 @@ riscv_push_dummy_call (struct gdbarch *gdbarch, > } > > case riscv_arg_info::location::by_ref: > + case riscv_arg_info::location:: > + in_several_regs: /* We shouldn't get here for this case*/ 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? > 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; > > arg_type = check_typedef (type); > - riscv_arg_location (gdbarch, &info, &call_info, arg_type, false); > + func_retval_type = (function && function->type ()) > + ? function->type ()->target_type () > + : nullptr; > + riscv_arg_location (gdbarch, &info, &call_info, arg_type, func_retval_type, > + false); > > if (riscv_debug_infcall) > { > @@ -3761,6 +4435,38 @@ riscv_return_value (struct gdbarch *gdbarch, > } > break; > > + case riscv_arg_info::location::in_several_regs: > + { > + int first_regnum = info.argloc[0].loc_data.regno; > + int last_regnum = info.argloc[1].loc_data.regno; > + > + gdb_byte *tmp_readbuf = readbuf; > + const gdb_byte *tmp_writebuf = writebuf; > + > + for (int cur_regnum = first_regnum; cur_regnum <= last_regnum; > + cur_regnum++) > + { > + if (readbuf) > + { > + gdb_byte *ptr = tmp_readbuf + info.argloc[0].c_offset; > + regcache->cooked_read_part (cur_regnum, 0, > + info.argloc[0].c_length, ptr); > + tmp_readbuf += info.argloc[0].c_length; > + } > + > + if (writebuf) > + { > + const gdb_byte *ptr = 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 += 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_frame_unwind ( > /*.prev_arch =*/ NULL > ); > > +static bool > +riscv_search_extension_in_march (std::string_view march, > + std::string_view extension) > +{ > + std::string regex_string = "_" + 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. */ > > @@ -3963,6 +4681,31 @@ riscv_features_from_bfd (const bfd *abfd) > } > features.embedded = true; > } > + > + obj_attribute *obj_attr = elf_known_obj_attributes_proc (abfd); > + const char *march = obj_attr[Tag_RISCV_arch].s; > + if (march) > + { > + /* According to the RVV specification, a binary file does not require > + any particular vlenb value. Therefore, we used minimal vlenb value > + to indicate that the vector ABI is in use. Additionally, a valid > + vlenb value is required here, as it will be used later to create a > + default target description. */ > + std::string_view march_str (march); > + if (riscv_search_extension_in_march (march_str, "v")) > + features.vlenb = 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 = 8; > + else if (riscv_search_extension_in_march (march_str, "zve32x") > + || riscv_search_extension_in_march (march_str, "zve32f")) > + features.vlenb = 4; > + else > + features.vlenb = 0; > + } > + else > + features.vlenb = 0; > } > > 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); > > + /* Look at riscv_features_from_bfd*/ Comment missing full stop. > + if ((abi_features.vlenb > 0) && (features.vlenb == 0)) > + { > + warning (_ ("bfd requires non-zero vlenb, but target has vlenb = 0, " 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 :) > + "vector registers unsupported")); > + } > + > /* Find a candidate among the list of pre-declared architectures. */ > for (arches = gdbarch_list_lookup_by_info (arches, &info); > arches != NULL; > @@ -5468,3 +6218,13 @@ riscv_process_record (struct gdbarch *gdbarch, struct regcache *regcache, > > return 0; > } > + > +bool > +riscv_is_vpr_or_vcsr (unsigned regnum) > +{ > + return (regnum >= RISCV_V0_REGNUM && regnum <= RISCV_V0_REGNUM + 31) > + || regnum == RISCV_CSR_VSTART_REGNUM > + || regnum == RISCV_CSR_VCSR_REGNUM || regnum == RISCV_CSR_VL_REGNUM > + || regnum == RISCV_CSR_VTYPE_REGNUM > + || regnum == 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 @@ > > #include "arch/riscv.h" > #include "gdbarch.h" > - > -/* RiscV register numbers. */ > -enum > -{ > - RISCV_ZERO_REGNUM = 0, /* Read-only register, always 0. */ > - RISCV_RA_REGNUM = 1, /* Return Address. */ > - RISCV_SP_REGNUM = 2, /* Stack Pointer. */ > - RISCV_GP_REGNUM = 3, /* Global Pointer. */ > - RISCV_TP_REGNUM = 4, /* Thread Pointer. */ > - RISCV_FP_REGNUM = 8, /* Frame Pointer. */ > - RISCV_A0_REGNUM = 10, /* First argument. */ > - RISCV_A1_REGNUM = 11, /* Second argument. */ > - RISCV_A2_REGNUM = 12, /* Third argument. */ > - RISCV_A3_REGNUM = 13, /* Forth argument. */ > - RISCV_A4_REGNUM = 14, /* Fifth argument. */ > - RISCV_A5_REGNUM = 15, /* Sixth argument. */ > - RISCV_A7_REGNUM = 17, /* Register to pass syscall number. */ > - RISCV_PC_REGNUM = 32, /* Program Counter. */ > - > - RISCV_NUM_INTEGER_REGS = 32, > - > - RISCV_FIRST_FP_REGNUM = 33, /* First Floating Point Register */ > - RISCV_FA0_REGNUM = 43, > - RISCV_FA1_REGNUM = RISCV_FA0_REGNUM + 1, > - RISCV_LAST_FP_REGNUM = 64, /* Last Floating Point Register */ > - > - RISCV_FIRST_CSR_REGNUM = 65, /* First CSR */ > -#define DECLARE_CSR(name, num, class, define_version, abort_version) \ > - RISCV_ ## num ## _REGNUM = RISCV_FIRST_CSR_REGNUM + num, > -#include "opcode/riscv-opc.h" > -#undef DECLARE_CSR > - RISCV_LAST_CSR_REGNUM = 4160, > - RISCV_CSR_LEGACY_MISA_REGNUM = 0xf10 + RISCV_FIRST_CSR_REGNUM, > - > - RISCV_PRIV_REGNUM = 4161, > - > - RISCV_V0_REGNUM, > - > - RISCV_V31_REGNUM = RISCV_V0_REGNUM + 31, > - > - RISCV_LAST_REGNUM = RISCV_V31_REGNUM > -}; > - > -/* RiscV DWARF register numbers. */ > -enum > -{ > - RISCV_DWARF_REGNUM_X0 = 0, > - RISCV_DWARF_REGNUM_X31 = 31, > - RISCV_DWARF_REGNUM_F0 = 32, > - RISCV_DWARF_REGNUM_F31 = 63, > - RISCV_DWARF_REGNUM_V0 = 96, > - RISCV_DWARF_REGNUM_V31 = 127, > - RISCV_DWARF_FIRST_CSR = 4096, > - RISCV_DWARF_LAST_CSR = 8191, > -}; > +#include "riscv-regs.h" > > /* 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); > > +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 reflects > 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); > > +extern int riscv_abi_vlenb (struct gdbarch *gdbarch); This function is never defined, please delete this declaration. Thanks, Andrew