S/390: Disassemble 31-bit binaries with "zarch" opcode set by default
[platform/upstream/binutils.git] / opcodes / s390-dis.c
1 /* s390-dis.c -- Disassemble S390 instructions
2    Copyright 2000, 2001, 2002, 2003, 2005, 2007, 2008, 2012
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 "sysdep.h"
24 #include <stdio.h>
25 #include "ansidecl.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     current_arch_mask = 1 << S390_OPCODE_ZARCH;
69
70   init_flag = 1;
71 }
72
73 /* Extracts an operand value from an instruction.  */
74 /* We do not perform the shift operation for larl-type address
75    operands here since that would lead to an overflow of the 32 bit
76    integer value.  Instead the shift operation is done when printing
77    the operand in print_insn_s390.  */
78
79 static inline unsigned int
80 s390_extract_operand (unsigned char *insn, const struct s390_operand *operand)
81 {
82   unsigned int val;
83   int bits;
84
85   /* Extract fragments of the operand byte for byte.  */
86   insn += operand->shift / 8;
87   bits = (operand->shift & 7) + operand->bits;
88   val = 0;
89   do
90     {
91       val <<= 8;
92       val |= (unsigned int) *insn++;
93       bits -= 8;
94     }
95   while (bits > 0);
96   val >>= -bits;
97   val &= ((1U << (operand->bits - 1)) << 1) - 1;
98
99   /* Check for special long displacement case.  */
100   if (operand->bits == 20 && operand->shift == 20)
101     val = (val & 0xff) << 12 | (val & 0xfff00) >> 8;
102
103   /* Sign extend value if the operand is signed or pc relative.  */
104   if ((operand->flags & (S390_OPERAND_SIGNED | S390_OPERAND_PCREL))
105       && (val & (1U << (operand->bits - 1))))
106     val |= (-1U << (operand->bits - 1)) << 1;
107
108   /* Length x in an instructions has real length x + 1.  */
109   if (operand->flags & S390_OPERAND_LENGTH)
110     val++;
111   return val;
112 }
113
114 /* Print a S390 instruction.  */
115
116 int
117 print_insn_s390 (bfd_vma memaddr, struct disassemble_info *info)
118 {
119   bfd_byte buffer[6];
120   const struct s390_opcode *opcode;
121   const struct s390_opcode *opcode_end;
122   unsigned int value;
123   int status, opsize, bufsize;
124   char separator;
125
126   if (init_flag == 0)
127     init_disasm (info);
128
129   /* The output looks better if we put 6 bytes on a line.  */
130   info->bytes_per_line = 6;
131
132   /* Every S390 instruction is max 6 bytes long.  */
133   memset (buffer, 0, 6);
134   status = (*info->read_memory_func) (memaddr, buffer, 6, info);
135   if (status != 0)
136     {
137       for (bufsize = 0; bufsize < 6; bufsize++)
138         if ((*info->read_memory_func) (memaddr, buffer, bufsize + 1, info) != 0)
139           break;
140       if (bufsize <= 0)
141         {
142           (*info->memory_error_func) (status, memaddr, info);
143           return -1;
144         }
145       /* Opsize calculation looks strange but it works
146          00xxxxxx -> 2 bytes, 01xxxxxx/10xxxxxx -> 4 bytes,
147          11xxxxxx -> 6 bytes.  */
148       opsize = ((((buffer[0] >> 6) + 1) >> 1) + 1) << 1;
149       status = opsize > bufsize;
150     }
151   else
152     {
153       bufsize = 6;
154       opsize = ((((buffer[0] >> 6) + 1) >> 1) + 1) << 1;
155     }
156
157   if (status == 0)
158     {
159       const struct s390_opcode *op;
160
161       /* Find the first match in the opcode table.  */
162       opcode_end = s390_opcodes + s390_num_opcodes;
163       for (opcode = s390_opcodes + opc_index[(int) buffer[0]];
164            (opcode < opcode_end) && (buffer[0] == opcode->opcode[0]);
165            opcode++)
166         {
167           const struct s390_operand *operand;
168           const unsigned char *opindex;
169
170           /* Check architecture.  */
171           if (!(opcode->modes & current_arch_mask))
172             continue;
173
174           /* Check signature of the opcode.  */
175           if ((buffer[1] & opcode->mask[1]) != opcode->opcode[1]
176               || (buffer[2] & opcode->mask[2]) != opcode->opcode[2]
177               || (buffer[3] & opcode->mask[3]) != opcode->opcode[3]
178               || (buffer[4] & opcode->mask[4]) != opcode->opcode[4]
179               || (buffer[5] & opcode->mask[5]) != opcode->opcode[5])
180             continue;
181
182           /* Advance to an opcode with a more specific mask.  */
183           for (op = opcode + 1; op < opcode_end; op++)
184             {
185               if ((buffer[0] & op->mask[0]) != op->opcode[0])
186                 break;
187
188               if ((buffer[1] & op->mask[1]) != op->opcode[1]
189                   || (buffer[2] & op->mask[2]) != op->opcode[2]
190                   || (buffer[3] & op->mask[3]) != op->opcode[3]
191                   || (buffer[4] & op->mask[4]) != op->opcode[4]
192                   || (buffer[5] & op->mask[5]) != op->opcode[5])
193                 continue;
194
195               if (((int)opcode->mask[0] + opcode->mask[1] +
196                    opcode->mask[2] + opcode->mask[3] +
197                    opcode->mask[4] + opcode->mask[5]) <
198                   ((int)op->mask[0] + op->mask[1] +
199                    op->mask[2] + op->mask[3] +
200                    op->mask[4] + op->mask[5]))
201                 opcode = op;
202             }
203
204           /* The instruction is valid.  */
205           if (opcode->operands[0] != 0)
206             (*info->fprintf_func) (info->stream, "%s\t", opcode->name);
207           else
208             (*info->fprintf_func) (info->stream, "%s", opcode->name);
209
210           /* Extract the operands.  */
211           separator = 0;
212           for (opindex = opcode->operands; *opindex != 0; opindex++)
213             {
214               operand = s390_operands + *opindex;
215               value = s390_extract_operand (buffer, operand);
216
217               if ((operand->flags & S390_OPERAND_INDEX) && value == 0)
218                 continue;
219               if ((operand->flags & S390_OPERAND_BASE) &&
220                   value == 0 && separator == '(')
221                 {
222                   separator = ',';
223                   continue;
224                 }
225
226               if (separator)
227                 (*info->fprintf_func) (info->stream, "%c", separator);
228
229               if (operand->flags & S390_OPERAND_GPR)
230                 (*info->fprintf_func) (info->stream, "%%r%i", value);
231               else if (operand->flags & S390_OPERAND_FPR)
232                 (*info->fprintf_func) (info->stream, "%%f%i", value);
233               else if (operand->flags & S390_OPERAND_AR)
234                 (*info->fprintf_func) (info->stream, "%%a%i", value);
235               else if (operand->flags & S390_OPERAND_CR)
236                 (*info->fprintf_func) (info->stream, "%%c%i", value);
237               else if (operand->flags & S390_OPERAND_PCREL)
238                 (*info->print_address_func) (memaddr + (int)value + (int)value,
239                                              info);
240               else if (operand->flags & S390_OPERAND_SIGNED)
241                 (*info->fprintf_func) (info->stream, "%i", (int) value);
242               else
243                 (*info->fprintf_func) (info->stream, "%u", value);
244
245               if (operand->flags & S390_OPERAND_DISP)
246                 {
247                   separator = '(';
248                 }
249               else if (operand->flags & S390_OPERAND_BASE)
250                 {
251                   (*info->fprintf_func) (info->stream, ")");
252                   separator = ',';
253                 }
254               else
255                 separator = ',';
256             }
257
258           /* Found instruction, printed it, return its size.  */
259           return opsize;
260         }
261       /* No matching instruction found, fall through to hex print.  */
262     }
263
264   if (bufsize >= 4)
265     {
266       value = (unsigned int) buffer[0];
267       value = (value << 8) + (unsigned int) buffer[1];
268       value = (value << 8) + (unsigned int) buffer[2];
269       value = (value << 8) + (unsigned int) buffer[3];
270       (*info->fprintf_func) (info->stream, ".long\t0x%08x", value);
271       return 4;
272     }
273   else if (bufsize >= 2)
274     {
275       value = (unsigned int) buffer[0];
276       value = (value << 8) + (unsigned int) buffer[1];
277       (*info->fprintf_func) (info->stream, ".short\t0x%04x", value);
278       return 2;
279     }
280   else
281     {
282       value = (unsigned int) buffer[0];
283       (*info->fprintf_func) (info->stream, ".byte\t0x%02x", value);
284       return 1;
285     }
286 }
287
288 void
289 print_s390_disassembler_options (FILE *stream)
290 {
291   fprintf (stream, _("\n\
292 The following S/390 specific disassembler options are supported for use\n\
293 with the -M switch (multiple options should be separated by commas):\n"));
294
295   fprintf (stream, _("  esa         Disassemble in ESA architecture mode\n"));
296   fprintf (stream, _("  zarch       Disassemble in z/Architecture mode\n"));
297 }