From 6793d19defcc4baba2879006e5e2ce89396e3afc Mon Sep 17 00:00:00 2001
From: "max.ma" <max.ma@starfivetech.com>
Date: Tue, 1 Nov 2022 19:50:38 -0700
Subject: [PATCH 4/7] add intial rvv support to display rvv registers

---
 gdb/arch/riscv.c             |  12 ++-
 gdb/features/riscv/vpu.c     |  66 +++++++++++++++++
 gdb/nat/riscv-linux-tdesc.c  |  46 +++++++++++-
 gdb/nat/riscv-linux-tdesc.h  |  18 +++++
 gdb/riscv-linux-nat.c        | 139 +++++++++++++++++++++++++++++++++++
 gdb/riscv-tdep.c             |  45 +++++++++++-
 gdb/riscv-tdep.h             |   5 ++
 gdbserver/linux-riscv-low.cc |  58 +++++++++++++++
 include/elf/common.h         |   4 +
 9 files changed, 388 insertions(+), 5 deletions(-)
 create mode 100644 gdb/features/riscv/vpu.c

diff --git a/gdb/arch/riscv.c b/gdb/arch/riscv.c
index 030c2cfdd9..03fcf7360f 100644
--- a/gdb/arch/riscv.c
+++ b/gdb/arch/riscv.c
@@ -25,6 +25,8 @@
 #include "../features/riscv/32bit-fpu.c"
 #include "../features/riscv/64bit-fpu.c"
 #include "../features/riscv/rv32e-xregs.c"
+#include "../features/riscv/vpu.c"
+
 
 #ifndef GDBSERVER
 #define STATIC_IN_GDB static
@@ -61,6 +63,9 @@ riscv_create_target_description (const struct riscv_gdbarch_features features)
     arch_name.append ("d");
   else if (features.flen == 16)
     arch_name.append ("q");
+  
+  if (features.vlen > 0)
+    arch_name.append ("v");
 
   set_tdesc_architecture (tdesc.get (), arch_name.c_str ());
 #endif
@@ -88,7 +93,12 @@ riscv_create_target_description (const struct riscv_gdbarch_features features)
      targets.  We don't support creating vector features on native targets
      (yet).  */
   if (features.vlen != 0)
-    error (_("unable to create vector feature"));
+  {
+    if (features.xlen == 4)
+      create_feature_riscv_vpu (tdesc.get (), 32, features.vlen);
+    else if (features.xlen == 8)
+      create_feature_riscv_vpu (tdesc.get (), 64, features.vlen);
+  }
 
   return tdesc;
 }
diff --git a/gdb/features/riscv/vpu.c b/gdb/features/riscv/vpu.c
new file mode 100644
index 0000000000..fe45f37b4c
--- /dev/null
+++ b/gdb/features/riscv/vpu.c
@@ -0,0 +1,66 @@
+#include "gdbsupport/tdesc.h"
+
+static int
+create_feature_riscv_vpu (struct target_desc *result, int arch, int vlen)
+{
+  struct tdesc_feature *feature;
+  tdesc_type *element_type, *field_type;
+  tdesc_type_with_fields *type_with_fields;
+  int i, regnum;
+  char regname[10]; 
+  printf("create_feature_riscv_vpu\n ");
+
+  feature = tdesc_create_feature (result, "org.gnu.gdb.riscv.vector");
+
+  if (vlen >= 16)
+  {
+    element_type = tdesc_named_type (feature, "uint128");
+    tdesc_create_vector (feature, "v_quads", element_type, (vlen * 8)/128);
+  }
+  if (vlen >= 8)
+  {
+    element_type = tdesc_named_type (feature, "uint64");
+    tdesc_create_vector (feature, "v_longs", element_type, (vlen * 8)/64);
+  }
+  element_type = tdesc_named_type (feature, "uint32");
+  tdesc_create_vector (feature, "v_words", element_type, (vlen * 8)/32);
+  element_type = tdesc_named_type (feature, "uint16");
+  tdesc_create_vector (feature, "v_shorts", element_type, (vlen * 8)/32);
+  element_type = tdesc_named_type (feature, "uint8");
+  tdesc_create_vector (feature, "v_bytes", element_type, vlen);
+
+  type_with_fields = tdesc_create_union (feature, "riscv_vector");
+  if (vlen >= 16)
+  {
+    field_type = tdesc_named_type (feature, "v_quads");
+    tdesc_add_field (type_with_fields, "q", field_type);
+  }
+  if (vlen >= 8)
+  {
+    field_type = tdesc_named_type (feature, "v_longs");
+    tdesc_add_field (type_with_fields, "l", field_type);
+  }
+  field_type = tdesc_named_type (feature, "v_words");
+  tdesc_add_field (type_with_fields, "w", field_type);
+  field_type = tdesc_named_type (feature, "v_shorts");
+  tdesc_add_field (type_with_fields, "s", field_type);
+  field_type = tdesc_named_type (feature, "v_bytes");
+  tdesc_add_field (type_with_fields, "b", field_type);
+
+  tdesc_create_reg (feature, "vstart", 73, 1, NULL, arch, "int");
+  tdesc_create_reg (feature, "vcsr", 80, 1, NULL, arch, "int");
+  tdesc_create_reg (feature, "vl", 3169, 1, NULL, arch, "int");
+  tdesc_create_reg (feature, "vtype", 3170, 1, NULL, arch, "int");
+
+  regnum = 4162;
+  
+  for (i = 0; i < 32; i++)
+  {
+    memset(regname, 0, sizeof(regname));
+    sprintf(regname, "v%d", i);
+    tdesc_create_reg (feature, regname, regnum++, 1, 
+                      NULL, vlen * 8, "riscv_vector");
+  }
+
+  return regnum;
+}
diff --git a/gdb/nat/riscv-linux-tdesc.c b/gdb/nat/riscv-linux-tdesc.c
index 07b49c0f16..b349035d9a 100644
--- a/gdb/nat/riscv-linux-tdesc.c
+++ b/gdb/nat/riscv-linux-tdesc.c
@@ -23,7 +23,7 @@
 #include "elf/common.h"
 #include "nat/gdb_ptrace.h"
 #include "nat/riscv-linux-tdesc.h"
-
+#include "nat/linux-ptrace.h"
 #include <sys/uio.h>
 
 /* Work around glibc header breakage causing ELF_NFPREG not to be usable.  */
@@ -31,6 +31,26 @@
 # define NFPREG 33
 #endif
 
+#ifndef CSR_VLENB
+#define CSR_VLENB 0xC22
+#endif
+
+#ifdef __ASSEMBLY__
+#define __ASM_STR(x)	x
+#else
+#define __ASM_STR(x)	#x
+#endif
+
+
+#define csr_read(csr)						\
+({								\
+	register unsigned long __v;				\
+	__asm__ __volatile__ ("csrr %0, " __ASM_STR(csr)	\
+			      : "=r" (__v) :			\
+			      : "memory");			\
+	__v;							\
+})
+
 /* See nat/riscv-linux-tdesc.h.  */
 
 struct riscv_gdbarch_features
@@ -78,6 +98,30 @@ riscv_linux_read_features (int tid)
 	features.flen = flen;
       break;
     }
+  
+  struct __riscv_v_state rv_state;
+  struct iovec iov;
+  iov.iov_base = &rv_state;
+  iov.iov_len = sizeof(rv_state);
+
+  if (ptrace (PTRACE_GETREGSET, tid, NT_RISCV_VECTOR,
+      (PTRACE_TYPE_ARG3) &iov) == -1)
+  {
+	  switch (errno)
+	    {
+	    case EINVAL:
+	      break;
+	    case EIO:
+	      break;
+	    default:
+	      perror_with_name (_("Couldn't get registers"));
+	      break;
+      }
+  }
+  else 
+  {
+    features.vlen = csr_read(CSR_VLENB);
+  }
 
   return features;
 }
diff --git a/gdb/nat/riscv-linux-tdesc.h b/gdb/nat/riscv-linux-tdesc.h
index 4f476aed5c..092ee7d29b 100644
--- a/gdb/nat/riscv-linux-tdesc.h
+++ b/gdb/nat/riscv-linux-tdesc.h
@@ -21,6 +21,24 @@
 
 #include "arch/riscv.h"
 
+/* Work around glibc header breakage causing ELF_NFPREG not to be usable.  */
+#ifndef NFPREG
+# define NFPREG 33
+#endif
+
+#ifndef NVREG
+#define NVREG 32
+#endif
+
+#define csr_read(csr)						\
+({								\
+	register unsigned long __v;				\
+	__asm__ __volatile__ ("csrr %0, " csr	\
+			      : "=r" (__v) :			\
+			      : "memory");			\
+	__v;							\
+})
+
 /* Determine XLEN and FLEN for the LWP identified by TID, and return a
    corresponding features object.  */
 struct riscv_gdbarch_features riscv_linux_read_features (int tid);
diff --git a/gdb/riscv-linux-nat.c b/gdb/riscv-linux-nat.c
index 7063494148..0e24cbcb86 100644
--- a/gdb/riscv-linux-nat.c
+++ b/gdb/riscv-linux-nat.c
@@ -34,6 +34,10 @@
 # define NFPREG 33
 #endif
 
+#ifndef ELF_NVREG 
+#define ELF_NVREG 32
+#endif
+
 /* RISC-V Linux native additions to the default linux support.  */
 
 class riscv_linux_nat_target final : public linux_nat_target
@@ -196,6 +200,90 @@ fill_fpregset (const struct regcache *regcache, prfpregset_t *fpregs,
     }
 }
 
+/* Copy vector register REGNUM (or all vector regs if REGNUM == -1)
+   from regset vregs into REGCACHE.  */
+
+static void
+supply_vregset_regnum (struct regcache *regcache, char *vregs,
+			int regnum)
+{
+  int i;
+  int vlen = riscv_isa_vlen(regcache->arch());
+  __riscv_v_state *vstate = (__riscv_v_state*)vregs;
+  vregs += sizeof(__riscv_v_state); 
+
+  if (regnum == -1)
+    {
+      regcache->raw_supply (RISCV_CSR_VSTART_REGNUM, &vstate->vstart);
+      regcache->raw_supply (RISCV_CSR_VCSR_REGNUM, &vstate->vcsr); 
+      regcache->raw_supply (RISCV_CSR_VL_REGNUM, &vstate->vl); 
+      regcache->raw_supply (RISCV_CSR_VTYPE_REGNUM, &vstate->vtype); 
+
+      for (i = RISCV_V0_REGNUM;
+	   i <= RISCV_V31_REGNUM;
+	   i++, vregs += vlen)
+	regcache->raw_supply (i, vregs);
+    }
+  else if (regnum >= RISCV_V0_REGNUM && regnum <= RISCV_V31_REGNUM)
+    {
+      vregs += (regnum - RISCV_V0_REGNUM) * vlen;
+      regcache->raw_supply (regnum, vregs);
+    }
+  else if (regnum == RISCV_CSR_VSTART_REGNUM)
+      regcache->raw_supply (regnum, &vstate->vstart);
+  else if (regnum == RISCV_CSR_VCSR_REGNUM)
+      regcache->raw_supply (regnum, &vstate->vcsr);
+  else if (regnum == RISCV_CSR_VL_REGNUM)
+      regcache->raw_supply (regnum, &vstate->vl);
+  else if (regnum == RISCV_CSR_VTYPE_REGNUM)
+      regcache->raw_supply (regnum, &vstate->vtype);
+}
+
+
+/* Copy all vector registers from regset vregs into REGCACHE.  */
+
+void
+supply_vregset (struct regcache *regcache, const void *vregs)
+{
+  supply_vregset_regnum (regcache, (char *)vregs, -1);
+}
+
+/* Copy vector register REGNUM (or all fp regs if REGNUM == -1)
+   from REGCACHE into regset FPREGS.  */
+void
+fill_vregset (struct regcache *regcache, char *vregs,
+	       int regnum)
+{
+  int i;
+  int vlen = riscv_isa_vlen(regcache->arch());
+  __riscv_v_state *vstate = (__riscv_v_state*)vregs;
+  if (regnum == -1)   
+    {
+      regcache->raw_collect (RISCV_CSR_VSTART_REGNUM, &vstate->vstart);
+      regcache->raw_collect (RISCV_CSR_VCSR_REGNUM, &vstate->vcsr); 
+      regcache->raw_collect (RISCV_CSR_VL_REGNUM, &vstate->vl); 
+      regcache->raw_collect (RISCV_CSR_VTYPE_REGNUM, &vstate->vtype); 
+
+      for (i = RISCV_V0_REGNUM;
+	   i <= RISCV_V31_REGNUM;
+	   i++, vregs += vlen)
+	regcache->raw_collect (i, vregs); 
+    }    
+  else if (regnum >= RISCV_V0_REGNUM && regnum <= RISCV_V31_REGNUM)
+    {
+      vregs += (regnum - RISCV_V0_REGNUM) * vlen;
+      regcache->raw_collect (regnum, vregs);
+    }
+    else if (regnum == RISCV_CSR_VSTART_REGNUM)
+      regcache->raw_collect (regnum, &vstate->vstart);
+    else if (regnum == RISCV_CSR_VCSR_REGNUM)
+      regcache->raw_collect (regnum, &vstate->vcsr);
+    else if (regnum == RISCV_CSR_VL_REGNUM)
+      regcache->raw_supply (regnum, &vstate->vl);
+    else if (regnum == RISCV_CSR_VTYPE_REGNUM)
+      regcache->raw_supply (regnum, &vstate->vl);
+}
+
 /* Return a target description for the current target.  */
 
 const struct target_desc *
@@ -252,6 +340,31 @@ riscv_linux_nat_target::fetch_registers (struct regcache *regcache, int regnum)
 	supply_fpregset_regnum (regcache, &regs, regnum);
     }
 
+  if ((regnum >= RISCV_V0_REGNUM
+       && regnum <= RISCV_V31_REGNUM)
+      || (regnum == RISCV_CSR_VSTART_REGNUM)
+      || (regnum == RISCV_CSR_VCSR_REGNUM)
+      || (regnum == RISCV_CSR_VL_REGNUM)
+      || (regnum == RISCV_CSR_VTYPE_REGNUM)
+      || (regnum == -1))
+    {
+      struct iovec iov;
+      iov.iov_len = sizeof(__riscv_v_state) + 
+          ELF_NVREG * riscv_isa_vlen(regcache->arch());
+      
+      iov.iov_base = malloc(iov.iov_len);
+      char * buf = (char *)iov.iov_base + sizeof(__riscv_v_state);
+      gdb_assert (iov.iov_base != NULL);
+
+      if (ptrace (PTRACE_GETREGSET, tid, NT_RISCV_VECTOR,
+		  (PTRACE_TYPE_ARG3) &iov) == -1)
+	perror_with_name (_("Couldn't get vector registers"));
+      else      
+	supply_vregset_regnum (regcache, (char *)(iov.iov_base), regnum);
+
+      free(iov.iov_base);
+    }
+
   if ((regnum == RISCV_CSR_MISA_REGNUM)
       || (regnum == -1))
     {
@@ -321,6 +434,32 @@ riscv_linux_nat_target::store_registers (struct regcache *regcache, int regnum)
 	}
     }
 
+  if ((regnum >= RISCV_V0_REGNUM
+       && regnum <= RISCV_V31_REGNUM)
+      || (regnum == RISCV_CSR_VSTART_REGNUM)
+      || (regnum == RISCV_CSR_VCSR_REGNUM)
+      || (regnum == RISCV_CSR_VL_REGNUM)
+      || (regnum == RISCV_CSR_VTYPE_REGNUM)
+      || (regnum == -1))
+    {
+      struct iovec iov;
+      iov.iov_len = sizeof(__riscv_v_state) + 
+          ELF_NVREG * riscv_isa_vlen(regcache->arch ());
+      iov.iov_base = malloc(iov.iov_len);
+      gdb_assert (iov.iov_base != NULL);
+
+      if (ptrace (PTRACE_GETREGSET, tid, NT_RISCV_VECTOR,
+		  (PTRACE_TYPE_ARG3) &iov) == -1)
+	perror_with_name (_("Couldn't get vector registers"));
+      else
+  { 
+    fill_vregset (regcache, (char *)(iov.iov_base), regnum);
+	  if (ptrace (PTRACE_SETREGSET, tid, NT_FPREGSET,
+		      (PTRACE_TYPE_ARG3) &iov) == -1)
+	    perror_with_name (_("Couldn't set vector registers"));
+  }
+      free(iov.iov_base);
+    }
   /* Access to CSRs has potential security issues, don't support them for
      now.  */
 }
diff --git a/gdb/riscv-tdep.c b/gdb/riscv-tdep.c
index 886996ce5b..44ce340f39 100644
--- a/gdb/riscv-tdep.c
+++ b/gdb/riscv-tdep.c
@@ -619,16 +619,21 @@ struct riscv_vector_feature : public riscv_register_feature
       { RISCV_V0_REGNUM + 29, { "v29" } },
       { RISCV_V0_REGNUM + 30, { "v30" } },
       { RISCV_V0_REGNUM + 31, { "v31" } },
+       
+      { RISCV_CSR_VSTART_REGNUM, { "vstart" } },
+      { RISCV_CSR_VCSR_REGNUM, { "vcsr" } },
+      { RISCV_CSR_VL_REGNUM, { "vl" } },
+      { RISCV_CSR_VTYPE_REGNUM, { "vtype" } },      
     };
   }
 
   /* Return the preferred name for the register with gdb register number
      REGNUM, which must be in the inclusive range RISCV_V0_REGNUM to
-     RISCV_V0_REGNUM + 31.  */
+     RISCV_V31_REGNUM.  */
   const char *register_name (int regnum) const
   {
     gdb_assert (regnum >= RISCV_V0_REGNUM
-		&& regnum <= RISCV_V0_REGNUM + 31);
+		&& regnum <= RISCV_V31_REGNUM);
     regnum -= RISCV_V0_REGNUM;
     return m_registers[regnum].names[0];
   }
@@ -663,6 +668,12 @@ struct riscv_vector_feature : public riscv_register_feature
     int vector_bitsize = -1;
     for (const auto &reg : m_registers)
       {
+        if (reg.regnum == RISCV_CSR_VSTART_REGNUM ||
+          reg.regnum == RISCV_CSR_VCSR_REGNUM || 
+          reg.regnum == RISCV_CSR_VL_REGNUM || 
+          reg.regnum == RISCV_CSR_VTYPE_REGNUM
+        )
+    continue;
 	int reg_bitsize = -1;
 	for (const char *name : reg.names)
 	  {
@@ -737,6 +748,16 @@ riscv_isa_xlen (struct gdbarch *gdbarch)
   return tdep->isa_features.xlen;
 }
 
+/* See riscv-tdep.h.  */
+
+int
+riscv_isa_vlen (struct gdbarch *gdbarch)
+{
+  riscv_gdbarch_tdep *tdep = (riscv_gdbarch_tdep *) gdbarch_tdep (gdbarch);
+  return tdep->isa_features.vlen;
+}
+
+
 /* See riscv-tdep.h.  */
 
 int
@@ -781,6 +802,13 @@ riscv_has_fp_regs (struct gdbarch *gdbarch)
   return (riscv_isa_flen (gdbarch) > 0);
 }
 
+/* Return true if the target for GDBARCH has vector hardware.  */
+static bool
+riscv_has_v_regs (struct gdbarch *gdbarch)
+{
+  return (riscv_isa_vlen (gdbarch) > 0);
+}
+
 /* Return true if GDBARCH is using any of the floating point hardware ABIs.  */
 
 static bool
@@ -873,7 +901,7 @@ riscv_sw_breakpoint_from_kind (struct gdbarch *gdbarch, int kind, int *size)
 
 /* Implement the register_name gdbarch method.  This is used instead of
    the function supplied by calling TDESC_USE_REGISTERS so that we can
-   ensure the preferred names are offered for x-regs and f-regs.  */
+   ensure the preferred names are offered for x-regs,f-regs and v-regs.  */
 
 static const char *
 riscv_register_name (struct gdbarch *gdbarch, int regnum)
@@ -902,6 +930,14 @@ riscv_register_name (struct gdbarch *gdbarch, int regnum)
 	return NULL;
     }
 
+  if (regnum >= RISCV_V0_REGNUM && regnum <= RISCV_LAST_REGNUM)
+    {
+      if (riscv_has_v_regs (gdbarch))
+	return riscv_vector_feature.register_name (regnum);
+      else
+	return NULL;
+    }
+
   /* Some targets (QEMU) are reporting these three registers twice, once
      in the FPU feature, and once in the CSR feature.  Both of these read
      the same underlying state inside the target, but naming the register
@@ -3545,6 +3581,7 @@ riscv_gcc_target_options (struct gdbarch *gdbarch)
 {
   int isa_xlen = riscv_isa_xlen (gdbarch);
   int isa_flen = riscv_isa_flen (gdbarch);
+  int isa_vlen = riscv_isa_vlen (gdbarch);
   int abi_xlen = riscv_abi_xlen (gdbarch);
   int abi_flen = riscv_abi_flen (gdbarch);
   std::string target_options;
@@ -3560,6 +3597,8 @@ riscv_gcc_target_options (struct gdbarch *gdbarch)
     target_options += "imafc";
   else
     target_options += "imac";
+  if (isa_vlen)
+    target_options += "v"; /* change to zvl zve later */
 
   target_options += " -mabi=";
   if (abi_xlen == 8)
diff --git a/gdb/riscv-tdep.h b/gdb/riscv-tdep.h
index ac4b4b7144..913c5f1724 100644
--- a/gdb/riscv-tdep.h
+++ b/gdb/riscv-tdep.h
@@ -139,6 +139,11 @@ extern int riscv_abi_xlen (struct gdbarch *gdbarch);
    with RISCV_ISA_FLEN.  */
 extern int riscv_abi_flen (struct gdbarch *gdbarch);
 
+/* Return the width in bytes of the hardware vector registers for
+   GDBARCH.  If this architecture has no vector registers, then
+   return 0.  Possible values are 32, 64, 128, ...2pow(16)  */
+extern int riscv_isa_vlen(struct gdbarch *gdbarch);
+
 /* Return true if GDBARCH is using the embedded x-regs abi, that is the
    target only has 16 x-registers, which includes a reduced number of
    argument registers.  */
diff --git a/gdbserver/linux-riscv-low.cc b/gdbserver/linux-riscv-low.cc
index 6b2902e422..54444f9883 100644
--- a/gdbserver/linux-riscv-low.cc
+++ b/gdbserver/linux-riscv-low.cc
@@ -30,6 +30,17 @@
 # define NFPREG 33
 #endif
 
+#ifndef NVREG 
+#define NVREG 32
+#endif
+
+/* In RVV spec, the register width must be no greater than 2exp(16). 
+   We set the max width to 1024 for now.
+*/
+#ifndef VREG_MAX_LEN
+#define VREG_MAX_LEN 1024
+#endif
+
 /* Linux target op definitions for the RISC-V architecture.  */
 
 class riscv_target : public linux_process_target
@@ -158,6 +169,50 @@ riscv_store_fpregset (struct regcache *regcache, const void *buf)
   supply_register_by_name (regcache, "fcsr", regbuf);
 }
 
+
+/* Collect VRs from REGCACHE into BUF.  */
+
+static void
+riscv_fill_vregset (struct regcache *regcache, void *buf)
+{
+  int i;
+  const struct target_desc *tdesc = regcache->tdesc;
+  int regno = find_regno (tdesc, "v0");
+  int vlen = register_size (regcache->tdesc, regno);
+  __riscv_v_state *vstate = (__riscv_v_state *)buf;
+  buf += sizeof(__riscv_v_state);
+
+  for (i = 0; i < NVREG; i++, buf += vlen)
+  	collect_register (regcache, regno + i, buf);
+
+  collect_register_by_name (regcache, "vstart", &vstate->vstart); 
+  collect_register_by_name (regcache, "vl", &vstate->vl);     
+  collect_register_by_name (regcache, "vtype", &vstate->vtype);  
+  collect_register_by_name (regcache, "vcsr", &vstate->vcsr);   
+}
+
+/* Supply VECRs from BUF into REGCACHE.  */
+
+static void
+riscv_store_vregset (struct regcache *regcache, const void *buf)
+{
+  const struct target_desc *tdesc = regcache->tdesc;
+  struct __riscv_v_state *vstate = (__riscv_v_state *)buf;
+  buf += sizeof(__riscv_v_state);
+  int regno = find_regno (tdesc, "v0");
+  int vlen = register_size (regcache->tdesc, regno);
+  int i;
+
+  for (i = 0; i < NVREG; i++, buf += vlen)
+    supply_register (regcache, regno + i, buf);
+
+  supply_register_by_name (regcache, "vstart", &vstate->vstart); 
+  supply_register_by_name (regcache, "vl", &vstate->vl);     
+  supply_register_by_name (regcache, "vtype", &vstate->vtype);  
+  supply_register_by_name (regcache, "vcsr", &vstate->vcsr);   ;
+}
+
+
 /* RISC-V/Linux regsets.  FPRs are optional and come in different sizes,
    so define multiple regsets for them marking them all as OPTIONAL_REGS
    rather than FP_REGS, so that "regsets_fetch_inferior_registers" picks
@@ -175,6 +230,9 @@ static struct regset_info riscv_regsets[] = {
   { PTRACE_GETREGSET, PTRACE_SETREGSET, NT_FPREGSET,
     sizeof (struct __riscv_mc_f_ext_state), OPTIONAL_REGS,
     riscv_fill_fpregset, riscv_store_fpregset },
+  { PTRACE_GETREGSET, PTRACE_SETREGSET, NT_RISCV_VECTOR,
+    sizeof (struct __riscv_v_state) + NVREG * VREG_MAX_LEN, EXTENDED_REGS,
+    riscv_fill_vregset, riscv_store_vregset},    
   NULL_REGSET
 };
 
diff --git a/include/elf/common.h b/include/elf/common.h
index 70d63e3299..2662e767ba 100644
--- a/include/elf/common.h
+++ b/include/elf/common.h
@@ -690,6 +690,10 @@
 					/*   note name must be "LINUX".  */
 #define NT_ARM_PAC_ENABLED_KEYS	0x40a	/* AArch64 pointer authentication
 					   enabled keys (prctl()) */
+
+					/*   note name must be "LINUX".  */
+#define NT_RISCV_VECTOR	0x900		/* RISC-V vector registers */                 
+
 					/*   note name must be "LINUX".  */
 #define NT_ARC_V2	0x600		/* ARC HS accumulator/extra registers.  */
 					/*   note name must be "LINUX".  */
-- 
2.25.1

