Back to index

cell-binutils  2.17cvs20070401
s390-dis.c
Go to the documentation of this file.
00001 /* s390-dis.c -- Disassemble S390 instructions
00002    Copyright 2000, 2001, 2002, 2003, 2005 Free Software Foundation, Inc.
00003    Contributed by Martin Schwidefsky (schwidefsky@de.ibm.com).
00004 
00005    This file is part of GDB, GAS and the GNU binutils.
00006 
00007    This program is free software; you can redistribute it and/or modify
00008    it under the terms of the GNU General Public License as published by
00009    the Free Software Foundation; either version 2 of the License, or
00010    (at your option) any later version.
00011 
00012    This program is distributed in the hope that it will be useful,
00013    but WITHOUT ANY WARRANTY; without even the implied warranty of
00014    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00015    GNU General Public License for more details.
00016 
00017    You should have received a copy of the GNU General Public License
00018    along with this program; if not, write to the Free Software
00019    Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA
00020    02110-1301, USA.  */
00021 
00022 #include <stdio.h>
00023 #include "ansidecl.h"
00024 #include "sysdep.h"
00025 #include "dis-asm.h"
00026 #include "opcode/s390.h"
00027 
00028 static int init_flag = 0;
00029 static int opc_index[256];
00030 static int current_arch_mask = 0;
00031 
00032 /* Set up index table for first opcode byte.  */
00033 
00034 static void
00035 init_disasm (struct disassemble_info *info)
00036 {
00037   const struct s390_opcode *opcode;
00038   const struct s390_opcode *opcode_end;
00039 
00040   memset (opc_index, 0, sizeof (opc_index));
00041   opcode_end = s390_opcodes + s390_num_opcodes;
00042   for (opcode = s390_opcodes; opcode < opcode_end; opcode++)
00043     {
00044       opc_index[(int) opcode->opcode[0]] = opcode - s390_opcodes;
00045       while ((opcode < opcode_end) &&
00046             (opcode[1].opcode[0] == opcode->opcode[0]))
00047        opcode++;
00048     }
00049   switch (info->mach)
00050     {
00051     case bfd_mach_s390_31:
00052       current_arch_mask = 1 << S390_OPCODE_ESA;
00053       break;
00054     case bfd_mach_s390_64:
00055       current_arch_mask = 1 << S390_OPCODE_ZARCH;
00056       break;
00057     default:
00058       abort ();
00059     }
00060   init_flag = 1;
00061 }
00062 
00063 /* Extracts an operand value from an instruction.  */
00064 
00065 static inline unsigned int
00066 s390_extract_operand (unsigned char *insn, const struct s390_operand *operand)
00067 {
00068   unsigned int val;
00069   int bits;
00070 
00071   /* Extract fragments of the operand byte for byte.  */
00072   insn += operand->shift / 8;
00073   bits = (operand->shift & 7) + operand->bits;
00074   val = 0;
00075   do
00076     {
00077       val <<= 8;
00078       val |= (unsigned int) *insn++;
00079       bits -= 8;
00080     }
00081   while (bits > 0);
00082   val >>= -bits;
00083   val &= ((1U << (operand->bits - 1)) << 1) - 1;
00084 
00085   /* Check for special long displacement case.  */
00086   if (operand->bits == 20 && operand->shift == 20)
00087     val = (val & 0xff) << 12 | (val & 0xfff00) >> 8;
00088 
00089   /* Sign extend value if the operand is signed or pc relative.  */
00090   if ((operand->flags & (S390_OPERAND_SIGNED | S390_OPERAND_PCREL))
00091       && (val & (1U << (operand->bits - 1))))
00092     val |= (-1U << (operand->bits - 1)) << 1;
00093 
00094   /* Double value if the operand is pc relative.  */
00095   if (operand->flags & S390_OPERAND_PCREL)
00096     val <<= 1;
00097 
00098   /* Length x in an instructions has real length x + 1.  */
00099   if (operand->flags & S390_OPERAND_LENGTH)
00100     val++;
00101   return val;
00102 }
00103 
00104 /* Print a S390 instruction.  */
00105 
00106 int
00107 print_insn_s390 (bfd_vma memaddr, struct disassemble_info *info)
00108 {
00109   bfd_byte buffer[6];
00110   const struct s390_opcode *opcode;
00111   const struct s390_opcode *opcode_end;
00112   unsigned int value;
00113   int status, opsize, bufsize;
00114   char separator;
00115 
00116   if (init_flag == 0)
00117     init_disasm (info);
00118 
00119   /* The output looks better if we put 6 bytes on a line.  */
00120   info->bytes_per_line = 6;
00121 
00122   /* Every S390 instruction is max 6 bytes long.  */
00123   memset (buffer, 0, 6);
00124   status = (*info->read_memory_func) (memaddr, buffer, 6, info);
00125   if (status != 0)
00126     {
00127       for (bufsize = 0; bufsize < 6; bufsize++)
00128        if ((*info->read_memory_func) (memaddr, buffer, bufsize + 1, info) != 0)
00129          break;
00130       if (bufsize <= 0)
00131        {
00132          (*info->memory_error_func) (status, memaddr, info);
00133          return -1;
00134        }
00135       /* Opsize calculation looks strange but it works
00136         00xxxxxx -> 2 bytes, 01xxxxxx/10xxxxxx -> 4 bytes,
00137         11xxxxxx -> 6 bytes.  */
00138       opsize = ((((buffer[0] >> 6) + 1) >> 1) + 1) << 1;
00139       status = opsize > bufsize;
00140     }
00141   else
00142     {
00143       bufsize = 6;
00144       opsize = ((((buffer[0] >> 6) + 1) >> 1) + 1) << 1;
00145     }
00146 
00147   if (status == 0)
00148     {
00149       /* Find the first match in the opcode table.  */
00150       opcode_end = s390_opcodes + s390_num_opcodes;
00151       for (opcode = s390_opcodes + opc_index[(int) buffer[0]];
00152           (opcode < opcode_end) && (buffer[0] == opcode->opcode[0]);
00153           opcode++)
00154        {
00155          const struct s390_operand *operand;
00156          const unsigned char *opindex;
00157 
00158          /* Check architecture.  */
00159          if (!(opcode->modes & current_arch_mask))
00160            continue;
00161          /* Check signature of the opcode.  */
00162          if ((buffer[1] & opcode->mask[1]) != opcode->opcode[1]
00163              || (buffer[2] & opcode->mask[2]) != opcode->opcode[2]
00164              || (buffer[3] & opcode->mask[3]) != opcode->opcode[3]
00165              || (buffer[4] & opcode->mask[4]) != opcode->opcode[4]
00166              || (buffer[5] & opcode->mask[5]) != opcode->opcode[5])
00167            continue;
00168 
00169          /* The instruction is valid.  */
00170          if (opcode->operands[0] != 0)
00171            (*info->fprintf_func) (info->stream, "%s\t", opcode->name);
00172          else
00173            (*info->fprintf_func) (info->stream, "%s", opcode->name);
00174 
00175          /* Extract the operands.  */
00176          separator = 0;
00177          for (opindex = opcode->operands; *opindex != 0; opindex++)
00178            {
00179              unsigned int value;
00180 
00181              operand = s390_operands + *opindex;
00182              value = s390_extract_operand (buffer, operand);
00183 
00184              if ((operand->flags & S390_OPERAND_INDEX) && value == 0)
00185               continue;
00186              if ((operand->flags & S390_OPERAND_BASE) &&
00187                 value == 0 && separator == '(')
00188               {
00189                 separator = ',';
00190                 continue;
00191               }
00192 
00193              if (separator)
00194               (*info->fprintf_func) (info->stream, "%c", separator);
00195 
00196              if (operand->flags & S390_OPERAND_GPR)
00197               (*info->fprintf_func) (info->stream, "%%r%i", value);
00198              else if (operand->flags & S390_OPERAND_FPR)
00199               (*info->fprintf_func) (info->stream, "%%f%i", value);
00200              else if (operand->flags & S390_OPERAND_AR)
00201               (*info->fprintf_func) (info->stream, "%%a%i", value);
00202              else if (operand->flags & S390_OPERAND_CR)
00203               (*info->fprintf_func) (info->stream, "%%c%i", value);
00204              else if (operand->flags & S390_OPERAND_PCREL)
00205               (*info->print_address_func) (memaddr + (int) value, info);
00206              else if (operand->flags & S390_OPERAND_SIGNED)
00207               (*info->fprintf_func) (info->stream, "%i", (int) value);
00208              else
00209               (*info->fprintf_func) (info->stream, "%u", value);
00210 
00211              if (operand->flags & S390_OPERAND_DISP)
00212               {
00213                 separator = '(';
00214               }
00215              else if (operand->flags & S390_OPERAND_BASE)
00216               {
00217                 (*info->fprintf_func) (info->stream, ")");
00218                 separator = ',';
00219               }
00220              else
00221               separator = ',';
00222            }
00223 
00224          /* Found instruction, printed it, return its size.  */
00225          return opsize;
00226        }
00227       /* No matching instruction found, fall through to hex print.  */
00228     }
00229 
00230   if (bufsize >= 4)
00231     {
00232       value = (unsigned int) buffer[0];
00233       value = (value << 8) + (unsigned int) buffer[1];
00234       value = (value << 8) + (unsigned int) buffer[2];
00235       value = (value << 8) + (unsigned int) buffer[3];
00236       (*info->fprintf_func) (info->stream, ".long\t0x%08x", value);
00237       return 4;
00238     }
00239   else if (bufsize >= 2)
00240     {
00241       value = (unsigned int) buffer[0];
00242       value = (value << 8) + (unsigned int) buffer[1];
00243       (*info->fprintf_func) (info->stream, ".short\t0x%04x", value);
00244       return 2;
00245     }
00246   else
00247     {
00248       value = (unsigned int) buffer[0];
00249       (*info->fprintf_func) (info->stream, ".byte\t0x%02x", value);
00250       return 1;
00251     }
00252 }