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