Mirror of the gdb-patches mailing list
 help / color / mirror / Atom feed
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 4/4] gdb/riscv: disassemble an attribute-less object by the description ISA
Date: Mon, 26 Oct 2026 12:56:46 +0300	[thread overview]
Message-ID: <20261026095647.3035166-5-khaidari.fg@gmail.com> (raw)
In-Reply-To: <20261026095647.3035166-1-khaidari.fg@gmail.com>

An object without a RISC-V architecture attribute is disassembled as
rv64gc, whatever the target description says.  A core file is such an
object, so its vector instructions print as raw .insn words even when
the description has vector registers.

For such objects, pass the ISA implied by the target description to
the disassembler as "arch=".  An object that records its own ISA keeps
using it.  The test checks both cases: with a vector description
loaded, an rv64gc executable must not decode the planted words as
vector instructions, and the same executable with the attribute
stripped must.

The option is set in print_insn, not through
gdbarch_disassembler_options_implicit as mips-tdep.c does.  A gdbarch
is shared by all objects with matching features, and only print_insn
knows which object it is disassembling.

User options are appended to the string for every instruction.
libopcodes clears disassembler_options after parsing and resets any
option missing from a later string, so they would be lost from the
second instruction on.  The string is local to print_insn, and the
previous disassembler_options value is restored after the call, so no
pointer to it outlives print_insn.

The test loads the vector description from a file.  In practice such a
description comes from a core, but a core only matches the executable
that produced it.  Only RV64 is tested; the RV32 ISA string was checked
by reading the code.

Signed-off-by: Farid Khaidari <khaidari.fg@gmail.com>
---
 gdb/riscv-tdep.c                              |  69 ++++++++++
 .../riscv-disasm-arch-option-vector.xml       | 123 ++++++++++++++++++
 .../gdb.arch/riscv-disasm-arch-option.exp     |  41 +++++-
 3 files changed, 232 insertions(+), 1 deletion(-)
 create mode 100644 gdb/testsuite/gdb.arch/riscv-disasm-arch-option-vector.xml

diff --git a/gdb/riscv-tdep.c b/gdb/riscv-tdep.c
index 0a997231abc..606bd371676 100644
--- a/gdb/riscv-tdep.c
+++ b/gdb/riscv-tdep.c
@@ -39,6 +39,7 @@
 #include "elf-bfd.h"
 #include "symcat.h"
 #include "dis-asm.h"
+#include "disasm.h"
 #include "frame-unwind.h"
 #include "frame-base.h"
 #include "trad-frame.h"
@@ -56,6 +57,7 @@
 #include "arch/riscv.h"
 #include "record-full.h"
 #include "riscv-ravenscar-thread.h"
+#include "gdbsupport/scope-exit.h"
 
 #include <vector>
 
@@ -4151,6 +4153,45 @@ riscv_gnu_triplet_regexp (struct gdbarch *gdbarch)
   return "riscv(32|64)?";
 }
 
+/* Return true if the object owning the section being disassembled
+   records a RISC-V ISA string attribute.  */
+
+static bool
+riscv_disasm_bfd_has_isa_attribute (struct disassemble_info *info)
+{
+  if (info->section == nullptr)
+    return false;
+
+  auto *abfd = info->section->owner;
+  if (abfd == nullptr || bfd_get_flavour (abfd) != bfd_target_elf_flavour)
+    return false;
+
+  return elf_known_obj_attributes_proc (abfd)[Tag_RISCV_arch].s != nullptr;
+}
+
+/* X register width, in bytes, implied by the RV32 base integer ISA.  */
+constexpr int riscv_xlen_32 = 4;
+
+/* Build an ISA string for the "arch=" disassembler option from
+   FEATURES, the target description of the architecture.  The option
+   replaces the rv64gc default of libopcodes, so the extension set is
+   that same default, widened by V once the target description sizes
+   the vector registers.  Naming the extensions the description does
+   know about instead would decode less than the default it replaces:
+   an ISA without G implies neither Zicsr nor Zifencei, which would
+   drop "csrr" and "fence.i" from a target that merely describes no FP
+   registers.  An RV32E target gets rv32gc for the same reason: E only
+   removes registers, so rv32gc decodes every RV32E instruction.  */
+
+static std::string
+riscv_isa_for_disassembler (const struct riscv_gdbarch_features &features)
+{
+  std::string isa = features.xlen == riscv_xlen_32 ? "rv32gc" : "rv64gc";
+  if (features.vlen > 0)
+    isa += "v";
+  return isa;
+}
+
 /* Implement the "print_insn" gdbarch method.  */
 
 static int
@@ -4162,6 +4203,34 @@ riscv_print_insn (bfd_vma addr, struct disassemble_info *info)
   if (s != nullptr)
     info->section = s->the_bfd_section;
 
+  /* An object that records its own ISA is disassembled according to
+     that ISA.  One that does not, such as a core file loaded without an
+     executable, is disassembled according to the target description;
+     libopcodes would otherwise fall back to plain rv64gc.
+
+     The option is supplied for each instruction, since the object can
+     change between them.  Each parse resets the options it does not
+     see, so the user ones are appended, last so that they win.  INFO
+     points at the local string only for this call.  */
+  auto *di = static_cast<gdb_disassemble_info *> (info->application_data);
+  if (di == nullptr || riscv_disasm_bfd_has_isa_attribute (info))
+    return default_print_insn (addr, info);
+
+  gdbarch *arch = di->arch ();
+  riscv_gdbarch_tdep *tdep = gdbarch_tdep<riscv_gdbarch_tdep> (arch);
+  std::string options
+    = "arch=" + riscv_isa_for_disassembler (tdep->isa_features);
+
+  const char *user_options = get_disassembler_options (arch);
+  if (user_options != nullptr && *user_options != '\0')
+    {
+      options += ',';
+      options += user_options;
+    }
+
+  const char *saved_options = info->disassembler_options;
+  info->disassembler_options = options.c_str ();
+  SCOPE_EXIT { info->disassembler_options = saved_options; };
   return default_print_insn (addr, info);
 }
 
diff --git a/gdb/testsuite/gdb.arch/riscv-disasm-arch-option-vector.xml b/gdb/testsuite/gdb.arch/riscv-disasm-arch-option-vector.xml
new file mode 100644
index 00000000000..7f514803d51
--- /dev/null
+++ b/gdb/testsuite/gdb.arch/riscv-disasm-arch-option-vector.xml
@@ -0,0 +1,123 @@
+<?xml version="1.0"?>
+<!-- Copyright (C) 2026 Free Software Foundation, Inc.
+
+     Copying and distribution of this file, with or without modification,
+     are permitted in any medium without royalty provided the copyright
+     notice and this notice are preserved.  -->
+
+<!DOCTYPE target SYSTEM "gdb-target.dtd">
+<target>
+  <architecture>riscv</architecture>
+  <feature name="org.gnu.gdb.riscv.cpu">
+    <reg name="zero" bitsize="64" type="int"/>
+    <reg name="ra" bitsize="64" type="code_ptr"/>
+    <reg name="sp" bitsize="64" type="data_ptr"/>
+    <reg name="gp" bitsize="64" type="data_ptr"/>
+    <reg name="tp" bitsize="64" type="data_ptr"/>
+    <reg name="t0" bitsize="64" type="int"/>
+    <reg name="t1" bitsize="64" type="int"/>
+    <reg name="t2" bitsize="64" type="int"/>
+    <reg name="fp" bitsize="64" type="data_ptr"/>
+    <reg name="s1" bitsize="64" type="int"/>
+    <reg name="a0" bitsize="64" type="int"/>
+    <reg name="a1" bitsize="64" type="int"/>
+    <reg name="a2" bitsize="64" type="int"/>
+    <reg name="a3" bitsize="64" type="int"/>
+    <reg name="a4" bitsize="64" type="int"/>
+    <reg name="a5" bitsize="64" type="int"/>
+    <reg name="a6" bitsize="64" type="int"/>
+    <reg name="a7" bitsize="64" type="int"/>
+    <reg name="s2" bitsize="64" type="int"/>
+    <reg name="s3" bitsize="64" type="int"/>
+    <reg name="s4" bitsize="64" type="int"/>
+    <reg name="s5" bitsize="64" type="int"/>
+    <reg name="s6" bitsize="64" type="int"/>
+    <reg name="s7" bitsize="64" type="int"/>
+    <reg name="s8" bitsize="64" type="int"/>
+    <reg name="s9" bitsize="64" type="int"/>
+    <reg name="s10" bitsize="64" type="int"/>
+    <reg name="s11" bitsize="64" type="int"/>
+    <reg name="t3" bitsize="64" type="int"/>
+    <reg name="t4" bitsize="64" type="int"/>
+    <reg name="t5" bitsize="64" type="int"/>
+    <reg name="t6" bitsize="64" type="int"/>
+    <reg name="pc" bitsize="64" type="code_ptr"/>
+  </feature>
+  <feature name="org.gnu.gdb.riscv.fpu">
+
+    <union id="riscv_double">
+      <field name="float" type="ieee_single"/>
+      <field name="double" type="ieee_double"/>
+    </union>
+
+    <reg name="ft0" bitsize="64" type="riscv_double" regnum="33"/>
+    <reg name="ft1" bitsize="64" type="riscv_double"/>
+    <reg name="ft2" bitsize="64" type="riscv_double"/>
+    <reg name="ft3" bitsize="64" type="riscv_double"/>
+    <reg name="ft4" bitsize="64" type="riscv_double"/>
+    <reg name="ft5" bitsize="64" type="riscv_double"/>
+    <reg name="ft6" bitsize="64" type="riscv_double"/>
+    <reg name="ft7" bitsize="64" type="riscv_double"/>
+    <reg name="fs0" bitsize="64" type="riscv_double"/>
+    <reg name="fs1" bitsize="64" type="riscv_double"/>
+    <reg name="fa0" bitsize="64" type="riscv_double"/>
+    <reg name="fa1" bitsize="64" type="riscv_double"/>
+    <reg name="fa2" bitsize="64" type="riscv_double"/>
+    <reg name="fa3" bitsize="64" type="riscv_double"/>
+    <reg name="fa4" bitsize="64" type="riscv_double"/>
+    <reg name="fa5" bitsize="64" type="riscv_double"/>
+    <reg name="fa6" bitsize="64" type="riscv_double"/>
+    <reg name="fa7" bitsize="64" type="riscv_double"/>
+    <reg name="fs2" bitsize="64" type="riscv_double"/>
+    <reg name="fs3" bitsize="64" type="riscv_double"/>
+    <reg name="fs4" bitsize="64" type="riscv_double"/>
+    <reg name="fs5" bitsize="64" type="riscv_double"/>
+    <reg name="fs6" bitsize="64" type="riscv_double"/>
+    <reg name="fs7" bitsize="64" type="riscv_double"/>
+    <reg name="fs8" bitsize="64" type="riscv_double"/>
+    <reg name="fs9" bitsize="64" type="riscv_double"/>
+    <reg name="fs10" bitsize="64" type="riscv_double"/>
+    <reg name="fs11" bitsize="64" type="riscv_double"/>
+    <reg name="ft8" bitsize="64" type="riscv_double"/>
+    <reg name="ft9" bitsize="64" type="riscv_double"/>
+    <reg name="ft10" bitsize="64" type="riscv_double"/>
+    <reg name="ft11" bitsize="64" type="riscv_double"/>
+
+    <reg name="fcsr" bitsize="32" type="int" regnum="68"/>
+  </feature>
+  <feature name="org.gnu.gdb.riscv.vector">
+    <vector id="bytes16" type="uint8" count="16"/>
+    <reg name="v0" bitsize="128" type="bytes16"/>
+    <reg name="v1" bitsize="128" type="bytes16"/>
+    <reg name="v2" bitsize="128" type="bytes16"/>
+    <reg name="v3" bitsize="128" type="bytes16"/>
+    <reg name="v4" bitsize="128" type="bytes16"/>
+    <reg name="v5" bitsize="128" type="bytes16"/>
+    <reg name="v6" bitsize="128" type="bytes16"/>
+    <reg name="v7" bitsize="128" type="bytes16"/>
+    <reg name="v8" bitsize="128" type="bytes16"/>
+    <reg name="v9" bitsize="128" type="bytes16"/>
+    <reg name="v10" bitsize="128" type="bytes16"/>
+    <reg name="v11" bitsize="128" type="bytes16"/>
+    <reg name="v12" bitsize="128" type="bytes16"/>
+    <reg name="v13" bitsize="128" type="bytes16"/>
+    <reg name="v14" bitsize="128" type="bytes16"/>
+    <reg name="v15" bitsize="128" type="bytes16"/>
+    <reg name="v16" bitsize="128" type="bytes16"/>
+    <reg name="v17" bitsize="128" type="bytes16"/>
+    <reg name="v18" bitsize="128" type="bytes16"/>
+    <reg name="v19" bitsize="128" type="bytes16"/>
+    <reg name="v20" bitsize="128" type="bytes16"/>
+    <reg name="v21" bitsize="128" type="bytes16"/>
+    <reg name="v22" bitsize="128" type="bytes16"/>
+    <reg name="v23" bitsize="128" type="bytes16"/>
+    <reg name="v24" bitsize="128" type="bytes16"/>
+    <reg name="v25" bitsize="128" type="bytes16"/>
+    <reg name="v26" bitsize="128" type="bytes16"/>
+    <reg name="v27" bitsize="128" type="bytes16"/>
+    <reg name="v28" bitsize="128" type="bytes16"/>
+    <reg name="v29" bitsize="128" type="bytes16"/>
+    <reg name="v30" bitsize="128" type="bytes16"/>
+    <reg name="v31" bitsize="128" type="bytes16"/>
+  </feature>
+</target>
diff --git a/gdb/testsuite/gdb.arch/riscv-disasm-arch-option.exp b/gdb/testsuite/gdb.arch/riscv-disasm-arch-option.exp
index 2dd7a998eeb..2c7a85bf70c 100644
--- a/gdb/testsuite/gdb.arch/riscv-disasm-arch-option.exp
+++ b/gdb/testsuite/gdb.arch/riscv-disasm-arch-option.exp
@@ -16,7 +16,8 @@
 # Check the "arch=" disassembler option against an executable.  The
 # option names the ISA to disassemble for, in place of the one the
 # object records, so the test needs an object both with and without an
-# architecture attribute.
+# architecture attribute.  GDB supplies the option itself for the object
+# that records nothing, which the test checks as well.
 #
 # A single "disassemble" prints the whole function through one
 # disassembler, so an ISA that survived only the first instruction would
@@ -78,3 +79,41 @@ gdb_test_no_output "set disassembler-options arch=rv64gcv" \
 
 gdb_test "disassemble vector_insns" $vector_re \
     "vector instructions decoded with arch=rv64gcv"
+
+# For an object that records no ISA, GDB names one on its own, out of the
+# target description.  In practice a description that sizes the vector
+# registers is the one recovered from a core file, but a core only pairs
+# with the executable it was dumped from, and the instructions of this
+# one would be nowhere in the memory such a core dumped.  A description
+# loaded from a file sizes the registers the same way and pairs with any
+# executable.
+set tdesc_file "${srcdir}/${subdir}/${testfile}-vector.xml"
+
+if {[is_remote host]} {
+    set tdesc_file [remote_download host $tdesc_file]
+}
+
+# Restarting drops the option set above: what decodes the instructions
+# here is the ISA GDB supplies itself.
+clean_restart $stripped
+
+gdb_test_no_output "set tdesc filename $tdesc_file" \
+    "load a description with vector registers, object without an attribute"
+
+gdb_test "disassemble vector_insns" $vector_re \
+    "the description ISA reaches the disassembler on its own"
+
+# The same description against the executable that does record rv64gc:
+# the attribute has to keep winning, so the planted encodings stay raw
+# words.  Were the description supplied here anyway, they would decode as
+# vector instructions.
+clean_restart $testfile
+
+gdb_test_no_output "set tdesc filename $tdesc_file" \
+    "load a description with vector registers"
+
+gdb_test "print sizeof (\$v0)" " = 16" \
+    "the description sizes the vector registers"
+
+gdb_test "disassemble vector_insns" $raw_re \
+    "the attribute of the object outranks the description ISA"
-- 
2.43.0


  parent reply	other threads:[~2026-10-26  9:59 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   ` [PATCH v2 2/4] gdb/riscv: recover core file ISA features from AT_HWCAP Farid Khaidari
2026-10-26  9:56   ` [PATCH v2 3/4] gdb/riscv: test the "arch=" disassembler option Farid Khaidari
2026-10-26  9:56   ` Farid Khaidari [this message]
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-5-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