[v4,1/2] RISC-V: Fix display of partial instructions

Message ID 20250107-fix_objdump_partial_insn-v4-1-5bca13284275@rivosinc.com
State New
Headers
Series RISC-V: Fix display of partial instructions |

Checks

Context Check Description
linaro-tcwg-bot/tcwg_gdb_build--master-arm success Build passed
linaro-tcwg-bot/tcwg_gdb_build--master-aarch64 fail Patch failed to apply
linaro-tcwg-bot/tcwg_gdb_check--master-arm fail Patch failed to apply

Commit Message

Charlie Jenkins Jan. 7, 2025, 9:35 p.m. UTC
  As of commit e43d8768d909 ("RISC-V: Fix disassemble fetch fail return
value.") partial instructions are no longer displayed by objdump. While
that commit fixed the behavior of print_insn_riscv() returning the
arbitrary status value upon failure, it caused the behavior of dumping
instructions to change. Allow partial instructions to be displayed once
again and only return -1 if no part of the instruction was able to be
displayed.

Fixes: e43d8768d909 ("RISC-V: Fix disassemble fetch fail return
value.")
Signed-off-by: Charlie Jenkins <charlie@rivosinc.com>
Acked-By: Andrew Burgess <aburgess@redhat.com>
---
 opcodes/riscv-dis.c | 53 +++++++++++++++++++++++++++++++++++++++++++++++++----
 1 file changed, 49 insertions(+), 4 deletions(-)
  

Patch

diff --git a/opcodes/riscv-dis.c b/opcodes/riscv-dis.c
index 101380f93aafbd528ba0020371f0c43a85f41bd1..8f551f5bddb9289458b54dfee90d6c014941f9a3 100644
--- a/opcodes/riscv-dis.c
+++ b/opcodes/riscv-dis.c
@@ -1308,6 +1308,14 @@  riscv_disassemble_data (bfd_vma memaddr ATTRIBUTE_UNUSED,
       (*info->fprintf_styled_func)
 	(info->stream, dis_style_immediate, "0x%04x", (unsigned) data);
       break;
+    case 3:
+      info->bytes_per_line = 7;
+      (*info->fprintf_styled_func)
+	(info->stream, dis_style_assembler_directive, ".word");
+      (*info->fprintf_styled_func) (info->stream, dis_style_text, "\t");
+      (*info->fprintf_styled_func)
+	(info->stream, dis_style_immediate, "0x%06x", (unsigned) data);
+      break;
     case 4:
       info->bytes_per_line = 8;
       (*info->fprintf_styled_func)
@@ -1360,12 +1368,31 @@  riscv_init_disasm_info (struct disassemble_info *info)
   return true;
 }
 
+/* Fetch an instruction. If only a partial instruction is able to be fetched,
+   return the number of accessible bytes.  */
+
+static bfd_vma
+fetch_insn (bfd_vma memaddr,
+	    bfd_byte *packet,
+	    bfd_vma dump_size,
+	    struct disassemble_info *info,
+	    volatile int *status)
+{
+  do
+    {
+      *status = (*info->read_memory_func) (memaddr, packet, dump_size, info);
+    }
+  while (*status != 0 && dump_size-- > 1);
+
+  return dump_size;
+}
+
 int
 print_insn_riscv (bfd_vma memaddr, struct disassemble_info *info)
 {
   bfd_byte packet[RISCV_MAX_INSN_LEN];
   insn_t insn = 0;
-  bfd_vma dump_size;
+  bfd_vma dump_size, bytes_fetched;
   int status;
   enum riscv_seg_mstate mstate;
   int (*riscv_disassembler) (bfd_vma, insn_t, const bfd_byte *,
@@ -1398,24 +1425,42 @@  print_insn_riscv (bfd_vma memaddr, struct disassemble_info *info)
   else
     {
       /* Get the first 2-bytes to check the lenghth of instruction.  */
-      status = (*info->read_memory_func) (memaddr, packet, 2, info);
+      bytes_fetched = fetch_insn (memaddr, packet, 2, info, &status);
       if (status != 0)
 	{
 	  (*info->memory_error_func) (status, memaddr, info);
 	  return -1;
 	}
+      else if (bytes_fetched != 2)
+       {
+	  /* Only the first byte was able to be read.  Dump the partial
+	     instruction.  */
+	  dump_size = bytes_fetched;
+	  info->bytes_per_chunk = dump_size;
+	  riscv_disassembler = riscv_disassemble_data;
+	  goto print;
+       }
       insn = (insn_t) bfd_getl16 (packet);
       dump_size = riscv_insn_length (insn);
       riscv_disassembler = riscv_disassemble_insn;
     }
 
-  /* Fetch the instruction to dump.  */
-  status = (*info->read_memory_func) (memaddr, packet, dump_size, info);
+  bytes_fetched = fetch_insn (memaddr, packet, dump_size, info, &status);
+
   if (status != 0)
     {
       (*info->memory_error_func) (status, memaddr, info);
       return -1;
     }
+  else if (bytes_fetched != dump_size)
+    {
+      dump_size = bytes_fetched;
+      info->bytes_per_chunk = dump_size;
+      riscv_disassembler = riscv_disassemble_data;
+    }
+
+ print:
+
   insn = (insn_t) bfd_get_bits (packet, dump_size * 8, false);
 
   return (*riscv_disassembler) (memaddr, insn, packet, info);