2010-09-27 Andreas Krebbel <Andreas.Krebbel@de.ibm.com>
[external/binutils.git] / opcodes / s390-dis.c
1 /* s390-dis.c -- Disassemble S390 instructions
2    Copyright 2000, 2001, 2002, 2003, 2005, 2007, 2008
3    Free Software Foundation, Inc.
4    Contributed by Martin Schwidefsky (schwidefsky@de.ibm.com).
5
6    This file is part of the GNU opcodes library.
7
8    This library is free software; you can redistribute it and/or modify
9    it under the terms of the GNU General Public License as published by
10    the Free Software Foundation; either version 3, or (at your option)
11    any later version.
12
13    It is distributed in the hope that it will be useful, but WITHOUT
14    ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
15    or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public
16    License for more details.
17
18    You should have received a copy of the GNU General Public License
19    along with this file; see the file COPYING.  If not, write to the
20    Free Software Foundation, 51 Franklin Street - Fifth Floor, Boston,
21    MA 02110-1301, USA.  */
22
23 #include <stdio.h>
24 #include "ansidecl.h"
25 #include "sysdep.h"
26 #include "dis-asm.h"
27 #include "opintl.h"
28 #include "opcode/s390.h"
29
30 static int init_flag = 0;
31 static int opc_index[256];
32 static int current_arch_mask = 0;
33
34 /* Set up index table for first opcode byte.  */
35
36 static void
37 init_disasm (struct disassemble_info *info)
38 {
39   const struct s390_opcode *opcode;
40   const struct s390_opcode *opcode_end;
41   const char *p;
42
43   memset (opc_index, 0, sizeof (opc_index));
44   opcode_end = s390_opcodes + s390_num_opcodes;
45   for (opcode = s390_opcodes; opcode < opcode_end; opcode++)
46     {
47       opc_index[(int) opcode->opcode[0]] = opcode - s390_opcodes;
48       while ((opcode < opcode_end) &&
49              (opcode[1].opcode[0] == opcode->opcode[0]))
50         opcode++;
51     }
52
53   for (p = info->disassembler_options; p != NULL; )
54     {
55       if (CONST_STRNEQ (p, "esa"))
56         current_arch_mask = 1 << S390_OPCODE_ESA;
57       else if (CONST_STRNEQ (p, "zarch"))
58         current_arch_mask = 1 << S390_OPCODE_ZARCH;
59       else
60         fprintf (stderr, "Unknown S/390 disassembler option: %s\n", p);
61
62       p = strchr (p, ',');
63       if (p != NULL)
64         p++;
65     }
66
67   if (!current_arch_mask)
68     switch (info->mach)
69       {
70       case bfd_mach_s390_31:
71         current_arch_mask = 1 << S390_OPCODE_ESA;
72         break;
73       case bfd_mach_s390_64:
74         current_arch_mask = 1 << S390_OPCODE_ZARCH;
75         break;
76       default:
77         abort ();
78       }
79
80   init_flag = 1;
81 }
82
83 /* Extracts an operand value from an instruction.  */
84 /* We do not perform the shift operation for larl-type address
85    operands here since that would lead to an overflow of the 32 bit
86    integer value.  Instead the shift operation is done when printing
87    the operand in print_insn_s390.  */
88
89 static inline unsigned int
90 s390_extract_operand (unsigned char *insn, const struct s390_operand *operand)
91 {
92   unsigned int val;
93   int bits;
94
95   /* Extract fragments of the operand byte for byte.  */
96   insn += operand->shift / 8;
97   bits = (operand->shift & 7) + operand->bits;
98   val = 0;
99   do
100     {
101       val <<= 8;
102       val |= (unsigned int) *insn++;
103       bits -= 8;
104     }
105   while (bits > 0);
106   val >>= -bits;
107   val &= ((1U << (operand->bits - 1)) << 1) - 1;
108
109   /* Check for special long displacement case.  */
110   if (operand->bits == 20 && operand->shift == 20)
111     val = (val & 0xff) << 12 | (val & 0xfff00) >> 8;
112
113   /* Sign extend value if the operand is signed or pc relative.  */
114   if ((operand->flags & (S390_OPERAND_SIGNED | S390_OPERAND_PCREL))
115       && (val & (1U << (operand->bits - 1))))
116     val |= (-1U << (operand->bits - 1)) << 1;
117
118   /* Length x in an instructions has real length x + 1.  */
119   if (operand->flags & S390_OPERAND_LENGTH)
120     val++;
121   return val;
122 }
123
124 /* Print a S390 instruction.  */
125
126 int
127 print_insn_s390 (bfd_vma memaddr, struct disassemble_info *info)
128 {
129   bfd_byte buffer[6];
130   const struct s390_opcode *opcode;
131   const struct s390_opcode *opcode_end;
132   unsigned int value;
133   int status, opsize, bufsize;
134   char separator;
135
136   if (init_flag == 0)
137     init_disasm (info);
138
139   /* The output looks better if we put 6 bytes on a line.  */
140   info->bytes_per_line = 6;
141
142   /* Every S390 instruction is max 6 bytes long.  */
143   memset (buffer, 0, 6);
144   status = (*info->read_memory_func) (memaddr, buffer, 6, info);
145   if (status != 0)
146     {
147       for (bufsize = 0; bufsize < 6; bufsize++)
148         if ((*info->read_memory_func) (memaddr, buffer, bufsize + 1, info) != 0)
149           break;
150       if (bufsize <= 0)
151         {
152           (*info->memory_error_func) (status, memaddr, info);
153           return -1;
154         }
155       /* Opsize calculation looks strange but it works
156          00xxxxxx -> 2 bytes, 01xxxxxx/10xxxxxx -> 4 bytes,
157          11xxxxxx -> 6 bytes.  */
158       opsize = ((((buffer[0] >> 6) + 1) >> 1) + 1) << 1;
159       status = opsize > bufsize;
160     }
161   else
162     {
163       bufsize = 6;
164       opsize = ((((buffer[0] >> 6) + 1) >> 1) + 1) << 1;
165     }
166
167   if (status == 0)
168     {
169       const struct s390_opcode *op;
170
171       /* Find the first match in the opcode table.  */
172       opcode_end = s390_opcodes + s390_num_opcodes;
173       for (opcode = s390_opcodes + opc_index[(int) buffer[0]];
174            (opcode < opcode_end) && (buffer[0] == opcode->opcode[0]);
175            opcode++)
176         {
177           const struct s390_operand *operand;
178           const unsigned char *opindex;
179
180           /* Check architecture.  */
181           if (!(opcode->modes & current_arch_mask))
182             continue;
183
184           /* Check signature of the opcode.  */
185           if ((buffer[1] & opcode->mask[1]) != opcode->opcode[1]
186               || (buffer[2] & opcode->mask[2]) != opcode->opcode[2]
187               || (buffer[3] & opcode->mask[3]) != opcode->opcode[3]
188               || (buffer[4] & opcode->mask[4]) != opcode->opcode[4]
189               || (buffer[5] & opcode->mask[5]) != opcode->opcode[5])
190             continue;
191
192           /* Advance to an opcode with a more specific mask.  */
193           for (op = opcode + 1; op < opcode_end; op++)
194             {
195               if ((buffer[0] & op->mask[0]) != op->opcode[0])
196                 break;
197
198               if ((buffer[1] & op->mask[1]) != op->opcode[1]
199                   || (buffer[2] & op->mask[2]) != op->opcode[2]
200                   || (buffer[3] & op->mask[3]) != op->opcode[3]
201                   || (buffer[4] & op->mask[4]) != op->opcode[4]
202                   || (buffer[5] & op->mask[5]) != op->opcode[5])
203                 continue;
204
205               if (((int)opcode->mask[0] + opcode->mask[1] +
206                    opcode->mask[2] + opcode->mask[3] +
207                    opcode->mask[4] + opcode->mask[5]) <
208                   ((int)op->mask[0] + op->mask[1] +
209                    op->mask[2] + op->mask[3] +
210                    op->mask[4] + op->mask[5]))
211                 opcode = op;
212             }
213
214           /* The instruction is valid.  */
215           if (opcode->operands[0] != 0)
216             (*info->fprintf_func) (info->stream, "%s\t", opcode->name);
217           else
218             (*info->fprintf_func) (info->stream, "%s", opcode->name);
219
220           /* Extract the operands.  */
221           separator = 0;
222           for (opindex = opcode->operands; *opindex != 0; opindex++)
223             {
224               operand = s390_operands + *opindex;
225               value = s390_extract_operand (buffer, operand);
226
227               if ((operand->flags & S390_OPERAND_INDEX) && value == 0)
228                 continue;
229               if ((operand->flags & S390_OPERAND_BASE) &&
230                   value == 0 && separator == '(')
231                 {
232                   separator = ',';
233                   continue;
234                 }
235
236               if (separator)
237                 (*info->fprintf_func) (info->stream, "%c", separator);
238
239               if (operand->flags & S390_OPERAND_GPR)
240                 (*info->fprintf_func) (info->stream, "%%r%i", value);
241               else if (operand->flags & S390_OPERAND_FPR)
242                 (*info->fprintf_func) (info->stream, "%%f%i", value);
243               else if (operand->flags & S390_OPERAND_AR)
244                 (*info->fprintf_func) (info->stream, "%%a%i", value);
245               else if (operand->flags & S390_OPERAND_CR)
246                 (*info->fprintf_func) (info->stream, "%%c%i", value);
247               else if (operand->flags & S390_OPERAND_PCREL)
248                 (*info->print_address_func) (memaddr + (int)value + (int)value,
249                                              info);
250               else if (operand->flags & S390_OPERAND_SIGNED)
251                 (*info->fprintf_func) (info->stream, "%i", (int) value);
252               else
253                 (*info->fprintf_func) (info->stream, "%u", value);
254
255               if (operand->flags & S390_OPERAND_DISP)
256                 {
257                   separator = '(';
258                 }
259               else if (operand->flags & S390_OPERAND_BASE)
260                 {
261                   (*info->fprintf_func) (info->stream, ")");
262                   separator = ',';
263                 }
264               else
265                 separator = ',';
266             }
267
268           /* Found instruction, printed it, return its size.  */
269           return opsize;
270         }
271       /* No matching instruction found, fall through to hex print.  */
272     }
273
274   if (bufsize >= 4)
275     {
276       value = (unsigned int) buffer[0];
277       value = (value << 8) + (unsigned int) buffer[1];
278       value = (value << 8) + (unsigned int) buffer[2];
279       value = (value << 8) + (unsigned int) buffer[3];
280       (*info->fprintf_func) (info->stream, ".long\t0x%08x", value);
281       return 4;
282     }
283   else if (bufsize >= 2)
284     {
285       value = (unsigned int) buffer[0];
286       value = (value << 8) + (unsigned int) buffer[1];
287       (*info->fprintf_func) (info->stream, ".short\t0x%04x", value);
288       return 2;
289     }
290   else
291     {
292       value = (unsigned int) buffer[0];
293       (*info->fprintf_func) (info->stream, ".byte\t0x%02x", value);
294       return 1;
295     }
296 }
297
298 void
299 print_s390_disassembler_options (FILE *stream)
300 {
301   fprintf (stream, _("\n\
302 The following S/390 specific disassembler options are supported for use\n\
303 with the -M switch (multiple options should be separated by commas):\n"));
304
305   fprintf (stream, _("  esa         Disassemble in ESA architecture mode\n"));
306   fprintf (stream, _("  zarch       Disassemble in z/Architecture mode\n"));
307 }