S/390: Dump unknown instructions according to their length.
authorAndreas Krebbel <krebbel@linux.vnet.ibm.com>
Fri, 10 Jun 2016 11:40:48 +0000 (13:40 +0200)
committerAndreas Krebbel <krebbel@linux.vnet.ibm.com>
Fri, 10 Jun 2016 11:41:42 +0000 (13:41 +0200)
Unknown instructions are currently just dumped as .long 1234.  On
S/390 we can do a bit better since the instruction length is encoded
in the opcode.  That way also unknown instructions can be skipped
according to their real length.  That way we can continue correctly
after that instruction.  However, there are also some drawbacks with
that behavior when dumping data.  So for now that behavior is only
enabled for text section but even there it might mess things up when
having a literal pool embedded in the code.  Therefore I've left the
feature disabled by default and have added the -Minsnlength option to
enable it explicitely.

opcodes/ChangeLog:

2016-06-10  Andreas Krebbel  <krebbel@linux.vnet.ibm.com>

* s390-dis.c (option_use_insn_len_bits_p): New file scope
variable.
(init_disasm): Handle new command line option "insnlength".
(print_s390_disassembler_options): Mention new option in help
output.
(print_insn_s390): Use the encoded insn length when dumping
unknown instructions.

opcodes/ChangeLog
opcodes/s390-dis.c

index f218365606d64a6df02cda055bb3e79a1af488d9..fbde3e179b48a7f7d38d24d6a3b8a275f8fba502 100644 (file)
@@ -1,3 +1,13 @@
+2016-06-10  Andreas Krebbel  <krebbel@linux.vnet.ibm.com>
+
+       * s390-dis.c (option_use_insn_len_bits_p): New file scope
+       variable.
+       (init_disasm): Handle new command line option "insnlength".
+       (print_s390_disassembler_options): Mention new option in help
+       output.
+       (print_insn_s390): Use the encoded insn length when dumping
+       unknown instructions.
+
 2016-06-03  Pitchumani Sivanupandi  <pitchumani.s@atmel.com>
 
        * avr-dis.c (avr_operand): Add default data address space origin (0x800000)
index eeaeaf8c4cae42fac0bf44b9e7e5875cd93ca27f..813407324e63f24b0571d3510ed0ac19c2ead0ac 100644 (file)
@@ -29,6 +29,7 @@
 static int init_flag = 0;
 static int opc_index[256];
 static int current_arch_mask = 0;
+static int option_use_insn_len_bits_p = 0;
 
 /* Set up index table for first opcode byte.  */
 
@@ -51,6 +52,8 @@ init_disasm (struct disassemble_info *info)
        current_arch_mask = 1 << S390_OPCODE_ESA;
       else if (CONST_STRNEQ (p, "zarch"))
        current_arch_mask = 1 << S390_OPCODE_ZARCH;
+      else if (CONST_STRNEQ (p, "insnlength"))
+       option_use_insn_len_bits_p = 1;
       else
        fprintf (stderr, "Unknown S/390 disassembler option: %s\n", p);
 
@@ -261,7 +264,7 @@ print_insn_s390 (bfd_vma memaddr, struct disassemble_info *info)
   bfd_byte buffer[6];
   const struct s390_opcode *opcode = NULL;
   unsigned int value;
-  int status, opsize, bufsize;
+  int status, opsize, bufsize, bytes_to_dump, i;
 
   if (init_flag == 0)
     init_disasm (info);
@@ -307,38 +310,54 @@ print_insn_s390 (bfd_vma memaddr, struct disassemble_info *info)
                  || opcode_mask_more_specific (op, opcode)))
            opcode = op;
        }
-    }
 
-  if (opcode != NULL)
-    {
-      /* The instruction is valid.  Print it and return its size.  */
-      s390_print_insn_with_opcode (memaddr, info, buffer, opcode);
-      return opsize;
+      if (opcode != NULL)
+       {
+         /* The instruction is valid.  Print it and return its size.  */
+         s390_print_insn_with_opcode (memaddr, info, buffer, opcode);
+         return opsize;
+       }
     }
 
+  /* For code sections it makes sense to skip unknown instructions
+     according to their length bits.  */
+  if (status == 0
+      && option_use_insn_len_bits_p
+      && info->section != NULL
+      && (info->section->flags & SEC_CODE))
+    bytes_to_dump = opsize;
+  else
+    /* By default unknown instructions are printed as .long's/.short'
+       depending on how many bytes are available.  */
+    bytes_to_dump = bufsize >= 4 ? 4 : bufsize;
+
+  if (bytes_to_dump == 0)
+    return 0;
+
   /* Fall back to hex print.  */
-  if (bufsize >= 4)
+  switch (bytes_to_dump)
     {
+    case 4:
       value = (unsigned int) buffer[0];
       value = (value << 8) + (unsigned int) buffer[1];
       value = (value << 8) + (unsigned int) buffer[2];
       value = (value << 8) + (unsigned int) buffer[3];
       info->fprintf_func (info->stream, ".long\t0x%08x", value);
       return 4;
-    }
-  else if (bufsize >= 2)
-    {
+    case 2:
       value = (unsigned int) buffer[0];
       value = (value << 8) + (unsigned int) buffer[1];
       info->fprintf_func (info->stream, ".short\t0x%04x", value);
       return 2;
+    default:
+      info->fprintf_func (info->stream, ".byte\t0x%02x",
+                         (unsigned int) buffer[0]);
+      for (i = 1; i < bytes_to_dump; i++)
+       info->fprintf_func (info->stream, ",0x%02x",
+                         (unsigned int) buffer[i]);
+      return bytes_to_dump;
     }
-  else
-    {
-      value = (unsigned int) buffer[0];
-      info->fprintf_func (info->stream, ".byte\t0x%02x", value);
-      return 1;
-    }
+  return 0;
 }
 
 void
@@ -350,4 +369,6 @@ with the -M switch (multiple options should be separated by commas):\n"));
 
   fprintf (stream, _("  esa         Disassemble in ESA architecture mode\n"));
   fprintf (stream, _("  zarch       Disassemble in z/Architecture mode\n"));
+  fprintf (stream, _("  insnlength  Print unknown instructions according "
+                    "to length from first two bits\n"));
 }