Mirror of the gdb-patches mailing list
 help / color / mirror / Atom feed
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 &reg_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 &reg : 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


  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