From: Jerry Zhang Jian <jerry.zhangjian@sifive.com>
To: Burgess Andrew <aburgess@redhat.com>
Cc: Radkin Kirill <hokeygo@gmail.com>,
gdb-patches@sourceware.org,
Bergner Peter <bergner@oss.tenstorrent.com>,
Matyukevich Sergey <geomatsi@gmail.com>,
Schuchardt Heinrich <heinrich.schuchardt@canonical.com>,
Palmer Dabbelt <palmer@dabbelt.com>
Subject: Re: [PATCH v2 1/3] RISC-V Vector Extension Support
Date: Fri, 9 Oct 2026 03:52:39 +0800 [thread overview]
Message-ID: <D77F71E8-C7C8-436F-9582-8017359F0C63@sifive.com> (raw)
In-Reply-To: <87tsmwt1tb.fsf@redhat.com>
Hi Andrew
I’ll also use our RISCV server to test it this weekend.
BRs
Jerry
> Andrew Burgess <aburgess@redhat.com> 於 2026年10月9日 03:44 寫道:
>
> 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:53 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
2026-10-08 19:52 ` Jerry Zhang Jian [this message]
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=D77F71E8-C7C8-436F-9582-8017359F0C63@sifive.com \
--to=jerry.zhangjian@sifive.com \
--cc=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=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