From: Andrew Burgess <aburgess@redhat.com>
To: Kirill Radkin <hokeygo@gmail.com>, gdb-patches@sourceware.org
Cc: Peter Bergner <bergner@oss.tenstorrent.com>,
Sergey Matyukevich <geomatsi@gmail.com>,
Jerry Zhang Jian <jerry.zhangjian@sifive.com>,
Heinrich Schuchardt <heinrich.schuchardt@canonical.com>,
Palmer Dabbelt <palmer@dabbelt.com>
Subject: Re: [PATCH v2 1/3] RISC-V Vector Extension Support
Date: Thu, 08 Oct 2026 20:44:16 +0100 [thread overview]
Message-ID: <87tsmwt1tb.fsf@redhat.com> (raw)
In-Reply-To: <20260925172947.403655-2-hokeygo@gmail.com>
Kirill Radkin <hokeygo@gmail.com> 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 <http://www.gnu.org/licenses/>. */
> +
> +#include "gdbsupport/gdb_assert.h"
> +#include "gdbsupport/tdesc.h"
> +#include "gdb/riscv-regs.h"
> +#include <vector>
> +
> +/* 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<vector_field_type_info> &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<vector_field_type_info> 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 <http://www.gnu.org/licenses/>. */
> +
> +#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 <sys/ptrace.h>
> @@ -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<char> 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<char> 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 <http://www.gnu.org/licenses/>. */
> +
> +#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 <array>
> +#include <charconv>
> +#include <list>
> +#include <numeric>
> +#include <optional>
> +#include <regex>
> #include <vector>
>
> /* 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<riscv_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<riscv_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<riscv_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<riscv_vector_arg_reg_interval> 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_name_mapping_t, 4> 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<int> (lmul) * static_cast<int> (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<int> (type_info.lmul)
> + * static_cast<int> (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<parsed_rvv_type_t> 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<long unsigned> (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<rvv_type_info>
> +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<unsigned> (
> + parsed_rvv_type.get (parsed_rvv_type_t::group::sew)))
> + {
> + res.sew = static_cast<rvv_type_info::rvv_sew_t> (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<int> (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<unsigned> (
> + parsed_rvv_type.get (parsed_rvv_type_t::group::lmul_val)))
> + {
> + res.lmul
> + = static_cast<rvv_type_info::rvv_lmul_t> (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<int> (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<unsigned> (
> + parsed_rvv_type.get (parsed_rvv_type_t::group::nfield_val)))
> + {
> + res.nfield
> + = static_cast<rvv_type_info::rvv_nfield_t> (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<int> (nfield_str.size ()), nfield_str.data ());
> + return std::nullopt;
> + }
> + }
> + else
> + res.nfield = rvv_type_info::rvv_nfield_t::NFIELD1;
> +
> + return res;
> +}
> +
> +static std::optional<rvv_type_info>
> +get_rvv_type_info (struct type *type)
> +{
> + std::optional<rvv_type_info> 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<rvv_type_info> 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<int> (arg_type_info.element_type),
> + static_cast<int> (arg_type_info.sew),
> + static_cast<int> (arg_type_info.lmul),
> + (arg_type_info.is_fractional_lmul ? "is" : "is not"),
> + static_cast<int> (arg_type_info.nfield));
> +
> + int num_required_regs = ((arg_type_info.is_fractional_lmul)
> + ? 1
> + : static_cast<int> (arg_type_info.lmul))
> + * static_cast<int> (arg_type_info.nfield);
> +
> + if (arg_type_info.is_fractional_lmul)
> + {
> + num_required_regs = static_cast<int> (arg_type_info.nfield);
> + data_length = data_length / static_cast<int> (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<int> (arg_type_info.nfield));
> + }
> + else if (ainfo->type->code () == TYPE_CODE_STRUCT)
> + {
> + first_regnum
> + = reg->get_interval_start (num_required_regs,
> + static_cast<int> (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<gdb_byte> 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
next prev parent reply other threads:[~2026-10-08 19:45 UTC|newest]
Thread overview: 9+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-09-25 17:29 [PATCH v2 0/3] RISC-V Vector Extension support Kirill Radkin
2026-09-25 17:29 ` [PATCH v2 1/3] RISC-V Vector Extension Support Kirill Radkin
2026-10-08 19:44 ` Andrew Burgess [this message]
2026-10-08 19:52 ` Jerry Zhang Jian
2026-10-13 13:58 ` Andrew Burgess
2026-10-13 14:19 ` Jerry Zhang Jian
2026-10-14 3:21 ` Maciej W. Rozycki
2026-09-25 17:29 ` [PATCH v2 2/3] Reverse execution support for RISC-V Vector Extension Kirill Radkin
2026-09-25 17:29 ` [PATCH v2 3/3] RISC-V Vector Extension Support Testing Kirill Radkin
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=87tsmwt1tb.fsf@redhat.com \
--to=aburgess@redhat.com \
--cc=bergner@oss.tenstorrent.com \
--cc=gdb-patches@sourceware.org \
--cc=geomatsi@gmail.com \
--cc=heinrich.schuchardt@canonical.com \
--cc=hokeygo@gmail.com \
--cc=jerry.zhangjian@sifive.com \
--cc=palmer@dabbelt.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox