Make linker scripts and section ordering via --section-ordering-file or
[deliverable/binutils-gdb.git] / opcodes / s390-dis.c
index b574edb60f70ee9f7b565b445826b823e72d836f..ef73d85f9b60d6afc9d835653916ff4465e82fcf 100644 (file)
@@ -1,46 +1,44 @@
 /* s390-dis.c -- Disassemble S390 instructions
-   Copyright 2000, 2001, 2002, 2003 Free Software Foundation, Inc.
+   Copyright 2000, 2001, 2002, 2003, 2005, 2007, 2008, 2012
+   Free Software Foundation, Inc.
    Contributed by Martin Schwidefsky (schwidefsky@de.ibm.com).
 
-   This file is part of GDB, GAS and the GNU binutils.
+   This file is part of the GNU opcodes library.
 
-   This program is free software; you can redistribute it and/or modify
+   This library is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
-   the Free Software Foundation; either version 2 of the License, or
-   (at your option) any later version.
+   the Free Software Foundation; either version 3, or (at your option)
+   any later version.
 
-   This program is distributed in the hope that it will be useful,
-   but WITHOUT ANY WARRANTY; without even the implied warranty of
-   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-   GNU General Public License for more details.
+   It is distributed in the hope that it will be useful, but WITHOUT
+   ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+   or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public
+   License for more details.
 
    You should have received a copy of the GNU General Public License
-   along with this program; if not, write to the Free Software
-   Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
-   02111-1307, USA.  */
+   along with this file; see the file COPYING.  If not, write to the
+   Free Software Foundation, 51 Franklin Street - Fifth Floor, Boston,
+   MA 02110-1301, USA.  */
 
+#include "sysdep.h"
 #include <stdio.h>
 #include "ansidecl.h"
-#include "sysdep.h"
 #include "dis-asm.h"
+#include "opintl.h"
 #include "opcode/s390.h"
 
 static int init_flag = 0;
 static int opc_index[256];
 static int current_arch_mask = 0;
 
-static void init_disasm PARAMS ((struct disassemble_info *));
-static unsigned int s390_extract_operand
-  PARAMS ((unsigned char *, const struct s390_operand *));
-
 /* Set up index table for first opcode byte.  */
 
 static void
-init_disasm (info)
-     struct disassemble_info *info;
+init_disasm (struct disassemble_info *info)
 {
   const struct s390_opcode *opcode;
   const struct s390_opcode *opcode_end;
+  const char *p;
 
   memset (opc_index, 0, sizeof (opc_index));
   opcode_end = s390_opcodes + s390_num_opcodes;
@@ -51,26 +49,45 @@ init_disasm (info)
             (opcode[1].opcode[0] == opcode->opcode[0]))
        opcode++;
     }
-  switch (info->mach)
+
+  for (p = info->disassembler_options; p != NULL; )
     {
-    case bfd_mach_s390_31:
-      current_arch_mask = 1 << S390_OPCODE_ESA;
-      break;
-    case bfd_mach_s390_64:
-      current_arch_mask = 1 << S390_OPCODE_ZARCH;
-      break;
-    default:
-      abort ();
+      if (CONST_STRNEQ (p, "esa"))
+       current_arch_mask = 1 << S390_OPCODE_ESA;
+      else if (CONST_STRNEQ (p, "zarch"))
+       current_arch_mask = 1 << S390_OPCODE_ZARCH;
+      else
+       fprintf (stderr, "Unknown S/390 disassembler option: %s\n", p);
+
+      p = strchr (p, ',');
+      if (p != NULL)
+       p++;
     }
+
+  if (!current_arch_mask)
+    switch (info->mach)
+      {
+      case bfd_mach_s390_31:
+       current_arch_mask = 1 << S390_OPCODE_ESA;
+       break;
+      case bfd_mach_s390_64:
+       current_arch_mask = 1 << S390_OPCODE_ZARCH;
+       break;
+      default:
+       abort ();
+      }
+
   init_flag = 1;
 }
 
 /* Extracts an operand value from an instruction.  */
+/* We do not perform the shift operation for larl-type address
+   operands here since that would lead to an overflow of the 32 bit
+   integer value.  Instead the shift operation is done when printing
+   the operand in print_insn_s390.  */
 
 static inline unsigned int
-s390_extract_operand (insn, operand)
-     unsigned char *insn;
-     const struct s390_operand *operand;
+s390_extract_operand (unsigned char *insn, const struct s390_operand *operand)
 {
   unsigned int val;
   int bits;
@@ -98,11 +115,7 @@ s390_extract_operand (insn, operand)
       && (val & (1U << (operand->bits - 1))))
     val |= (-1U << (operand->bits - 1)) << 1;
 
-  /* Double value if the operand is pc relative.  */
-  if (operand->flags & S390_OPERAND_PCREL)
-    val <<= 1;
-
-  /* Length x in an instructions has real length x+1.  */
+  /* Length x in an instructions has real length x + 1.  */
   if (operand->flags & S390_OPERAND_LENGTH)
     val++;
   return val;
@@ -111,9 +124,7 @@ s390_extract_operand (insn, operand)
 /* Print a S390 instruction.  */
 
 int
-print_insn_s390 (memaddr, info)
-     bfd_vma memaddr;
-     struct disassemble_info *info;
+print_insn_s390 (bfd_vma memaddr, struct disassemble_info *info)
 {
   bfd_byte buffer[6];
   const struct s390_opcode *opcode;
@@ -155,6 +166,8 @@ print_insn_s390 (memaddr, info)
 
   if (status == 0)
     {
+      const struct s390_opcode *op;
+
       /* Find the first match in the opcode table.  */
       opcode_end = s390_opcodes + s390_num_opcodes;
       for (opcode = s390_opcodes + opc_index[(int) buffer[0]];
@@ -167,6 +180,7 @@ print_insn_s390 (memaddr, info)
          /* Check architecture.  */
          if (!(opcode->modes & current_arch_mask))
            continue;
+
          /* Check signature of the opcode.  */
          if ((buffer[1] & opcode->mask[1]) != opcode->opcode[1]
              || (buffer[2] & opcode->mask[2]) != opcode->opcode[2]
@@ -175,6 +189,28 @@ print_insn_s390 (memaddr, info)
              || (buffer[5] & opcode->mask[5]) != opcode->opcode[5])
            continue;
 
+         /* Advance to an opcode with a more specific mask.  */
+         for (op = opcode + 1; op < opcode_end; op++)
+           {
+             if ((buffer[0] & op->mask[0]) != op->opcode[0])
+               break;
+
+             if ((buffer[1] & op->mask[1]) != op->opcode[1]
+                 || (buffer[2] & op->mask[2]) != op->opcode[2]
+                 || (buffer[3] & op->mask[3]) != op->opcode[3]
+                 || (buffer[4] & op->mask[4]) != op->opcode[4]
+                 || (buffer[5] & op->mask[5]) != op->opcode[5])
+               continue;
+
+             if (((int)opcode->mask[0] + opcode->mask[1] +
+                  opcode->mask[2] + opcode->mask[3] +
+                  opcode->mask[4] + opcode->mask[5]) <
+                 ((int)op->mask[0] + op->mask[1] +
+                  op->mask[2] + op->mask[3] +
+                  op->mask[4] + op->mask[5]))
+               opcode = op;
+           }
+
          /* The instruction is valid.  */
          if (opcode->operands[0] != 0)
            (*info->fprintf_func) (info->stream, "%s\t", opcode->name);
@@ -185,8 +221,6 @@ print_insn_s390 (memaddr, info)
          separator = 0;
          for (opindex = opcode->operands; *opindex != 0; opindex++)
            {
-             unsigned int value;
-
              operand = s390_operands + *opindex;
              value = s390_extract_operand (buffer, operand);
 
@@ -211,11 +245,12 @@ print_insn_s390 (memaddr, info)
              else if (operand->flags & S390_OPERAND_CR)
                (*info->fprintf_func) (info->stream, "%%c%i", value);
              else if (operand->flags & S390_OPERAND_PCREL)
-               (*info->print_address_func) (memaddr + (int) value, info);
+               (*info->print_address_func) (memaddr + (int)value + (int)value,
+                                            info);
              else if (operand->flags & S390_OPERAND_SIGNED)
                (*info->fprintf_func) (info->stream, "%i", (int) value);
              else
-               (*info->fprintf_func) (info->stream, "%i", value);
+               (*info->fprintf_func) (info->stream, "%u", value);
 
              if (operand->flags & S390_OPERAND_DISP)
                {
@@ -259,3 +294,14 @@ print_insn_s390 (memaddr, info)
       return 1;
     }
 }
+
+void
+print_s390_disassembler_options (FILE *stream)
+{
+  fprintf (stream, _("\n\
+The following S/390 specific disassembler options are supported for use\n\
+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"));
+}
This page took 0.038742 seconds and 4 git commands to generate.