From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from simark.ca by simark.ca with LMTP id 559VNkr1mWr/hyYAWB0awg (envelope-from ) for ; Thu, 03 Sep 2026 18:31:38 -0400 Authentication-Results: simark.ca; dkim=pass (2048-bit key; unprotected) header.d=tenstorrent.com header.i=@tenstorrent.com header.a=rsa-sha256 header.s=google header.b=MZENDFM9; dkim-atps=neutral Received: by simark.ca (Postfix, from userid 112) id 9AE3E1E166; Thu, 03 Sep 2026 18:31:38 -0400 (EDT) X-Spam-Checker-Version: SpamAssassin 4.0.1 (2024-03-25) on simark.ca X-Spam-Level: X-Spam-Status: No, score=-2.3 required=5.0 tests=ARC_SIGNED,ARC_VALID,BAYES_00, DKIM_SIGNED,DKIM_VALID,MAILING_LIST_MULTI,RCVD_IN_DNSWL_MED, RCVD_IN_VALIDITY_CERTIFIED_BLOCKED,RCVD_IN_VALIDITY_RPBL_BLOCKED, RCVD_IN_VALIDITY_SAFE_BLOCKED autolearn=ham autolearn_force=no version=4.0.1 Received: from vm01.sourceware.org (vm01.sourceware.org [38.145.34.32]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange x25519 server-signature ECDSA (prime256v1) server-digest SHA256) (No client certificate requested) by simark.ca (Postfix) with ESMTPS id C024C1E033 for ; Thu, 03 Sep 2026 18:31:33 -0400 (EDT) Received: from vm01.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id 1A6554BB1C3C for ; Thu, 3 Sep 2026 22:31:27 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 1A6554BB1C3C Authentication-Results: sourceware.org; dkim=pass (2048-bit key, unprotected) header.d=tenstorrent.com header.i=@tenstorrent.com header.a=rsa-sha256 header.s=google header.b=MZENDFM9 Received: from mail-oi1-x233.google.com (mail-oi1-x233.google.com [IPv6:2607:f8b0:4864:20::233]) by sourceware.org (Postfix) with ESMTPS id 8A2D64BB1C27 for ; Thu, 3 Sep 2026 22:30:49 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org 8A2D64BB1C27 Authentication-Results: sourceware.org; dmarc=none (p=none dis=none) header.from=oss.tenstorrent.com Authentication-Results: sourceware.org; spf=pass smtp.mailfrom=tenstorrent.com ARC-Filter: OpenARC Filter v1.0.0 sourceware.org 8A2D64BB1C27 Authentication-Results: sourceware.org; arc=none smtp.remote-ip=2607:f8b0:4864:20::233 ARC-Seal: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1788474649; cv=none; b=F3OrZZ9ZaEE04Afx4qai7ez2LlsM6O2WBW97OCIohpeYsa+2x+KZQWBbtdP/t6Zw1h0rzHM0B9pzLEJjUByfMFo2fcV1EjQdeGuF/psj4Yq8dGYEQJw1vbrR6WF/eed/cmem9gzWifrOOiKvbuDm0ANpgFeYO1xFCkX5oxxdTTU= ARC-Message-Signature: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1788474649; c=relaxed/simple; bh=g5Caw2bYwHtsEmaOvpYln4vz6cNfU4Zz3wOvbTcgtjc=; h=DKIM-Signature:Message-ID:Date:MIME-Version:Subject:To:From; b=Vt98C9fYM2LTe3x5ZT+G52YlVp1JLzMWk50TH9v+Cos7ph1PVKu0IifstkoCPOuEbwmp/kodXKrwy4+C/dmABI3usr5OS8I5Yly6lDjSgcDkeGW043H7RDdYy6yAPI6DouUke70RNWUFpi0vTLhSCC1RdUiYedGtbwOsC+a8/pw= ARC-Authentication-Results: i=1; sourceware.org; dkim=pass (2048-bit key, unprotected) header.d=tenstorrent.com header.i=@tenstorrent.com header.a=rsa-sha256 header.s=google header.b=MZENDFM9 DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 8A2D64BB1C27 Received: by mail-oi1-x233.google.com with SMTP id 5614622812f47-4b28df1f600so292374b6e.2 for ; Thu, 03 Sep 2026 15:30:49 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=tenstorrent.com; s=google; t=1788474649; x=1789079449; darn=sourceware.org; h=content-transfer-encoding:content-type:in-reply-to:cc :content-language:from:references:to:subject:user-agent:mime-version :date:message-id:from:to:cc:subject:date:message-id:reply-to :content-type; bh=05Djxa3PPHLDavaSNZM/92DUxfmUp4x8sdxTwL2s4YI=; b=MZENDFM9tSnL/lRpUV4q26zbcfqRvzgnQZ0l4HylkZk2vrJI3nCZZrqncX5xa63JYW bYrzX6NaSg/iylCv7uE+4C0vpRtoM1qTPmWFwtLYK9lEnaBaXsBvxc107NZlMW6B4IzH 7Wmn8RdoKkNDds4Oyn2dmmQpXVQPvykuHIdadw00VPklxmSCg7CpR+m7u2UyQLVaEzKh rZf34rvx8scXPDb1Cl+pxxNJX97SFvhLtWDB0m5knb7v7oifPqnrczRyOoaC4g1PUV4S lEjcQNpbz0+Z9O32miTSyU0RjK4hGNjTLMO5dGLN6lS3ShqrVUs0YyyDQwdhbmyhlZoy TSQQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1788474649; x=1789079449; h=content-transfer-encoding:content-type:in-reply-to:cc :content-language:from:references:to:subject:user-agent:mime-version :date:message-id:x-gm-gg:x-gm-message-state:from:to:cc:subject:date :message-id:reply-to:content-type; bh=05Djxa3PPHLDavaSNZM/92DUxfmUp4x8sdxTwL2s4YI=; b=LjLrAPxH9AEbYpOhlxxYxwxbQON7WhzT2bAIkRK9NGPlB8TYoiNLEPZ7Xt88mflW0B S/0e0EpDgyKleyUALySKsPRzFO1vTuqNnY1HJ5DUJzpHdbbUfDp/aqRdUAwGqD5ZSoZu jRfx6kN2HdzFX3lkvSadiJ9jf5GM90J9nSQR33lQPg11F79inH6meZScj7bu0o6tJC53 EdxlNdJ6vsSkc9OaR/M6N5lrQr+6OQSuscQ2Ow5+Lu78t5ig/4Wf2TkAzFjluW1C5sGJ a7iG6aiuxaqBR9WodQvvzxWMCDHMOKZl+kdS7pch65y9TyLhulAA0AyYWzRijHbTN1qQ 7oMA== X-Forwarded-Encrypted: i=1; AKwUvBwaDUXQLnPAfMXtGCmo3oB0NU/T6qlyySNz/6RUmx57+Y5bd93gOlquJB1vK6ClP8bvNGqFOOUo5XlG+g==@sourceware.org X-Gm-Message-State: AFuF++nLyzEwg7kA70W63eJ7QZ8FKC/Lf/5LoiS9PiDsIJ4XWCAR0W+n mrRdIO92Fy6Xpy5wtYH2Cd/gVDSN8gcyqBwHPyikkdrkUP3DGGh4ck+nxw9ms0Hm0b6tCsoYKdj +0DDsJZo= X-Gm-Gg: AYBFou3XPs1cxuRMdSiufBZomhRUut/DrgCSY/mlUEojVCx6AwNg+sywXlE48A0uTDk suyAfivOoERHuckxe7Khyck8wC7zB0EXX6V9laV7+/E1T1WkvnPdWD0gY1BvlotHqEF6alyLbd3 3T1QKSFkvuunbSIUKzkiIUu67GetoAdhcfz3CScA2/tLUOCx0XGQ4nBWHjWQ6g/btRaegbGNhFi duUHPJh0TnZ1EO99GC9Ffo5alR56bledUxNEei8c8Cv3KOO18me5LX8QXaXkmJmpLCbnT4jUAs9 dPG3kNHI/9dtPsLX/M4SXxhvrkzzOyaDZzzVh8sg7rxNEgMps30SoJ1463oHqEtOtHjfz6jpl3z ief7ZgACfHtOPURQDZtmBVlnHNm4CWRKWUCSLSoDYIj+uzzlhYJbrGB4SmOk5Db9z6AdRGW1vze 1Q670PSBhSMnGPoQQkfd9Y/wyeVqKkHhXT5kZdtA+I+NQ5uzv/H4V3fHqVBKahDNeB3IpeR64yb x2ewDgaB0miAmM1HA== X-Received: by 2002:a05:6808:2222:b0:4b2:3e72:bab1 with SMTP id 5614622812f47-4b960378193mr1780914b6e.6.1788474647960; Thu, 03 Sep 2026 15:30:47 -0700 (PDT) Received: from [192.168.1.113] ([104.219.198.9]) by smtp.gmail.com with ESMTPSA id 5614622812f47-4b970d200fesm591547b6e.3.2026.09.03.15.30.46 (version=TLS1_3 cipher=TLS_AES_128_GCM_SHA256 bits=128/128); Thu, 03 Sep 2026 15:30:47 -0700 (PDT) Message-ID: Date: Thu, 3 Sep 2026 17:30:45 -0500 MIME-Version: 1.0 User-Agent: Mozilla Thunderbird Subject: Re: [PATCH 1/2] RISC-V Vector Extension Support To: Kirill Radkin , gdb-patches@sourceware.org References: <20251107165534.1688124-1-kirill.radkin@syntacore.com> From: Peter Bergner Content-Language: en-US Cc: Sameer Natu , Andrew Burgess , Jeffrey Law , Robin Dapp In-Reply-To: <20251107165534.1688124-1-kirill.radkin@syntacore.com> Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 7bit X-BeenThere: gdb-patches@sourceware.org X-Mailman-Version: 2.1.30 Precedence: list List-Id: Gdb-patches mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: gdb-patches-bounces~public-inbox=simark.ca@sourceware.org It would be nice if either this patch series or Sameer's patch series were to be reviewed. I can't comment on whose GDB patch series is preferred, but having something is better than the nothing we have now. I've been relegated to applying and building these patches manually, just so I can debug riscv rvv optimized code. I'm sure I'm not alone in that. :-( Peter On 11/7/25 10:55 AM, Kirill Radkin wrote: > 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 (74, 128, 1024). Implementation > is tested on system QEMU (Linux) and on OpenOCD + spike configuration. > --- > 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 | 33 ++ > gdb/riscv-linux-nat.c | 164 ++++++++ > gdb/riscv-regs.h | 79 ++++ > gdb/riscv-tdep.c | 758 ++++++++++++++++++++++++++++++----- > gdb/riscv-tdep.h | 63 +-- > gdbserver/linux-riscv-low.cc | 140 +++++-- > gdbsupport/common-utils.h | 2 + > include/elf/common.h | 1 + > 13 files changed, 1255 insertions(+), 197 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 c698fa2b62e..d5d41fe6382 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 bc95e72bb35..8b4e4b3c8cb 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..a7a3adb5e65 > --- /dev/null > +++ b/gdb/features/riscv/rvv.c > @@ -0,0 +1,113 @@ > +/* Copyright (C) 2025 Free Software Foundation, Inc. > + > + This file is part of GDB. > + > + This program is free software; you can redistribute it and/or modify > + it under the terms of the GNU General Public License as published by > + the Free Software Foundation; either version 3 of the License, or > + (at your option) any later version. > + > + This program is distributed in the hope that it will be useful, > + but WITHOUT ANY WARRANTY; without even the implied warranty of > + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the > + GNU General Public License for more details. > + > + You should have received a copy of the GNU General Public License > + along with this program. If not, see . */ > + > +#include "gdbsupport/gdb_assert.h" > +#include "gdbsupport/tdesc.h" > +#include "gdb/riscv-regs.h" > +#include > + > +/* This file is NOT auto generated from xml. > + 'create_feature_riscv_rvv' creates a RISCV Vector Extension feature. > + 'vlenb' is a vector register size in bytes */ > + > +struct vector_field_type_info > +{ > + const char *element_type_name; > + const char *vector_type_name; > + int element_count; > +}; > + > +static void > +create_vector_register_type (tdesc_feature *feature, > + std::vector &types_info, > + const char *type_name) > +{ > + tdesc_type *element_type; > + > + for (auto &&type_info : types_info) > + { > + if (type_info.element_count == -1) > + continue; > + element_type = tdesc_named_type (feature, type_info.element_type_name); > + tdesc_create_vector (feature, type_info.vector_type_name, element_type, > + type_info.element_count); > + } > + > + tdesc_type_with_fields *type_with_fields > + = tdesc_create_union (feature, type_name); > + > + for (auto &&type_info : types_info) > + { > + if (type_info.element_count == -1) > + continue; > + element_type = tdesc_named_type (feature, type_info.vector_type_name); > + tdesc_add_field (type_with_fields, type_info.vector_type_name, > + element_type); > + } > +} > + > +static int > +create_feature_riscv_rvv (target_desc *result, int vlenb, int xlen) > +{ > + gdb_assert (result); > + gdb_assert (xlen == 4 || xlen == 8); > + gdb_assert (vlenb >= 4 && ((vlenb & (vlenb - 1)) == 0)); > + > + int v_bitsize = 8 * vlenb; > + int x_bitsize = 8 * xlen; > + > + tdesc_feature *csr_feature > + = tdesc_create_feature (result, "org.gnu.gdb.riscv.csr"); > + tdesc_create_reg (csr_feature, "vstart", RISCV_CSR_VSTART_REGNUM, 1, NULL, > + x_bitsize, "int"); > + tdesc_create_reg (csr_feature, "vcsr", RISCV_CSR_VCSR_REGNUM, 1, NULL, > + x_bitsize, "int"); > + tdesc_create_reg (csr_feature, "vl", RISCV_CSR_VL_REGNUM, 1, NULL, x_bitsize, > + "int"); > + tdesc_create_reg (csr_feature, "vtype", RISCV_CSR_VTYPE_REGNUM, 1, NULL, > + x_bitsize, "int"); > + tdesc_create_reg (csr_feature, "vlenb", RISCV_CSR_VLENB_REGNUM, 1, NULL, > + x_bitsize, "int"); > + > + tdesc_feature *vector_feature > + = tdesc_create_feature (result, "org.gnu.gdb.riscv.vector"); > + > + std::vector elements_types_info > + = { { "int8", "i8", vlenb }, > + { "int16", "i16", vlenb / 2 }, > + { "int32", "i32", vlenb / 4 }, > + { "int64", "i64", (vlenb >= 8) ? vlenb / 8 : -1 }, > + { "ieee_half", "half", vlenb / 2 }, > + { "ieee_single", "f32", vlenb / 4 }, > + { "ieee_double", "f64", (vlenb >= 8) ? vlenb / 8 : -1 } }; > + > + create_vector_register_type (vector_feature, elements_types_info, "rvv"); > + > + int regnum = RISCV_V0_REGNUM; > + > + constexpr const char *vec_reg_names[] > + = { "v0", "v1", "v2", "v3", "v4", "v5", "v6", "v7", > + "v8", "v9", "v10", "v11", "v12", "v13", "v14", "v15", > + "v16", "v17", "v18", "v19", "v20", "v21", "v22", "v23", > + "v24", "v25", "v26", "v27", "v28", "v29", "v30", "v31" }; > + > + for (int i = 0; i < 32; ++i) > + tdesc_create_reg (vector_feature, vec_reg_names[i], regnum++, 1, NULL, > + v_bitsize, "rvv"); > + > + return regnum; > +} > diff --git a/gdb/gdbtypes.c b/gdb/gdbtypes.c > index 63d6f4c0ceb..ba356fefdea 100644 > --- a/gdb/gdbtypes.c > +++ b/gdb/gdbtypes.c > @@ -2151,6 +2151,21 @@ is_dynamic_type_internal (struct type *type, bool top_level) > } > } > 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 */ > + if (type->target_type () > + && is_dynamic_type_internal (type->target_type (), false)) > + return true; > + > + /* Same for function arguments */ > + for (int i = 0; i < type->num_fields (); ++i) > + if (is_dynamic_type_internal (type->field (i).type (), false)) > + return true; > + } > + break; > } > > return false; > @@ -2873,6 +2888,25 @@ resolve_dynamic_struct (struct type *type, > return resolved_type; > } > > +/* Resolve dynamic function's arguments/returned value types */ > +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 * > @@ -2971,6 +3005,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*/ > + 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..4ec67093936 > --- /dev/null > +++ b/gdb/nat/riscv-linux-ptrace.h > @@ -0,0 +1,31 @@ > +/* Copyright (C) 2025 Free Software Foundation, Inc. > + > + This file is part of GDB. > + > + This program is free software; you can redistribute it and/or modify > + it under the terms of the GNU General Public License as published by > + the Free Software Foundation; either version 3 of the License, or > + (at your option) any later version. > + > + This program is distributed in the hope that it will be useful, > + but WITHOUT ANY WARRANTY; without even the implied warranty of > + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the > + GNU General Public License for more details. > + > + You should have received a copy of the GNU General Public License > + along with this program. If not, see . */ > + > +#ifndef NAT_RISCV_LINUX_HW_PTRACE_H > +#define NAT_RISCV_LINUX_HW_PTRACE_H > + > +struct __riscv_v_regset_state > +{ > + unsigned long vstart; > + unsigned long vl; > + unsigned long vtype; > + unsigned long vcsr; > + unsigned long vlenb; > + char vreg[]; > +}; > + > +#endif // NAT_RISCV_LINUX_HW_PTRACE_H > diff --git a/gdb/nat/riscv-linux-tdesc.c b/gdb/nat/riscv-linux-tdesc.c > index 254a25ccefe..e7d6d29eea1 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 > +#define RISCV_HWPROBE_IMA_V (1 << 2) > +#endif > + > +struct riscv_hwprobe > +{ > + int64_t key; > + uint64_t value; > +}; > + > /* See nat/riscv-linux-tdesc.h. */ > > struct riscv_gdbarch_features > @@ -78,5 +99,17 @@ riscv_linux_read_features (int tid) > break; > } > > + features.vlenb = 0; > + > + static struct riscv_hwprobe query[] = { { RISCV_HWPROBE_KEY_IMA_EXT_0, 0 } }; > + > + if ((syscall (NR_riscv_hwprobe, query, 1, 0, NULL, 0) == 0) > + && (query[0].value & RISCV_HWPROBE_IMA_V)) > + { > + int reg = 0; > + asm volatile ("csrr %[vlenb], vlenb" : [vlenb] "=r"(reg)); > + features.vlenb = reg; > + } > + > return features; > } > diff --git a/gdb/riscv-linux-nat.c b/gdb/riscv-linux-nat.c > index 89f1ddc1b17..459654565a3 100644 > --- a/gdb/riscv-linux-nat.c > +++ b/gdb/riscv-linux-nat.c > @@ -24,10 +24,13 @@ > > #include "elf/common.h" > > +#include "nat/riscv-linux-ptrace.h" > #include "nat/riscv-linux-tdesc.h" > > #include > > +#include > + > /* Work around glibc header breakage causing ELF_NFPREG not to be usable. */ > #ifndef NFPREG > # define NFPREG 33 > @@ -132,6 +135,63 @@ 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 +255,63 @@ fill_fpregset (const struct regcache *regcache, prfpregset_t *fpregs, > } > } > > +static void > +fill_vecregset_regnum (regcache *regcache, __riscv_v_regset_state *vecregs, > + int regnum) > +{ > + if ((regnum >= RISCV_V0_REGNUM && regnum <= RISCV_V31_REGNUM)) > + { > + regcache->raw_collect ( > + regnum, vecregs->vreg + vecregs->vlenb * (regnum - RISCV_V0_REGNUM)); > + return; > + } > + > + if (regnum == RISCV_CSR_VSTART_REGNUM) > + { > + regcache->raw_collect (regnum, &vecregs->vstart); > + return; > + } > + > + if (regnum == RISCV_CSR_VCSR_REGNUM) > + { > + regcache->raw_collect (regnum, &vecregs->vcsr); > + return; > + } > + > + if (regnum == RISCV_CSR_VL_REGNUM) > + { > + regcache->raw_collect (regnum, &vecregs->vl); > + return; > + } > + > + if (regnum == RISCV_CSR_VTYPE_REGNUM) > + { > + regcache->raw_collect (regnum, &vecregs->vtype); > + return; > + } > + > + if (regnum == RISCV_CSR_VLENB_REGNUM) > + { > + regcache->raw_collect (regnum, &vecregs->vlenb); > + return; > + } > + > + if (regnum == -1) > + { > + regcache->raw_collect (RISCV_CSR_VSTART_REGNUM, &vecregs->vstart); > + regcache->raw_collect (RISCV_CSR_VCSR_REGNUM, &vecregs->vcsr); > + regcache->raw_collect (RISCV_CSR_VL_REGNUM, &vecregs->vl); > + regcache->raw_collect (RISCV_CSR_VTYPE_REGNUM, &vecregs->vtype); > + regcache->raw_collect (RISCV_CSR_VLENB_REGNUM, &vecregs->vlenb); > + > + for (int i = RISCV_V0_REGNUM; i <= RISCV_V31_REGNUM; i++) > + regcache->raw_collect ( > + i, vecregs->vreg + vecregs->vlenb * (i - RISCV_V0_REGNUM)); > + > + return; > + } > +} > + > /* Return a target description for the current target. */ > > const struct target_desc * > @@ -261,6 +378,29 @@ riscv_linux_nat_target::fetch_registers (struct regcache *regcache, int regnum) > regcache->raw_supply_zeroed (RISCV_CSR_MISA_REGNUM); > } > > + if (riscv_is_vpr_or_vcsr (regnum) || (regnum == -1)) > + { > + int vecreg_size = register_size (regcache->arch (), RISCV_V0_REGNUM); > + std::vector vregs_buff (sizeof (__riscv_v_regset_state) > + + vecreg_size * 32); > + > + __riscv_v_regset_state *vregs_state > + = (__riscv_v_regset_state *)vregs_buff.data (); > + > + iovec iov; > + iov.iov_base = vregs_state; > + iov.iov_len = sizeof (struct __riscv_v_regset_state) + 32 * vecreg_size; > + > + if (ptrace (PTRACE_GETREGSET, tid, NT_RISCV_VECTOR, > + (PTRACE_TYPE_ARG3)&iov) > + == 0 > + && vregs_state->vlenb > 0) > + { > + gdb_assert (vregs_state->vlenb == vecreg_size); > + supply_vecregset_regnum (regcache, vregs_state, regnum); > + } > + } > + > /* Access to other CSRs has potential security issues, don't support them for > now. */ > } > @@ -323,6 +463,30 @@ riscv_linux_nat_target::store_registers (struct regcache *regcache, int regnum) > } > } > > + if (riscv_is_vpr_or_vcsr (regnum) || (regnum == -1)) > + { > + int vecreg_size = register_size (regcache->arch (), RISCV_V0_REGNUM); > + std::vector vregs_buff (sizeof (__riscv_v_regset_state) > + + vecreg_size * 32); > + > + __riscv_v_regset_state *vregs_state > + = (__riscv_v_regset_state *)vregs_buff.data (); > + > + iovec iov; > + iov.iov_base = vregs_state; > + iov.iov_len = sizeof (struct __riscv_v_regset_state) + 32 * vecreg_size; > + > + if (ptrace (PTRACE_GETREGSET, tid, NT_RISCV_VECTOR, > + (PTRACE_TYPE_ARG3)&iov) > + == 0) > + { > + fill_vecregset_regnum (regcache, vregs_state, regnum); > + > + ptrace (PTRACE_SETREGSET, tid, NT_RISCV_VECTOR, > + (PTRACE_TYPE_ARG3)&iov); > + } > + } > + > /* Access to CSRs has potential security issues, don't support them for > now. */ > } > diff --git a/gdb/riscv-regs.h b/gdb/riscv-regs.h > new file mode 100644 > index 00000000000..e6b06445e6e > --- /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) 2025 Free Software Foundation, Inc. > + > + This file is part of GDB. > + > + This program is free software; you can redistribute it and/or modify > + it under the terms of the GNU General Public License as published by > + the Free Software Foundation; either version 3 of the License, or > + (at your option) any later version. > + > + This program is distributed in the hope that it will be useful, > + but WITHOUT ANY WARRANTY; without even the implied warranty of > + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the > + GNU General Public License for more details. > + > + You should have received a copy of the GNU General Public License > + along with this program. If not, see . */ > + > +#ifndef GDB_RISCV_REGS_H > +#define GDB_RISCV_REGS_H > + > +/* RiscV register numbers. */ > +enum > +{ > + RISCV_ZERO_REGNUM = 0, /* Read-only register, always 0. */ > + RISCV_RA_REGNUM = 1, /* Return Address. */ > + RISCV_SP_REGNUM = 2, /* Stack Pointer. */ > + RISCV_GP_REGNUM = 3, /* Global Pointer. */ > + RISCV_TP_REGNUM = 4, /* Thread Pointer. */ > + RISCV_FP_REGNUM = 8, /* Frame Pointer. */ > + RISCV_A0_REGNUM = 10, /* First argument. */ > + RISCV_A1_REGNUM = 11, /* Second argument. */ > + RISCV_A2_REGNUM = 12, /* Third argument. */ > + RISCV_A3_REGNUM = 13, /* Forth argument. */ > + RISCV_A4_REGNUM = 14, /* Fifth argument. */ > + RISCV_A5_REGNUM = 15, /* Sixth argument. */ > + RISCV_A7_REGNUM = 17, /* Register to pass syscall number. */ > + RISCV_PC_REGNUM = 32, /* Program Counter. */ > + > + RISCV_NUM_INTEGER_REGS = 32, > + > + RISCV_FIRST_FP_REGNUM = 33, /* First Floating Point Register */ > + RISCV_FA0_REGNUM = 43, > + RISCV_FA1_REGNUM = RISCV_FA0_REGNUM + 1, > + RISCV_LAST_FP_REGNUM = 64, /* Last Floating Point Register */ > + > + RISCV_FIRST_CSR_REGNUM = 65, /* First CSR */ > +#define DECLARE_CSR(name, num, class, define_version, abort_version) \ > + RISCV_ ## num ## _REGNUM = RISCV_FIRST_CSR_REGNUM + num, > +#include "opcode/riscv-opc.h" > +#undef DECLARE_CSR > + RISCV_LAST_CSR_REGNUM = 4160, > + RISCV_CSR_LEGACY_MISA_REGNUM = 0xf10 + RISCV_FIRST_CSR_REGNUM, > + > + RISCV_PRIV_REGNUM = 4161, > + > + RISCV_V0_REGNUM, > + > + RISCV_V31_REGNUM = RISCV_V0_REGNUM + 31, > + > + RISCV_LAST_REGNUM = RISCV_V31_REGNUM > +}; > + > +/* RiscV DWARF register numbers. */ > +enum > +{ > + RISCV_DWARF_REGNUM_X0 = 0, > + RISCV_DWARF_REGNUM_X31 = 31, > + RISCV_DWARF_REGNUM_F0 = 32, > + RISCV_DWARF_REGNUM_F31 = 63, > + RISCV_DWARF_REGNUM_V0 = 96, > + RISCV_DWARF_REGNUM_V31 = 127, > + RISCV_DWARF_FIRST_CSR = 4096, > + RISCV_DWARF_LAST_CSR = 8191, > +}; > + > +#endif /* GDB_RISCV_REGS_H */ > diff --git a/gdb/riscv-tdep.c b/gdb/riscv-tdep.c > index 76d10a3b298..03587e14418 100644 > --- a/gdb/riscv-tdep.c > +++ b/gdb/riscv-tdep.c > @@ -17,6 +17,8 @@ > You should have received a copy of the GNU General Public License > along with this program. If not, see . */ > > +#include > + > #include "extract-store-integer.h" > #include "frame.h" > #include "inferior.h" > @@ -57,6 +59,13 @@ > #include "record-full.h" > #include "riscv-ravenscar-thread.h" > > +#include > +#include > +#include > +#include > +#include > +#include > +#include > #include > > /* The stack must be 16-byte aligned. */ > @@ -619,39 +628,23 @@ struct riscv_vector_feature : public riscv_register_feature > riscv_vector_feature () > : riscv_register_feature (riscv_feature_name_vector) > { > - m_registers = { > - { RISCV_V0_REGNUM + 0, { "v0" } }, > - { RISCV_V0_REGNUM + 1, { "v1" } }, > - { RISCV_V0_REGNUM + 2, { "v2" } }, > - { RISCV_V0_REGNUM + 3, { "v3" } }, > - { RISCV_V0_REGNUM + 4, { "v4" } }, > - { RISCV_V0_REGNUM + 5, { "v5" } }, > - { RISCV_V0_REGNUM + 6, { "v6" } }, > - { RISCV_V0_REGNUM + 7, { "v7" } }, > - { RISCV_V0_REGNUM + 8, { "v8" } }, > - { RISCV_V0_REGNUM + 9, { "v9" } }, > - { RISCV_V0_REGNUM + 10, { "v10" } }, > - { RISCV_V0_REGNUM + 11, { "v11" } }, > - { RISCV_V0_REGNUM + 12, { "v12" } }, > - { RISCV_V0_REGNUM + 13, { "v13" } }, > - { RISCV_V0_REGNUM + 14, { "v14" } }, > - { RISCV_V0_REGNUM + 15, { "v15" } }, > - { RISCV_V0_REGNUM + 16, { "v16" } }, > - { RISCV_V0_REGNUM + 17, { "v17" } }, > - { RISCV_V0_REGNUM + 18, { "v18" } }, > - { RISCV_V0_REGNUM + 19, { "v19" } }, > - { RISCV_V0_REGNUM + 20, { "v20" } }, > - { RISCV_V0_REGNUM + 21, { "v21" } }, > - { RISCV_V0_REGNUM + 22, { "v22" } }, > - { RISCV_V0_REGNUM + 23, { "v23" } }, > - { RISCV_V0_REGNUM + 24, { "v24" } }, > - { RISCV_V0_REGNUM + 25, { "v25" } }, > - { RISCV_V0_REGNUM + 26, { "v26" } }, > - { RISCV_V0_REGNUM + 27, { "v27" } }, > - { RISCV_V0_REGNUM + 28, { "v28" } }, > - { RISCV_V0_REGNUM + 29, { "v29" } }, > - { RISCV_V0_REGNUM + 30, { "v30" } }, > - { RISCV_V0_REGNUM + 31, { "v31" } }, > + m_registers = { > + { RISCV_V0_REGNUM + 0, { "v0" } }, { RISCV_V0_REGNUM + 1, { "v1" } }, > + { RISCV_V0_REGNUM + 2, { "v2" } }, { RISCV_V0_REGNUM + 3, { "v3" } }, > + { RISCV_V0_REGNUM + 4, { "v4" } }, { RISCV_V0_REGNUM + 5, { "v5" } }, > + { RISCV_V0_REGNUM + 6, { "v6" } }, { RISCV_V0_REGNUM + 7, { "v7" } }, > + { RISCV_V0_REGNUM + 8, { "v8" } }, { RISCV_V0_REGNUM + 9, { "v9" } }, > + { RISCV_V0_REGNUM + 10, { "v10" } }, { RISCV_V0_REGNUM + 11, { "v11" } }, > + { RISCV_V0_REGNUM + 12, { "v12" } }, { RISCV_V0_REGNUM + 13, { "v13" } }, > + { RISCV_V0_REGNUM + 14, { "v14" } }, { RISCV_V0_REGNUM + 15, { "v15" } }, > + { RISCV_V0_REGNUM + 16, { "v16" } }, { RISCV_V0_REGNUM + 17, { "v17" } }, > + { RISCV_V0_REGNUM + 18, { "v18" } }, { RISCV_V0_REGNUM + 19, { "v19" } }, > + { RISCV_V0_REGNUM + 20, { "v20" } }, { RISCV_V0_REGNUM + 21, { "v21" } }, > + { RISCV_V0_REGNUM + 22, { "v22" } }, { RISCV_V0_REGNUM + 23, { "v23" } }, > + { RISCV_V0_REGNUM + 24, { "v24" } }, { RISCV_V0_REGNUM + 25, { "v25" } }, > + { RISCV_V0_REGNUM + 26, { "v26" } }, { RISCV_V0_REGNUM + 27, { "v27" } }, > + { RISCV_V0_REGNUM + 28, { "v28" } }, { RISCV_V0_REGNUM + 29, { "v29" } }, > + { RISCV_V0_REGNUM + 30, { "v30" } }, { RISCV_V0_REGNUM + 31, { "v31" } }, > }; > } > > @@ -660,10 +653,14 @@ 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 +676,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 +693,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 +712,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 +793,25 @@ riscv_abi_xlen (struct gdbarch *gdbarch) > > /* See riscv-tdep.h. */ > > +int > +riscv_isa_vlenb (struct gdbarch *gdbarch) > +{ > + riscv_gdbarch_tdep *tdep = gdbarch_tdep (gdbarch); > + return tdep->isa_features.vlenb; > +} > + > +/* Return true if GDBARCH is using vector hardware ABI. */ > + > +static bool > +riscv_has_vector_abi (struct gdbarch *gdbarch) > +{ > + gdb_assert (gdbarch); > + riscv_gdbarch_tdep *tdep = gdbarch_tdep (gdbarch); > + return tdep->abi_features.vlenb > 0; > +} > + > +/* See riscv-tdep.h. */ > + > int > riscv_isa_flen (struct gdbarch *gdbarch) > { > @@ -1211,7 +1230,7 @@ riscv_print_one_register_info (struct gdbarch *gdbarch, > struct value_print_options opts; > riscv_gdbarch_tdep *tdep = gdbarch_tdep (gdbarch); > > - /* Print the register in hex. */ > + /* Print the register in hex, exclude vector registers. */ > get_formatted_print_options (&opts, 'x'); > opts.deref_ref = true; > common_val_print (val, file, 0, &opts, current_language); > @@ -1339,17 +1358,45 @@ 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) > - { > - get_user_print_options (&opts); > - 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) > + { > + get_user_print_options (&opts); > + opts.deref_ref = true; > + gdb_printf (file, "\t"); > + common_val_print (val, file, 0, &opts, current_language); > } > } > } > @@ -1469,7 +1516,7 @@ riscv_register_reggroup_p (struct gdbarch *gdbarch, int regnum, > return 0; > } > else if (reggroup == vector_reggroup) > - return (regnum >= RISCV_V0_REGNUM && regnum <= RISCV_V31_REGNUM); > + return riscv_is_vpr_or_vcsr (regnum); > else > return 0; > } > @@ -2654,18 +2701,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 as an on stack argument. */ > - on_stack, > + /* 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 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 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; > > /* Information that depends on the location type. */ > union > @@ -2714,13 +2768,98 @@ struct riscv_arg_reg > /* Nothing. */ > } > > - /* The GDB register number to use in this set. */ > + /* The GDB register number to use in this set. */ > int next_regnum; > > - /* The last GDB register number to use in this set. */ > + /* The last GDB register number to use in this set. */ > int last_regnum; > }; > > +struct riscv_vector_arg_reg_interval > +{ > + int first; > + int last; > +}; > + > +struct riscv_vector_arg_reg > +{ > + riscv_vector_arg_reg (int first, int last) > + : available_intervals{ { first, last } } > + { > + /* Nothing. */ > + } > + > + int > + get_interval_start (int count, int NFIELDS = 1) > + { > + gdb_assert (count % NFIELDS == 0); > + > + int LMUL = count / NFIELDS; > + for (auto cur_interval = available_intervals.begin (); > + cur_interval != available_intervals.end (); ++cur_interval) > + { > + int cur_first = cur_interval->first; > + int cur_last = cur_interval->last; > + if ((cur_first - RISCV_V0_REGNUM) % LMUL > + != 0) /* According to RISC-V Vector ABI, > + first register number should be > + a multiple of LMUL */ > + { > + cur_first -= (cur_first - RISCV_V0_REGNUM) % LMUL; > + cur_first += LMUL; > + } > + > + if ((cur_last - cur_first + 1) >= count) > + { > + if (cur_first > cur_interval->first) > + { > + available_intervals.insert ( > + cur_interval, { cur_interval->first, cur_first - 1 }); > + } > + > + cur_interval->first = cur_first + count; > + > + return cur_first; > + } > + } > + > + return -1; > + } > + > + int > + try_use_v0 () > + { > + if (is_v0_used) > + return get_interval_start (1); > + else > + { > + is_v0_used = true; > + return RISCV_V0_REGNUM; > + } > + } > + > + bool is_v0_used = false; > + > + std::list available_intervals; > + > + /* From RISCV-ABI, Standard Vector Calling Convention Variant: > + The rules for passing vector arguments are as follows: > + 1. For the first vector mask argument, use v0 to pass it. > + 2. For vector data arguments or rest vector mask arguments, starting > + from the v8 register, if a vector register group between v8-v23 that has > + not been allocated can be found and the first register number is a > + multiple of LMUL, then allocate this vector register group to the argument > + and mark these registers as allocated. Otherwise, pass it by reference and > + are replaced in the 12 argument list with the address. > + 3. For tuple vector data arguments, starting from the v8 register, if > + NFIELDS consecutive vector register groups between v8-v23 that have not > + been allocated can be found and the first register number is a multiple of > + LMUL, then allocate these vector register groups to the argument and mark > + these registers as allocated. Otherwise, pass it by reference and are > + replaced in the argument list with the address > + */ > +}; > + > /* Arguments can be passed as on stack arguments, or by reference. The > on stack arguments must be in a continuous region starting from $sp, > while the by reference arguments can be anywhere, but we'll put them > @@ -2757,11 +2896,17 @@ struct riscv_memory_offsets > 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) > + : int_regs (RISCV_A0_REGNUM, RISCV_A0_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). */ > @@ -2771,6 +2916,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 > @@ -2785,10 +2934,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 > @@ -2830,6 +2984,291 @@ 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. */ > + unsigned sew = 0; > + > + /* Length Multiplier, amount of registers used for this type. */ > + unsigned lmul = 0; > + > + /* For non-tuple types, nfield = 1. */ > + unsigned nfield = 0; > + > + enum class rvv_elem_type : char > + { > + RVV_INT, > + RVV_UINT, > + RVV_FLOAT, > + RVV_BOOL, > + RVV_UNKNOWN, > + } element_type > + = rvv_elem_type::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; > +}; > + > +/* verify_rvv_type() only checks those unavailable configurations. > + Unavailable configurations: > + 1) lmul == 1 && is_fractional_lmul == true > + 2) RVV_FLOAT && sew == 8 > + 3) (sew == 1,2,4) && !RVV_BOOL > + 4) (lmul != 1 || nfield != 1) && RVV_BOOL */ > +static bool > +verify_rvv_type (rvv_type_info type_info) > +{ > + if (type_info.lmul == 1 && type_info.is_fractional_lmul) > + return false; > + > + switch (type_info.element_type) > + { > + case rvv_type_info::rvv_elem_type::RVV_FLOAT: > + if (type_info.sew == 8) > + return false; > + [[fallthrough]]; > + > + case rvv_type_info::rvv_elem_type::RVV_INT: > + case rvv_type_info::rvv_elem_type::RVV_UINT: > + return (type_info.sew != 1 && type_info.sew != 2 && type_info.sew != 4); > + > + case rvv_type_info::rvv_elem_type::RVV_BOOL: > + return (type_info.lmul == 1 && type_info.nfield == 1); > + > + default: > + return false; > + } > + > + gdb_assert_not_reached ("Uknown element type: %c", > + static_cast (type_info.element_type)); > +} > + > +static std::optional > +get_rvv_type_info_unverified (struct type *type) > +{ > + if (!type) > + return std::nullopt; > + > + type = check_typedef (type); > + > + if (!type->name ()) > + { > + riscv_infcall_debug_printf ( > + "The type name is missing, unable to get RVV type info."); > + return std::nullopt; > + } > + > + if (type->code () != TYPE_CODE_ARRAY && type->code () != TYPE_CODE_STRUCT) > + { > + riscv_infcall_debug_printf ("Incorrect type_code: %d. Expected %d " > + "(TYPE_CODE_ARRAY) or %d (TYPE_CODE_STRUCT)", > + type->code (), TYPE_CODE_ARRAY, > + TYPE_CODE_STRUCT); > + return std::nullopt; > + } > + > + struct rvv_type_name_mapping_t > + { > + const char *name; > + rvv_type_info::rvv_elem_type type; > + }; > + constexpr std::array rvv_type_names = { > + rvv_type_name_mapping_t{ "int", rvv_type_info::rvv_elem_type::RVV_INT }, > + rvv_type_name_mapping_t{ "uint", rvv_type_info::rvv_elem_type::RVV_UINT }, > + rvv_type_name_mapping_t{ "float", > + rvv_type_info::rvv_elem_type::RVV_FLOAT }, > + rvv_type_name_mapping_t{ "bool", rvv_type_info::rvv_elem_type::RVV_BOOL } > + }; > + std::string regex_string ("__rvv_("); > + std::string separator = ""; > + for (auto type_name : rvv_type_names) > + { > + regex_string += separator + type_name.name; > + separator = "|"; > + } > + regex_string += ")(1|2|4|8|16|32|64)((m|mf)([1248]))?(x([2-8]))?_t"; > + > + std::regex rvv_type_regex (regex_string); > + std::cmatch matches; > + if (!std::regex_search (type->name (), matches, rvv_type_regex)) > + { > + riscv_infcall_debug_printf ("Failed to match RVV type name: %s", > + type->name ()); > + return std::nullopt; > + } > + /* 'matches' content example for name __rvv_int32mf2x4_t: > + ["__rvv_vint32mf2x4_t", "int", "32", "mf2", "mf", "2", "x4", "4"] > + 'matches' content example for name __rvv_bool8_t: > + ["__rvv_bool8_t", "bool", "8", "", "", "", "", ""] */ > + > + std::string_view parsed_name (matches[1].first, matches[1].length ()); > + std::string_view parsed_sew (matches[2].first, matches[2].length ()); > + std::string_view parsed_lmul_str (matches[3].first, matches[3].length ()); > + std::string_view parsed_lmul_type (matches[4].first, matches[4].length ()); > + std::string_view parsed_lmul_val (matches[5].first, matches[5].length ()); > + std::string_view parsed_nfield_str (matches[6].first, matches[6].length ()); > + std::string_view parsed_nfield_val (matches[7].first, matches[7].length ()); > + > + rvv_type_info res; > + > + auto it = std::find_if ( > + rvv_type_names.begin (), rvv_type_names.end (), > + [parsed_name] (const rvv_type_name_mapping_t &type_name) { > + return parsed_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 (std::from_chars (parsed_sew.data (), > + parsed_sew.data () + parsed_sew.size (), res.sew) > + .ec > + != std::errc{}) > + { > + riscv_infcall_debug_printf ( > + "Failed to convert SEW string (%s) to unsigned", parsed_sew.data ()); > + return std::nullopt; > + } > + > + if (!parsed_lmul_str.empty ()) > + { > + if (parsed_lmul_type.compare ("mf") == 0) > + res.is_fractional_lmul = true; > + else > + res.is_fractional_lmul = false; > + > + if (std::from_chars (parsed_lmul_val.data (), > + parsed_lmul_val.data () + parsed_lmul_val.size (), > + res.lmul) > + .ec > + != std::errc{}) > + { > + riscv_infcall_debug_printf ( > + "Failed to convert LMUL string (%s) to unsigned", > + parsed_lmul_val.data ()); > + return std::nullopt; > + } > + } > + else > + res.lmul = 1; > + > + if (!parsed_nfield_str.empty ()) > + { > + if (std::from_chars (parsed_nfield_val.data (), > + parsed_nfield_val.data () > + + parsed_nfield_val.size (), > + res.nfield) > + .ec > + != std::errc{}) > + { > + riscv_infcall_debug_printf ( > + "Failed to convert NFIELD string (%s) to unsigned", > + parsed_nfield_val.data ()); > + return std::nullopt; > + } > + } > + else > + res.nfield = 1; > + > + return res; > +} > + > +static std::optional > +get_rvv_type_info (struct type *type) > +{ > + std::optional res = get_rvv_type_info_unverified (type); > + > + if (res.has_value () && verify_rvv_type (res.value ())) > + return res; > + > + return std::nullopt; > +} > + > +static bool > +is_rvv_type (struct type *type) > +{ > + return get_rvv_type_info (type).has_value (); > +} > + > +static bool > +riscv_assign_vec_reg_location (struct riscv_arg_info *ainfo, > + struct riscv_vector_arg_reg *reg, > + struct type *func_arg_type, int vlenb) > +{ > + int data_length = vlenb; /* Amount of data that is stored on one register */ > + > + struct riscv_arg_info::location *loc0 = &ainfo->argloc[0]; > + struct riscv_arg_info::location *loc1 = &ainfo->argloc[1]; > + > + rvv_type_info arg_type_info; > + if (std::optional res = get_rvv_type_info (func_arg_type)) > + arg_type_info = res.value (); > + else > + gdb_assert_not_reached ("Incorrect type %s", func_arg_type->name ()); > + > + riscv_infcall_debug_printf ( > + "rvv_type_info of %s: element_type = %d, sew = %u, lmul = %u (%s " > + "fractional), nfield = %u", > + func_arg_type->name (), static_cast (arg_type_info.element_type), > + arg_type_info.sew, arg_type_info.lmul, > + (arg_type_info.is_fractional_lmul ? "is" : "is not"), > + arg_type_info.nfield); > + > + int num_required_regs > + = ((arg_type_info.is_fractional_lmul) ? 1 : arg_type_info.lmul) > + * arg_type_info.nfield; > + > + if (arg_type_info.is_fractional_lmul) > + { > + num_required_regs = arg_type_info.nfield; > + data_length = data_length / 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, > + arg_type_info.nfield); > + } > + else if (ainfo->type->code () == TYPE_CODE_STRUCT) > + { > + first_regnum > + = reg->get_interval_start (num_required_regs, 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. > @@ -3238,21 +3677,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 (); > @@ -3262,6 +3724,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 */ > + { > + riscv_call_arg_vector (ainfo, cinfo, func_arg_type); > + return; > + } > + > switch (ainfo->type->code ()) > { > case TYPE_CODE_INT: > @@ -3384,6 +3852,13 @@ 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"); > } > @@ -3398,15 +3873,13 @@ static void > riscv_regcache_cooked_write (int regnum, const gdb_byte *data, int len, > struct regcache *regcache, int flen) > { > - gdb_byte tmp [sizeof (ULONGEST)]; > - > + int regsize = register_size (regcache->arch (), regnum); > + std::vector tmp (regsize); > /* FP values in FP registers must be NaN-boxed. */ > if (riscv_is_fp_regno_p (regnum) && len < flen) > - memset (tmp, -1, sizeof (tmp)); > - else > - memset (tmp, 0, sizeof (tmp)); > - memcpy (tmp, data, len); > - regcache->cooked_write (regnum, tmp); > + memset (tmp.data (), -1, tmp.size ()); > + memcpy (tmp.data (), data, len); > + regcache->cooked_write (regnum, tmp.data ()); > } > > /* Implement the push dummy call gdbarch callback. */ > @@ -3446,16 +3919,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 (); > } > > @@ -3466,14 +3944,18 @@ riscv_push_dummy_call (struct gdbarch *gdbarch, > if (riscv_debug_infcall) > { > 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_infcall_debug_printf ( > + "floating point ABI %s in use", > + (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]; > @@ -3547,6 +4029,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"); > } > @@ -3577,6 +4075,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*/ > default: > /* The second location should never be a reference, any > argument being passed by reference just places its address > @@ -3615,9 +4115,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) > { > @@ -3770,9 +4275,41 @@ 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")); > + error (_ ("invalid argument location")); > break; > } > > @@ -3804,6 +4341,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; > @@ -3973,6 +4511,28 @@ 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 march_str (march); > + if (march_str.find ("_v") != std::string::npos) > + features.vlenb = 16; > + else if (march_str.find ("_zve64") != std::string::npos) > + features.vlenb = 8; > + else if (march_str.find ("_zve32") != std::string::npos) > + features.vlenb = 4; > + else > + features.vlenb = 0; > + } > + else > + features.vlenb = 0; > } > > return features; > @@ -4266,18 +4826,24 @@ riscv_gdbarch_init (struct gdbarch_info info, > however, this has not been tested in GDB yet, so for now we require > that the requested xlen match the targets xlen. */ > if (abi_features.xlen != features.xlen) > - error (_("bfd requires xlen %d, but target has xlen %d"), > - abi_features.xlen, features.xlen); > + error (_ ("bfd requires xlen %d, but target has xlen %d"), > + abi_features.xlen, features.xlen); > /* We do support running binaries compiled for 32-bit float on targets > with 64-bit float, so we only complain if the binary requires more > than the target has available. */ > if (abi_features.flen > features.flen) > - error (_("bfd requires flen %d, but target has flen %d"), > - abi_features.flen, features.flen); > + error (_ ("bfd requires flen %d, but target has flen %d"), > + abi_features.flen, features.flen); > + > + /* Look at riscv_features_from_bfd*/ > + if ((abi_features.vlenb > 0) && (features.vlenb == 0)) > + { > + warning (_ ("bfd requires non-zero vlenb, but target has vlenb = 0, " > + "vector registers unsupported")); > + } > > /* Find a candidate among the list of pre-declared architectures. */ > - for (arches = gdbarch_list_lookup_by_info (arches, &info); > - arches != NULL; > + for (arches = gdbarch_list_lookup_by_info (arches, &info); arches != NULL; > arches = gdbarch_list_lookup_by_info (arches->next, &info)) > { > /* Check that the feature set of the ARCHES matches the feature set > @@ -5388,3 +5954,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 2903aefd007..91dd01dac62 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); > + > /* Single step based on where the current instruction will take us. */ > extern std::vector riscv_software_single_step > (struct regcache *regcache); > @@ -194,4 +144,7 @@ extern int riscv_process_record (struct gdbarch *gdbarch, > /* The names of the RISC-V target description features. */ > extern const char *riscv_feature_name_csr; > > +/* Determines if regnum corresponds to vector register vX or vector CSR. */ > +extern bool riscv_is_vpr_or_vcsr (unsigned regnum); > + > #endif /* GDB_RISCV_TDEP_H */ > diff --git a/gdbserver/linux-riscv-low.cc b/gdbserver/linux-riscv-low.cc > index f70ed597051..82362542c19 100644 > --- a/gdbserver/linux-riscv-low.cc > +++ b/gdbserver/linux-riscv-low.cc > @@ -21,6 +21,7 @@ > #include "linux-low.h" > #include "tdesc.h" > #include "elf/common.h" > +#include "nat/riscv-linux-ptrace.h" > #include "nat/riscv-linux-tdesc.h" > #include "opcode/riscv.h" > > @@ -102,26 +103,6 @@ riscv_target::low_get_syscall_trapinfo (regcache *regcache, int *sysno) > *sysno = (int)l_sysno; > } > > -/* Implementation of linux target ops method "low_arch_setup". */ > - > -void > -riscv_target::low_arch_setup () > -{ > - static const char *expedite_regs[] = { "sp", "pc", NULL }; > - > - const riscv_gdbarch_features features > - = riscv_linux_read_features (current_thread->id.lwp ()); > - target_desc_up tdesc = riscv_create_target_description (features); > - > - if (tdesc->expedite_regs.empty ()) > - { > - init_target_desc (tdesc.get (), expedite_regs, GDB_OSABI_LINUX); > - gdb_assert (!tdesc->expedite_regs.empty ()); > - } > - > - current_process ()->tdesc = tdesc.release (); > -} > - > /* Collect GPRs from REGCACHE into BUF. */ > > static void > @@ -185,25 +166,76 @@ riscv_store_fpregset (struct regcache *regcache, const void *buf) > supply_register_by_name (regcache, "fcsr", regbuf); > } > > +/* Collect vector regs from REGCACHE into BUF. */ > + > +static void > +riscv_fill_vecregset (struct regcache *regcache, void *buf) > +{ > + const struct target_desc *tdesc = regcache->tdesc; > + int v0_regno = find_regno (tdesc, "v0"); > + > + struct __riscv_v_regset_state *vecregs > + = (struct __riscv_v_regset_state *)buf; > + unsigned long vlenb = vecregs->vlenb; > + gdb_byte *regbuf = (gdb_byte *)vecregs->vreg; > + > + for (int i = 0; i < 32; i++, regbuf += vlenb) > + collect_register (regcache, v0_regno + i, regbuf); > + > + collect_register_by_name (regcache, "vstart", &vecregs->vstart); > + collect_register_by_name (regcache, "vcsr", &vecregs->vcsr); > + collect_register_by_name (regcache, "vl", &vecregs->vl); > + collect_register_by_name (regcache, "vtype", &vecregs->vtype); > + collect_register_by_name (regcache, "vlenb", &vecregs->vlenb); > +} > + > +/* Supply vector regs from BUF into REGCACHE. */ > + > +static void > +riscv_store_vecregset (struct regcache *regcache, const void *buf) > +{ > + const struct target_desc *tdesc = regcache->tdesc; > + int v0_regno = find_regno (tdesc, "v0"); > + > + const struct __riscv_v_regset_state *vecregs > + = (const struct __riscv_v_regset_state *)buf; > + if (vecregs->vlenb == 0) > + return; > + int v0_regsize = register_size (tdesc, v0_regno); > + gdb_assert (vecregs->vlenb == v0_regsize); > + unsigned long vlenb = vecregs->vlenb; > + const gdb_byte *regbuf = (const gdb_byte *)vecregs->vreg; > + > + for (int i = 0; i < 32; i++, regbuf += vlenb) > + supply_register (regcache, v0_regno + i, regbuf); > + > + supply_register_by_name (regcache, "vstart", &vecregs->vstart); > + supply_register_by_name (regcache, "vcsr", &vecregs->vcsr); > + supply_register_by_name (regcache, "vl", &vecregs->vl); > + supply_register_by_name (regcache, "vtype", &vecregs->vtype); > + supply_register_by_name (regcache, "vlenb", &vecregs->vlenb); > +} > + > /* 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 > the right one according to size. */ > -static struct regset_info riscv_regsets[] = { > - { PTRACE_GETREGSET, PTRACE_SETREGSET, NT_PRSTATUS, > - sizeof (elf_gregset_t), GENERAL_REGS, > - riscv_fill_gregset, riscv_store_gregset }, > - { PTRACE_GETREGSET, PTRACE_SETREGSET, NT_FPREGSET, > - sizeof (struct __riscv_mc_q_ext_state), OPTIONAL_REGS, > - riscv_fill_fpregset, riscv_store_fpregset }, > - { PTRACE_GETREGSET, PTRACE_SETREGSET, NT_FPREGSET, > - sizeof (struct __riscv_mc_d_ext_state), OPTIONAL_REGS, > - riscv_fill_fpregset, riscv_store_fpregset }, > - { PTRACE_GETREGSET, PTRACE_SETREGSET, NT_FPREGSET, > - sizeof (struct __riscv_mc_f_ext_state), OPTIONAL_REGS, > - riscv_fill_fpregset, riscv_store_fpregset }, > - NULL_REGSET > -}; > +static struct regset_info riscv_regsets[] > + = { { PTRACE_GETREGSET, PTRACE_SETREGSET, NT_PRSTATUS, > + sizeof (elf_gregset_t), GENERAL_REGS, riscv_fill_gregset, > + riscv_store_gregset }, > + { PTRACE_GETREGSET, PTRACE_SETREGSET, NT_FPREGSET, > + sizeof (struct __riscv_mc_q_ext_state), OPTIONAL_REGS, > + riscv_fill_fpregset, riscv_store_fpregset }, > + { PTRACE_GETREGSET, PTRACE_SETREGSET, NT_FPREGSET, > + sizeof (struct __riscv_mc_d_ext_state), OPTIONAL_REGS, > + riscv_fill_fpregset, riscv_store_fpregset }, > + { 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, 0, > + EXTENDED_REGS, riscv_fill_vecregset, riscv_store_vecregset }, > + NULL_REGSET }; > > /* RISC-V/Linux regset information. */ > static struct regsets_info riscv_regsets_info = > @@ -229,6 +261,44 @@ riscv_target::get_regs_info () > return &riscv_regs; > } > > +/* Setup Vector Regset. */ > +static void > +setup_vector_regset (struct regset_info *vector_regset_info, > + const riscv_gdbarch_features *features) > +{ > + int vecreg_size = features->vlenb * 8; > + vector_regset_info->size > + = sizeof (struct __riscv_v_regset_state) + 32 * vecreg_size; > +} > + > +/* Implementation of linux target ops method "low_arch_setup". */ > + > +void > +riscv_target::low_arch_setup () > +{ > + static const char *expedite_regs[] = { "sp", "pc", NULL }; > + > + const riscv_gdbarch_features features > + = riscv_linux_read_features (current_thread->id.lwp ()); > + target_desc_up tdesc = riscv_create_target_description (features); > + > + struct regset_info *regset; > + for (regset = riscv_regsets; regset->size >= 0; regset++) > + if (regset->nt_type == NT_RISCV_VECTOR) > + { > + setup_vector_regset (regset, &features); > + break; > + } > + > + if (tdesc->expedite_regs.empty ()) > + { > + init_target_desc (tdesc.get (), expedite_regs, GDB_OSABI_LINUX); > + gdb_assert (!tdesc->expedite_regs.empty ()); > + } > + > + current_process ()->tdesc = tdesc.release (); > +} > + > /* Implementation of linux target ops method "low_fetch_register". */ > > bool > diff --git a/gdbsupport/common-utils.h b/gdbsupport/common-utils.h > index 10bf9f49e2a..a29aa8edfa4 100644 > --- a/gdbsupport/common-utils.h > +++ b/gdbsupport/common-utils.h > @@ -20,12 +20,14 @@ > #ifndef GDBSUPPORT_COMMON_UTILS_H > #define GDBSUPPORT_COMMON_UTILS_H > > +#include > #include > #include > #include "gdbsupport/byte-vector.h" > #include "gdbsupport/gdb_unique_ptr.h" > #include "gdbsupport/array-view.h" > #include "poison.h" > +#include > #include > > #if defined HAVE_LIBXXHASH > diff --git a/include/elf/common.h b/include/elf/common.h > index 5d0f93ebf56..f3bc367b962 100644 > --- a/include/elf/common.h > +++ b/include/elf/common.h > @@ -776,6 +776,7 @@ > /* note name must be "LINUX". */ > #define NT_RISCV_CSR 0x900 /* RISC-V Control and Status Registers */ > /* note name must be "LINUX". */ > +#define NT_RISCV_VECTOR 0x901 /* RISC-V Vector Registers. */ > #define NT_SIGINFO 0x53494749 /* Fields of siginfo_t. */ > #define NT_FILE 0x46494c45 /* Description of mapped files. */ >