]> git.ipfire.org Git - thirdparty/binutils-gdb.git/commitdiff
s390: Optionally print instruction description in disassembly
authorJens Remus <jremus@linux.ibm.com>
Wed, 20 Dec 2023 10:34:15 +0000 (11:34 +0100)
committerAndreas Krebbel <krebbel@linux.ibm.com>
Wed, 20 Dec 2023 10:50:32 +0000 (11:50 +0100)
Print instruction description as comment in disassembly with s390
architecture specific option "insndesc":

- For objdump it can be enabled with option "-M insndesc"
- In gdb it can be enabled with "set disassembler-options insndesc"

Since comments are not column aligned the output can enhanced for
readability by postprocessing using a filter such as "expand":

... | expand -t 8,16,24,32,40,80

Or when using in combination with objdump option --visualize-jumps:

... | expand | sed -e 's/ *#/\t#/' | expand -t 1,80

Note that the instruction descriptions add about 128 KB to s390-opc.o:

s390-opc.o without instruction descriptions: 216368 bytes
s390-opc.o with instruction descriptions   : 348432 bytes

binutils/
* NEWS: Mention new s390-specific disassembler option
  "insndesc".

include/
* opcode/s390.h (struct s390_opcode): Add field to hold
  instruction description.

opcodes/
* s390-mkopc.c: Copy instruction description from s390-opc.txt
  into generated operation code table s390-opc.tab.
* s390-opc.c (s390_opformats): Provide NULL as description in
  .insn pseudo-mnemonics opcode table.
* s390-dis.c: Add s390-specific disassembler option "insndesc"
  and optionally print the instruction description as comment in
  the disassembly when it is specified.

gas/
* testsuite/gas/s390/s390.exp: Add new test disassembly test
  case "zarch-insndesc".
* testsuite/gas/s390/zarch-insndesc.s: New test case for s390-
  specific disassembler option "insndesc".
* testsuite/gas/s390/zarch-insndesc.d: Likewise.

Signed-off-by: Jens Remus <jremus@linux.ibm.com>
Reviewed-by: Andreas Krebbel <krebbel@linux.ibm.com>
binutils/NEWS
gas/testsuite/gas/s390/s390.exp
gas/testsuite/gas/s390/zarch-insndesc.d [new file with mode: 0644]
gas/testsuite/gas/s390/zarch-insndesc.s [new file with mode: 0644]
include/opcode/s390.h
opcodes/s390-dis.c
opcodes/s390-mkopc.c
opcodes/s390-opc.c

index 73df7053be467afdca31aaf101b5c0f9f5dab78d..35b84e62b957950b837b2132e99f7c3fd72c5803 100644 (file)
 
 * objdump --visualize-jumps is now supported on s390 architecture.
 
+* The s390 disassembly now optionally includes the instruction description as
+  comment with the s390-specific disassembler option "insndesc":
+  - For objdump it can be enabled with "objdump -M insndesc ...".
+  - In gdb it can be enabled with "set disassembler-options insndesc".
+
 Changes in 2.41:
 
 * The MIPS port now supports the Sony Interactive Entertainment Allegrex
index 356fba95885e07e9cc2fe2fe34898432e677d8d6..86e2dd492cd12bde5a50348c57a027fd151cabe8 100644 (file)
@@ -37,6 +37,7 @@ if [expr [istarget "s390-*-*"] ||  [istarget "s390x-*-*"]]  then {
     run_dump_test "zarch-operands" "{as -m64} {as -march=z9-109}"
     run_dump_test "zarch-machine" "{as -m64} {as -march=z900}"
     run_dump_test "zarch-optargs" "{as -m64} {as -march=arch12}"
+    run_dump_test "zarch-insndesc" "{as -m64}"
     run_list_test "machine-parsing-1" ""
     run_list_test "machine-parsing-2" ""
     run_list_test "machine-parsing-3" ""
diff --git a/gas/testsuite/gas/s390/zarch-insndesc.d b/gas/testsuite/gas/s390/zarch-insndesc.d
new file mode 100644 (file)
index 0000000..9a121fb
--- /dev/null
@@ -0,0 +1,17 @@
+#name: s390x insndesc
+#objdump: -dr -M insndesc
+
+.*: +file format .*
+
+Disassembly of section .text:
+
+.* <foo>:
+.*:    b3 95 00 69 [    ]*cdfbr        %f6,%r9 # convert from fixed 32 to long bfp
+ *([\da-f]+):  84 69 00 00 [    ]*brxh %r6,%r9,\1 <foo\+0x\1>  # branch relative on index high
+.*:    b2 99 5f ff [    ]*srnm 4095\(%r5\)     # set rounding mode
+.*:    b9 11 00 96 [    ]*lngfr        %r9,%r6 # load negative 64<32
+.*:    ec 67 92 1c 26 54 [      ]*rnsbgt       %r6,%r7,18,28,38        # rotate then and selected bits and test results
+.*:    ec 67 0c 8d 0e 5d [      ]*risbhgz      %r6,%r7,12,13,14        # rotate then insert selected bits high and zero remaining bits
+.*:    b3 96 37 59 [    ]*cxfbra       %f5,3,%r9,7     # convert from 32 bit fixed to extended bfp with rounding mode
+.*:    ec 67 0c 94 0e 59 [      ]*risbgnz      %r6,%r7,12,20,14        # rotate then insert selected bits and zero remaining bits nocc
+.*:    07 07 [  ]*nopr %r7     # no operation
diff --git a/gas/testsuite/gas/s390/zarch-insndesc.s b/gas/testsuite/gas/s390/zarch-insndesc.s
new file mode 100644 (file)
index 0000000..e964315
--- /dev/null
@@ -0,0 +1,10 @@
+.text
+foo:
+       cdfbr   %f6,%r9
+       brxh    %r6,%r9,.
+       srnm    4095(%r5)
+       lngfr   %r9,%r6
+       rnsbgt  %r6,%r7,18,28,38
+       risbhgz %r6,%r7,12,13,14
+       cxfbra %f5,3,%r9,7
+       risbgnz %r6,%r7,12,20,14
index d540e1dfd007f6a37c3f2fcc4d2e73531c182d96..319bfe2d6296a266caf489cc5d5a778f01a860fe 100644 (file)
@@ -81,7 +81,7 @@ enum s390_opcode_cpu_val
 
 struct s390_opcode
   {
-    /* The opcode name.  */
+    /* The opcode name (mnemonic).  */
     const char * name;
 
     /* The opcode itself.  Those bits which will be filled in with
@@ -110,6 +110,9 @@ struct s390_opcode
 
     /* Instruction specific flags.  */
     unsigned int flags;
+
+    /* Instruction description.  */
+    const char * description;
   };
 
 /* The table itself is sorted by major opcode number, and is otherwise
index 8c8a98c4e24339a99d16e575768032915f3b9e2a..fca965fbb5dcd74c5d516961932b34e3e9d216e5 100644 (file)
@@ -31,6 +31,7 @@
 static int opc_index[256];
 static int current_arch_mask = 0;
 static int option_use_insn_len_bits_p = 0;
+static int option_print_insn_desc = 0;
 
 typedef struct
 {
@@ -43,7 +44,8 @@ static const s390_options_t options[] =
   { "esa" ,       N_("Disassemble in ESA architecture mode") },
   { "zarch",      N_("Disassemble in z/Architecture mode") },
   { "insnlength", N_("Print unknown instructions according to "
-                    "length from first two bits") }
+                    "length from first two bits") },
+  { "insndesc",   N_("Print instruction description as comment") },
 };
 
 /* Set up index table for first opcode byte.  */
@@ -63,6 +65,7 @@ disassemble_init_s390 (struct disassemble_info *info)
 
   current_arch_mask = 1 << S390_OPCODE_ZARCH;
   option_use_insn_len_bits_p = 0;
+  option_print_insn_desc = 0;
 
   for (p = info->disassembler_options; p != NULL; )
     {
@@ -72,6 +75,8 @@ disassemble_init_s390 (struct disassemble_info *info)
        current_arch_mask = 1 << S390_OPCODE_ZARCH;
       else if (startswith (p, "insnlength"))
        option_use_insn_len_bits_p = 1;
+      else if (startswith (p, "insndesc"))
+       option_print_insn_desc = 1;
       else
        /* xgettext:c-format */
        opcodes_error_handler (_("unknown S/390 disassembler option: %s"), p);
@@ -311,6 +316,12 @@ s390_print_insn_with_opcode (bfd_vma memaddr,
       else
        separator = ',';
     }
+
+  /* Optional: instruction name.  */
+  if (option_print_insn_desc && opcode->description
+      && opcode->description[0] != '\0')
+    info->fprintf_styled_func (info->stream, dis_style_comment_start, "\t# %s",
+                              opcode->description);
 }
 
 /* Check whether opcode A's mask is more specific than that of B.  */
index eae0397d4977038451b6c843d39a6d90cd1110ac..c6930a3e9b5f83e064e6cf2cf29813a76a47c941 100644 (file)
@@ -63,6 +63,7 @@ struct op_struct
     int   mode_bits;
     int   min_cpu;
     int   flags;
+    char  description[MAX_DESCRIPTION_LEN + 1];
 
     unsigned long long sort_value;
     int   no_nibbles;
@@ -84,7 +85,7 @@ createTable (void)
 
 static void
 insertOpcode (char *opcode, char *mnemonic, char *format,
-             int min_cpu, int mode_bits, int flags)
+             int min_cpu, int mode_bits, int flags, char* description)
 {
   char *str;
   unsigned long long sort_value;
@@ -132,6 +133,8 @@ insertOpcode (char *opcode, char *mnemonic, char *format,
   op_array[ix].min_cpu = min_cpu;
   op_array[ix].mode_bits = mode_bits;
   op_array[ix].flags = flags;
+  strncpy (op_array[ix].description, description, MAX_DESCRIPTION_LEN);
+  op_array[ix].description[MAX_DESCRIPTION_LEN] = '\0';
   no_ops++;
 }
 
@@ -193,7 +196,7 @@ const struct s390_cond_ext_format s390_crb_extensions[NUM_CRB_EXTENSIONS] =
 
 static void
 insertExpandedMnemonic (char *opcode, char *mnemonic, char *format,
-                       int min_cpu, int mode_bits, int flags)
+                       int min_cpu, int mode_bits, int flags, char *description)
 {
   char *tag;
   char prefix[MAX_MNEMONIC_LEN + 1];
@@ -206,7 +209,7 @@ insertExpandedMnemonic (char *opcode, char *mnemonic, char *format,
 
   if (!(tag = strpbrk (mnemonic, "*$")))
     {
-      insertOpcode (opcode, mnemonic, format, min_cpu, mode_bits, flags);
+      insertOpcode (opcode, mnemonic, format, min_cpu, mode_bits, flags, description);
       return;
     }
 
@@ -290,7 +293,7 @@ insertExpandedMnemonic (char *opcode, char *mnemonic, char *format,
          return;
        }
 
-      insertOpcode (opcode, new_mnemonic, format, min_cpu, mode_bits, flags);
+      insertOpcode (opcode, new_mnemonic, format, min_cpu, mode_bits, flags, description);
     }
   return;
 
@@ -311,7 +314,8 @@ static const char file_header[] =
   "   instruction which matches.\n"
   "   MODE_BITS - zarch or esa\n"
   "   MIN_CPU - number of the min cpu level required\n"
-  "   FLAGS - instruction flags.  */\n\n"
+  "   FLAGS - instruction flags.\n"
+  "   DESCRIPTION - description of the instruction.  */\n\n"
   "const struct s390_opcode s390_opcodes[] =\n  {\n";
 
 /* `dumpTable': write opcode table.  */
@@ -337,7 +341,8 @@ dumpTable (void)
              op_array[ix].format, op_array[ix].format);
       printf ("%i, ", op_array[ix].mode_bits);
       printf ("%i, ", op_array[ix].min_cpu);
-      printf ("%i}", op_array[ix].flags);
+      printf ("%i, ", op_array[ix].flags);
+      printf ("\"%s\" }", op_array[ix].description);
       if (ix < no_ops-1)
        printf (",\n");
       else
@@ -497,7 +502,7 @@ main (void)
              str++;
          } while (*str != 0);
        }
-      insertExpandedMnemonic (opcode, mnemonic, format, min_cpu, mode_bits, flag_bits);
+      insertExpandedMnemonic (opcode, mnemonic, format, min_cpu, mode_bits, flag_bits, description);
 
  continue_loop:
       ;
index cbfdb3df0b73d87517aa606611f73d2ee8e5b9a7..e44621a74790b440074ad3dc7ded536d8f3bfc8b 100644 (file)
@@ -774,37 +774,37 @@ unused_s390_operands_static_asserts (void)
 
 const struct s390_opcode s390_opformats[] =
   {
-  { "e",    OP8(0x00LL), MASK_E,          INSTR_E,           3,  0 ,0 },
-  { "ri",   OP8(0x00LL), MASK_RI_RI,      INSTR_RI_RI,       3,  0 ,0 },
-  { "rie",  OP8(0x00LL), MASK_RIE_RRP,    INSTR_RIE_RRP,     3,  0 ,0 },
-  { "ril",  OP8(0x00LL), MASK_RIL_RP,     INSTR_RIL_RP,      3,  0 ,0 },
-  { "rilu", OP8(0x00LL), MASK_RIL_RU,     INSTR_RIL_RU,      3,  0 ,0 },
-  { "ris",  OP8(0x00LL), MASK_RIS_RURDI,   INSTR_RIS_RURDI,   3,  6 ,0 },
-  { "rr",   OP8(0x00LL), MASK_RR_RR,      INSTR_RR_RR,       3,  0 ,0 },
-  { "rre",  OP8(0x00LL), MASK_RRE_RR,     INSTR_RRE_RR,      3,  0 ,0 },
-  { "rrf",  OP8(0x00LL), MASK_RRF_RURR,           INSTR_RRF_RURR,    3,  0 ,0 },
-  { "rrs",  OP8(0x00LL), MASK_RRS_RRRDU,   INSTR_RRS_RRRDU,   3,  6 ,0 },
-  { "rs",   OP8(0x00LL), MASK_RS_RRRD,    INSTR_RS_RRRD,     3,  0 ,0 },
-  { "rse",  OP8(0x00LL), MASK_RSE_RRRD,           INSTR_RSE_RRRD,    3,  0 ,0 },
-  { "rsi",  OP8(0x00LL), MASK_RSI_RRP,    INSTR_RSI_RRP,     3,  0 ,0 },
-  { "rsy",  OP8(0x00LL), MASK_RSY_RRRD,           INSTR_RSY_RRRD,    3,  3 ,0 },
-  { "rx",   OP8(0x00LL), MASK_RX_RRRD,    INSTR_RX_RRRD,     3,  0 ,0 },
-  { "rxe",  OP8(0x00LL), MASK_RXE_RRRD,           INSTR_RXE_RRRD,    3,  0 ,0 },
-  { "rxf",  OP8(0x00LL), MASK_RXF_RRRDR,   INSTR_RXF_RRRDR,   3,  0 ,0 },
-  { "rxy",  OP8(0x00LL), MASK_RXY_RRRD,           INSTR_RXY_RRRD,    3,  3 ,0 },
-  { "s",    OP8(0x00LL), MASK_S_RD,       INSTR_S_RD,        3,  0 ,0 },
-  { "si",   OP8(0x00LL), MASK_SI_URD,     INSTR_SI_URD,      3,  0 ,0 },
-  { "siy",  OP8(0x00LL), MASK_SIY_URD,    INSTR_SIY_URD,     3,  3 ,0 },
-  { "sil",  OP8(0x00LL), MASK_SIL_RDI,     INSTR_SIL_RDI,     3,  6 ,0 },
-  { "ss",   OP8(0x00LL), MASK_SS_RRRDRD,   INSTR_SS_RRRDRD,   3,  0 ,0 },
-  { "sse",  OP8(0x00LL), MASK_SSE_RDRD,           INSTR_SSE_RDRD,    3,  0 ,0 },
-  { "ssf",  OP8(0x00LL), MASK_SSF_RRDRD,   INSTR_SSF_RRDRD,   3,  0 ,0 },
-  { "vrv",  OP8(0x00LL), MASK_VRV_VVXRDU,  INSTR_VRV_VVXRDU,  3,  9 ,0 },
-  { "vri",  OP8(0x00LL), MASK_VRI_VVUUU,   INSTR_VRI_VVUUU,   3,  9 ,0 },
-  { "vrx",  OP8(0x00LL), MASK_VRX_VRRDU,   INSTR_VRX_VRRDU,   3,  9 ,0 },
-  { "vrs",  OP8(0x00LL), MASK_VRS_RVRDU,   INSTR_VRS_RVRDU,   3,  9 ,0 },
-  { "vrr",  OP8(0x00LL), MASK_VRR_VVV0UUU, INSTR_VRR_VVV0UUU, 3,  9 ,0 },
-  { "vsi",  OP8(0x00LL), MASK_VSI_URDV,           INSTR_VSI_URDV,    3, 10 ,0 },
+  { "e",    OP8(0x00LL), MASK_E,          INSTR_E,           3,  0, 0, NULL },
+  { "ri",   OP8(0x00LL), MASK_RI_RI,      INSTR_RI_RI,       3,  0, 0, NULL },
+  { "rie",  OP8(0x00LL), MASK_RIE_RRP,    INSTR_RIE_RRP,     3,  0, 0, NULL },
+  { "ril",  OP8(0x00LL), MASK_RIL_RP,     INSTR_RIL_RP,      3,  0, 0, NULL },
+  { "rilu", OP8(0x00LL), MASK_RIL_RU,     INSTR_RIL_RU,      3,  0, 0, NULL },
+  { "ris",  OP8(0x00LL), MASK_RIS_RURDI,   INSTR_RIS_RURDI,   3,  6, 0, NULL },
+  { "rr",   OP8(0x00LL), MASK_RR_RR,      INSTR_RR_RR,       3,  0, 0, NULL },
+  { "rre",  OP8(0x00LL), MASK_RRE_RR,     INSTR_RRE_RR,      3,  0, 0, NULL },
+  { "rrf",  OP8(0x00LL), MASK_RRF_RURR,           INSTR_RRF_RURR,    3,  0, 0, NULL },
+  { "rrs",  OP8(0x00LL), MASK_RRS_RRRDU,   INSTR_RRS_RRRDU,   3,  6, 0, NULL },
+  { "rs",   OP8(0x00LL), MASK_RS_RRRD,    INSTR_RS_RRRD,     3,  0, 0, NULL },
+  { "rse",  OP8(0x00LL), MASK_RSE_RRRD,           INSTR_RSE_RRRD,    3,  0, 0, NULL },
+  { "rsi",  OP8(0x00LL), MASK_RSI_RRP,    INSTR_RSI_RRP,     3,  0, 0, NULL },
+  { "rsy",  OP8(0x00LL), MASK_RSY_RRRD,           INSTR_RSY_RRRD,    3,  3, 0, NULL },
+  { "rx",   OP8(0x00LL), MASK_RX_RRRD,    INSTR_RX_RRRD,     3,  0, 0, NULL },
+  { "rxe",  OP8(0x00LL), MASK_RXE_RRRD,           INSTR_RXE_RRRD,    3,  0, 0, NULL },
+  { "rxf",  OP8(0x00LL), MASK_RXF_RRRDR,   INSTR_RXF_RRRDR,   3,  0, 0, NULL },
+  { "rxy",  OP8(0x00LL), MASK_RXY_RRRD,           INSTR_RXY_RRRD,    3,  3, 0, NULL },
+  { "s",    OP8(0x00LL), MASK_S_RD,       INSTR_S_RD,        3,  0, 0, NULL },
+  { "si",   OP8(0x00LL), MASK_SI_URD,     INSTR_SI_URD,      3,  0, 0, NULL },
+  { "siy",  OP8(0x00LL), MASK_SIY_URD,    INSTR_SIY_URD,     3,  3, 0, NULL },
+  { "sil",  OP8(0x00LL), MASK_SIL_RDI,     INSTR_SIL_RDI,     3,  6, 0, NULL },
+  { "ss",   OP8(0x00LL), MASK_SS_RRRDRD,   INSTR_SS_RRRDRD,   3,  0, 0, NULL },
+  { "sse",  OP8(0x00LL), MASK_SSE_RDRD,           INSTR_SSE_RDRD,    3,  0, 0, NULL },
+  { "ssf",  OP8(0x00LL), MASK_SSF_RRDRD,   INSTR_SSF_RRDRD,   3,  0, 0, NULL },
+  { "vrv",  OP8(0x00LL), MASK_VRV_VVXRDU,  INSTR_VRV_VVXRDU,  3,  9, 0, NULL },
+  { "vri",  OP8(0x00LL), MASK_VRI_VVUUU,   INSTR_VRI_VVUUU,   3,  9, 0, NULL },
+  { "vrx",  OP8(0x00LL), MASK_VRX_VRRDU,   INSTR_VRX_VRRDU,   3,  9, 0, NULL },
+  { "vrs",  OP8(0x00LL), MASK_VRS_RVRDU,   INSTR_VRS_RVRDU,   3,  9, 0, NULL },
+  { "vrr",  OP8(0x00LL), MASK_VRR_VVV0UUU, INSTR_VRR_VVV0UUU, 3,  9, 0, NULL },
+  { "vsi",  OP8(0x00LL), MASK_VSI_URDV,           INSTR_VSI_URDV,    3, 10, 0, NULL },
 };
 
 const int s390_num_opformats =