From: Farid Khaidari <khaidari.fg@gmail.com>
To: gdb-patches@sourceware.org
Cc: Andrew Burgess <aburgess@redhat.com>,
Palmer Dabbelt <palmer@dabbelt.com>,
Timur Golubovich <timurgol007@gmail.com>,
Kevin Buettner <kevinb@redhat.com>
Subject: [PATCH v2 2/4] gdb/riscv: recover core file ISA features from AT_HWCAP
Date: Mon, 26 Oct 2026 12:56:44 +0300 [thread overview]
Message-ID: <20261026095647.3035166-3-khaidari.fg@gmail.com> (raw)
In-Reply-To: <20261026095647.3035166-1-khaidari.fg@gmail.com>
When a core has neither a float ABI in e_flags nor an NT_FPREGSET
note, the RISC-V Linux core_read_description hook now reads AT_HWCAP
from the core's auxv and takes FLEN from the F and D bits.
The V bit is ignored. AT_HWCAP gives no vector length, and a guessed
vlen would give the vector registers the wrong size.
The test core is a real Linux core dump with NT_FPREGSET removed, so
AT_HWCAP (0x20112d, rv64imafdcv) is the only source of FP information.
Its V bit also lets the test check that GDB adds no vector registers.
Signed-off-by: Farid Khaidari <khaidari.fg@gmail.com>
---
gdb/riscv-linux-tdep.c | 72 +++++++++++++++++-
.../gdb.arch/riscv-core-hwcap.core.bz2 | Bin 0 -> 3229 bytes
gdb/testsuite/gdb.arch/riscv-core-hwcap.exp | 67 ++++++++++++++++
3 files changed, 137 insertions(+), 2 deletions(-)
create mode 100644 gdb/testsuite/gdb.arch/riscv-core-hwcap.core.bz2
create mode 100644 gdb/testsuite/gdb.arch/riscv-core-hwcap.exp
diff --git a/gdb/riscv-linux-tdep.c b/gdb/riscv-linux-tdep.c
index 594f6a36f89..707852e8f54 100644
--- a/gdb/riscv-linux-tdep.c
+++ b/gdb/riscv-linux-tdep.c
@@ -31,6 +31,7 @@
#include "linux-record.h"
#include "riscv-linux-tdep.h"
#include "inferior.h"
+#include "auxv.h"
#include "gdbsupport/selftest.h"
extern unsigned int record_debug;
@@ -547,12 +548,43 @@ riscv_linux_flen_from_fpregset_size (bfd_size_type size)
return 0;
}
+/* The AT_HWCAP bit for a single-letter ISA extension (COMPAT_HWCAP_ISA_*
+ in arch/riscv/include/asm/hwcap.h). */
+
+static constexpr ULONGEST
+riscv_hwcap_isa (char ext)
+{
+ gdb_assert (ext >= 'a' && ext <= 'z');
+ return ULONGEST{ 1 } << (ext - 'a');
+}
+
+/* Refine FEATURES with the F and D bits of the AT_HWCAP mask HWCAP,
+ which imply the FLEN. Only fields still at their unknown value (0)
+ are filled in, so a width already recovered from the core wins.
+
+ The V bit is deliberately ignored: AT_HWCAP carries no vector
+ length, and a target description with a guessed vlen would
+ misrepresent the vector registers. */
+
+static void
+riscv_apply_hwcap (struct riscv_gdbarch_features &features, ULONGEST hwcap)
+{
+ if (features.flen != 0)
+ return;
+
+ if ((hwcap & riscv_hwcap_isa ('d')) != 0)
+ features.flen = riscv_flen_d;
+ else if ((hwcap & riscv_hwcap_isa ('f')) != 0)
+ features.flen = riscv_flen_f;
+}
+
/* Implement the "core_read_description" gdbarch method.
A core dumped by the Linux kernel has no float ABI in its e_flags, so
if ABFD has an NT_FPREGSET note (the ".reg2" pseudo-section), recover
- the FLEN from its size. A core with an NT_GDB_TDESC note never gets
- here; the core target uses that note directly. */
+ the FLEN from its size; failing that, from AT_HWCAP in the core's
+ auxv. A core with an NT_GDB_TDESC note never gets here; the core
+ target uses that note directly. */
static const struct target_desc *
riscv_linux_core_read_description (struct gdbarch *gdbarch,
@@ -571,6 +603,9 @@ riscv_linux_core_read_description (struct gdbarch *gdbarch,
pulongest (size));
}
+ auto auxv = target_read_auxv_raw (target);
+ riscv_apply_hwcap (features, linux_get_hwcap (auxv, target, gdbarch));
+
/* Nothing was learnt beyond the ELF header. Let GDB fall back to its
default description, which also takes the executable into account. */
if (features.flen == 0)
@@ -645,6 +680,37 @@ riscv_linux_flen_from_fpregset_size_test ()
SELF_CHECK (riscv_linux_flen_from_fpregset_size (32 * 16 + 8) == 0);
}
+/* Check that AT_HWCAP bits refine the ISA features as expected. */
+
+static void
+riscv_apply_hwcap_test ()
+{
+ const ULONGEST hwcap_f = riscv_hwcap_isa ('f');
+ const ULONGEST hwcap_d = riscv_hwcap_isa ('d');
+ const ULONGEST hwcap_v = riscv_hwcap_isa ('v');
+
+ /* Return features with FLEN set, refined by HWCAP. */
+ auto apply = [] (ULONGEST hwcap, int flen = 0)
+ {
+ riscv_gdbarch_features features;
+ features.flen = flen;
+ riscv_apply_hwcap (features, hwcap);
+ return features;
+ };
+
+ /* 'd' implies double precision, 'f' single, and 'd' wins. */
+ SELF_CHECK (apply (hwcap_d).flen == riscv_flen_d);
+ SELF_CHECK (apply (hwcap_f).flen == riscv_flen_f);
+ SELF_CHECK (apply (hwcap_d | hwcap_f).flen == riscv_flen_d);
+ SELF_CHECK (apply (0).flen == 0);
+
+ /* An FLEN already recovered from the core is not overwritten. */
+ SELF_CHECK (apply (hwcap_d, riscv_flen_f).flen == riscv_flen_f);
+
+ /* The 'v' bit is ignored: AT_HWCAP carries no vector length. */
+ SELF_CHECK (apply (hwcap_v).vlen == 0);
+}
+
} /* namespace selftests */
#endif /* GDB_SELF_TEST */
@@ -659,5 +725,7 @@ INIT_GDB_FILE (riscv_linux_tdep)
selftests::register_test
("riscv-linux-flen-from-fpregset-size",
selftests::riscv_linux_flen_from_fpregset_size_test);
+ selftests::register_test ("riscv-apply-hwcap",
+ selftests::riscv_apply_hwcap_test);
#endif
}
diff --git a/gdb/testsuite/gdb.arch/riscv-core-hwcap.core.bz2 b/gdb/testsuite/gdb.arch/riscv-core-hwcap.core.bz2
new file mode 100644
index 0000000000000000000000000000000000000000..9ced8e4c9a16d0afa823f3bde8e31288f463945a
GIT binary patch
literal 3229
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
P@BCfK6yZWb9KvM$m8QOX
literal 0
HcmV?d00001
diff --git a/gdb/testsuite/gdb.arch/riscv-core-hwcap.exp b/gdb/testsuite/gdb.arch/riscv-core-hwcap.exp
new file mode 100644
index 00000000000..3655cb047a0
--- /dev/null
+++ b/gdb/testsuite/gdb.arch/riscv-core-hwcap.exp
@@ -0,0 +1,67 @@
+# Copyright 2026 Free Software Foundation, Inc.
+
+# 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/>.
+
+# Check that GDB recovers the ISA features of a core file from the
+# AT_HWCAP entry of the NT_AUXV note: the kernel publishes the
+# single-letter ISA extensions of the machine there, so a core it dumps
+# opened without the executable still reveals the F and D extensions.
+#
+# The bundled core (riscv-core-hwcap.core.bz2) is a real Linux core
+# (e_flags = 0, no NT_GDB_TDESC, no RISC-V attributes) whose
+# NT_FPREGSET note has been stripped, leaving AT_HWCAP = 0x20112d
+# (rv64acdfimv) as the only evidence of the FP extension. The F-only
+# mapping and the precedence rules are covered by the
+# "riscv-apply-hwcap" selftest.
+#
+# How to regenerate the fixture: take the riscv-core-fpregset.core.bz2
+# core and remove the NT_FPREGSET note from PT_NOTE: rewrite the
+# note blob without the CORE/type-2 entry, zero-pad the segment to keep
+# file offsets stable, shrink p_filesz of the PT_NOTE program
+# header accordingly, and bzip2 the result.
+
+# The fixture is an ELF64 Linux core and the FLEN assertions are
+# RV64-specific.
+require {istarget "riscv64-*-linux*"}
+
+set core [decompress_bz2 $srcdir/$subdir/riscv-core-hwcap.core.bz2]
+if {$core == ""} {
+ untested "failed to decompress core file"
+ return -1
+}
+set core [gdb_remote_download host $core]
+
+clean_restart
+
+# Before the core is loaded there is no target, so nothing to prove
+# that the FP and vector registers below really come from the core.
+gdb_test "info registers \$fa0" "The program has no registers now\\." \
+ "no registers before the core is loaded"
+
+if {[gdb_core_cmd $core "load core without executable"] != 1} {
+ return -1
+}
+
+# The D bit of AT_HWCAP gives us the FP registers.
+gdb_test "info registers \$fa0" "fa0\[ \t\]+.*" \
+ "fp registers recovered from hwcap"
+
+# ... and implies FLEN = 8.
+gdb_test "print sizeof (\$fa0)" "= 8" \
+ "flen recovered from hwcap"
+
+# The V bit of AT_HWCAP is deliberately ignored: it carries no vector
+# length, so no vector registers are invented.
+gdb_test "info registers \$v0" "Invalid register .v0." \
+ "no vector registers invented from hwcap"
--
2.43.0
next prev parent reply other threads:[~2026-10-26 9:58 UTC|newest]
Thread overview: 16+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-10-22 15:44 [PATCH 0/4] gdb/riscv: analyse a core file without the executable Farid Khaidari
2026-10-22 15:44 ` [PATCH 1/4] gdb/riscv: recover FLEN from the NT_FPREGSET note size in core files Farid Khaidari
2026-10-25 20:07 ` Kevin Buettner
2026-10-26 10:01 ` Farid Khaidari
2026-10-22 15:44 ` [PATCH 2/4] gdb/riscv: recover core file ISA features from AT_HWCAP Farid Khaidari
2026-10-22 15:44 ` [PATCH 3/4] gdb/riscv: test the "arch=" disassembler option Farid Khaidari
2026-10-22 15:44 ` [PATCH 4/4] gdb/riscv: disassemble an attribute-less object by the description ISA Farid Khaidari
2026-10-25 20:50 ` Kevin Buettner
2026-10-26 10:01 ` Farid Khaidari
2026-10-25 20:17 ` [PATCH 0/4] gdb/riscv: analyse a core file without the executable Kevin Buettner
2026-10-26 9:56 ` [PATCH v2 " Farid Khaidari
2026-10-26 9:56 ` [PATCH v2 1/4] gdb/riscv: recover FLEN from the NT_FPREGSET note size in core files Farid Khaidari
2026-10-26 9:56 ` Farid Khaidari [this message]
2026-10-26 9:56 ` [PATCH v2 3/4] gdb/riscv: test the "arch=" disassembler option Farid Khaidari
2026-10-26 9:56 ` [PATCH v2 4/4] gdb/riscv: disassemble an attribute-less object by the description ISA Farid Khaidari
2026-10-27 14:31 ` [PATCH v2 0/4] gdb/riscv: analyse a core file without the executable Farid Khaidari
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=20261026095647.3035166-3-khaidari.fg@gmail.com \
--to=khaidari.fg@gmail.com \
--cc=aburgess@redhat.com \
--cc=gdb-patches@sourceware.org \
--cc=kevinb@redhat.com \
--cc=palmer@dabbelt.com \
--cc=timurgol007@gmail.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