[PATCH 2/3] RISC-V: Print cm.jt and cm.jalt target addresses

Jerry Zhang Jian jerry.zhangjian@sifive.com
Mon Jan 12 13:29:33 GMT 2026


From: Kito Cheng <kito.cheng@sifive.com>

Print the resolved target address for cm.jt/cm.jalt when __jvt_base$
and the table jump section are available. Load the JVT contents and
use the entry index to find the target address for display.

Refactor xlen detection logic into riscv_set_xlen_from_elf() helper
to reduce code duplication.

Signed-off-by: Kito Cheng <kito.cheng@sifive.com>
Co-Authored-by: Jerry Zhang Jian <jerry.zhangjian@sifive.com>
Co-Authored-by: Hau Hsu <hau.hsu@sifive.com>
Co-Authored-by: Charlie Keaney <charlie.keaney@embecosm.com>
Co-Authored-by: Mary Bennett <mary.bennett@embecosm.com>
Co-Authored-by: Nandni Jamnadas <nandni.jamnadas@embecosm.com>
Co-Authored-by: Sinan Lin <sinan.lin@linux.alibaba.com>
Co-Authored-by: Simon Cook <simon.cook@embecosm.com>
Co-Authored-by: Shihua Liao <shihua@iscas.ac.cn>
Co-Authored-by: Yulong Shi <yulong@iscas.ac.cn>
---
 opcodes/riscv-dis.c | 153 +++++++++++++++++++++++++++++++++++++++-----
 1 file changed, 138 insertions(+), 15 deletions(-)

diff --git a/opcodes/riscv-dis.c b/opcodes/riscv-dis.c
index fa2d44af28f..f6c9598456d 100644
--- a/opcodes/riscv-dis.c
+++ b/opcodes/riscv-dis.c
@@ -47,6 +47,10 @@ struct riscv_private_data
   bfd_vma hi_addr[OP_MASK_RD + 1];
   bool to_print_addr;
   bool has_gp;
+  bool has_jvt_base;
+  asection *jvt_section;
+  bfd_byte *jvt_content;
+  bfd_size_type jvt_size;
   /* Current XLEN for the disassembler.  */
   unsigned xlen;
   /* Default ISA specification version.  */
@@ -220,6 +224,47 @@ maybe_print_address (struct riscv_private_data *pd, int base_reg, int offset,
     pd->print_addr = (bfd_vma)(uint32_t)pd->print_addr;
 }
 
+/* Set pd->xlen from ELF class if not already known.  */
+
+static void
+riscv_set_xlen_from_elf (struct riscv_private_data *pd,
+			 struct disassemble_info *info)
+{
+  if (pd->xlen != 0)
+    return;
+
+  if (info->mach == bfd_mach_riscv64)
+    pd->xlen = 64;
+  else if (info->mach == bfd_mach_riscv32)
+    pd->xlen = 32;
+  else if (info->section != NULL)
+    {
+      Elf_Internal_Ehdr *ehdr = elf_elfheader (info->section->owner);
+      pd->xlen = ehdr->e_ident[EI_CLASS] == ELFCLASS64 ? 64 : 32;
+    }
+}
+
+/* Try to print target address of cm.jalt and cm.jt.  */
+
+static void
+maybe_print_jvt_address (struct riscv_private_data *pd, int index)
+{
+  if (!pd->has_jvt_base || pd->jvt_section == NULL || pd->jvt_content == NULL
+      || pd->xlen == 0)
+    return;
+
+  bfd_size_type entry_size = pd->xlen / 8;
+  bfd_size_type offset = entry_size * (bfd_size_type) index;
+  if (index < 0 || index > (ZCMT_TOTAL_ENTRIES - 1)
+      || offset + entry_size > pd->jvt_size)
+    return;
+
+  bfd_byte *packet = pd->jvt_content + offset;
+
+  pd->to_print_addr = true;
+  pd->print_addr = bfd_get_bits (packet, pd->xlen, false);
+}
+
 /* Get Zcmp reg_list field.  */
 
 static void
@@ -747,6 +792,7 @@ print_insn_args (const char *oparg, insn_t l, bfd_vma pc, disassemble_info *info
 		case 'I':
 		  print (info->stream, dis_style_address_offset,
 			 "%" PRIu64, EXTRACT_ZCMT_INDEX (l));
+		  maybe_print_jvt_address (pd, EXTRACT_ZCMT_INDEX (l));
 		  break;
 		default:
 		  goto undefined_modifier;
@@ -983,17 +1029,7 @@ riscv_disassemble_insn (bfd_vma memaddr,
   if (op != NULL)
     {
       /* If XLEN is not known, get its value from the ELF class.  */
-      if (pd->xlen != 0)
-	;
-      else if (info->mach == bfd_mach_riscv64)
-	pd->xlen = 64;
-      else if (info->mach == bfd_mach_riscv32)
-	pd->xlen = 32;
-      else if (info->section != NULL)
-	{
-	  Elf_Internal_Ehdr *ehdr = elf_elfheader (info->section->owner);
-	  pd->xlen = ehdr->e_ident[EI_CLASS] == ELFCLASS64 ? 64 : 32;
-	}
+      riscv_set_xlen_from_elf (pd, info);
 
       /* If arch has the Zfinx extension, replace FPR with GPR.  */
       if (riscv_subset_supports (&pd->riscv_rps_dis, "zfinx"))
@@ -1017,10 +1053,12 @@ riscv_disassemble_insn (bfd_vma memaddr,
 	  if ((op->xlen_requirement != 0)
 	      && (op->xlen_requirement != pd->xlen))
 	    continue;
-	  /* Is this instruction supported by the current architecture?  */
+	  /* Is this instruction supported by the current architecture?
+	     Always disassemble ZCMT instructions if __jvt_base$ is present.  */
 	  if (!pd->all_ext
 	      && !riscv_multi_subset_supports (&pd->riscv_rps_dis,
-					       op->insn_class))
+					       op->insn_class)
+	      && !(pd->has_jvt_base && op->insn_class == INSN_CLASS_ZCMT))
 	    continue;
 
 	  /* It's a match.  */
@@ -1412,6 +1450,43 @@ riscv_disassemble_data (bfd_vma memaddr ATTRIBUTE_UNUSED,
   return info->bytes_per_chunk;
 }
 
+/* DATA is the function address in jump table entry.
+   Lookup the address in symbols and print the function name.  */
+static int
+riscv_disassemble_jvt (bfd_vma memaddr, insn_t data,
+		       const bfd_byte *packet ATTRIBUTE_UNUSED,
+		       disassemble_info *info)
+{
+  struct riscv_private_data *pd = info->private_data;
+  if (pd == NULL || pd->xlen == 0)
+    return -1;
+
+  bfd_size_type entry_size = pd->xlen / 8;
+  int idx = (memaddr - info->section->vma) / entry_size;
+  if (idx < 0 || idx > (ZCMT_TOTAL_ENTRIES - 1))
+    opcodes_error_handler (_ ("invalid jvt index: %i"), idx);
+
+  const char *inst_str;
+  if (idx <= ZCMT_JT_END)
+    inst_str = "jvt.jt";
+  else
+    inst_str = "jvt.jalt";
+
+  const char *funcname = "<unknown>";
+  for (int i = 0; i < info->symtab_size; i++)
+    {
+      bfd_vma addr = bfd_asymbol_value (info->symtab[i]);
+      if (addr == (bfd_vma) data)
+	{
+	  funcname = info->symtab[i]->name;
+	  break;
+	}
+    }
+  (*info->fprintf_styled_func) (info->stream, dis_style_text, "%s[%i]:\t%s",
+				inst_str, idx, funcname);
+  return info->bytes_per_line;
+}
+
 static bool
 riscv_init_disasm_info (struct disassemble_info *info)
 {
@@ -1424,7 +1499,34 @@ riscv_init_disasm_info (struct disassemble_info *info)
     pd->hi_addr[i] = -1;
   pd->to_print_addr = false;
 
+  pd->has_jvt_base = false;
   pd->has_gp = false;
+  pd->jvt_section = NULL;
+  pd->jvt_content = NULL;
+  pd->jvt_size = 0;
+
+  if (info->section != NULL)
+    {
+      bfd *abfd = info->section->owner;
+      if (abfd && bfd_get_flavour (abfd) == bfd_target_elf_flavour)
+	{
+	  asection *s = bfd_get_section_by_name (abfd, TABLE_JUMP_SEC_NAME);
+	  if (s != NULL && bfd_section_size (s) > 0)
+	    {
+	      bfd_size_type size = bfd_section_size (s);
+	      bfd_byte *buf = (bfd_byte *) xmalloc (size);
+	      if (bfd_get_section_contents (abfd, s, buf, 0, size))
+		{
+		  pd->jvt_section = s;
+		  pd->jvt_content = buf;
+		  pd->jvt_size = size;
+		}
+	      else
+		free (buf);
+	    }
+	}
+    }
+
   for (i = 0; i < info->symtab_size; i++)
     {
       asymbol *sym = info->symtab[i];
@@ -1433,9 +1535,18 @@ riscv_init_disasm_info (struct disassemble_info *info)
 	  pd->gp = bfd_asymbol_value (sym);
 	  pd->has_gp = true;
 	}
+
+      if (strcmp (bfd_asymbol_name (sym), RISCV_TABLE_JUMP_BASE_SYMBOL) == 0)
+	{
+	  bfd_vma jvt_base = bfd_asymbol_value (sym);
+	  if (pd->jvt_section != NULL
+	      && jvt_base == bfd_section_lma (pd->jvt_section))
+	    pd->has_jvt_base = true;
+	}
     }
 
   pd->xlen = 0;
+  riscv_set_xlen_from_elf (pd, info);
   pd->default_isa_spec = ISA_SPEC_CLASS_DRAFT - 1;
   pd->default_priv_spec = PRIV_SPEC_CLASS_NONE;
 
@@ -1529,8 +1640,19 @@ print_insn_riscv (bfd_vma memaddr, struct disassemble_info *info)
   ((struct riscv_private_data *) info->private_data)->last_map_state = mstate;
 
   /* Set the size to dump.  */
-  if (mstate == MAP_DATA
-      && (info->flags & DISASSEMBLE_DATA) == 0)
+  if (strcmp (info->section->name, TABLE_JUMP_SEC_NAME) == 0)
+    {
+      struct riscv_private_data *pd = info->private_data;
+      riscv_set_xlen_from_elf (pd, info);
+
+      dump_size = pd->xlen / 8;
+      info->bytes_per_chunk = dump_size;
+      info->bytes_per_line = dump_size;
+      info->endian_code = BFD_ENDIAN_LITTLE;
+      info->display_endian = BFD_ENDIAN_LITTLE;
+      riscv_disassembler = riscv_disassemble_jvt;
+    }
+  else if (mstate == MAP_DATA && (info->flags & DISASSEMBLE_DATA) == 0)
     {
       dump_size = riscv_data_length (memaddr, info);
       info->bytes_per_chunk = dump_size;
@@ -1760,5 +1882,6 @@ void disassemble_free_riscv (struct disassemble_info *info ATTRIBUTE_UNUSED)
     {
       riscv_release_subset_list (pd->riscv_rps_dis.subset_list);
       free (pd->riscv_rps_dis.subset_list);
+      free (pd->jvt_content);
     }
 }
-- 
2.51.0



More information about the Binutils mailing list