Upload Tizen:Base source
[external/gdb.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       /* Find the first match in the opcode table.  */
170       opcode_end = s390_opcodes + s390_num_opcodes;
171       for (opcode = s390_opcodes + opc_index[(int) buffer[0]];
172            (opcode < opcode_end) && (buffer[0] == opcode->opcode[0]);
173            opcode++)
174         {
175           const struct s390_operand *operand;
176           const unsigned char *opindex;
177
178           /* Check architecture.  */
179           if (!(opcode->modes & current_arch_mask))
180             continue;
181           /* Check signature of the opcode.  */
182           if ((buffer[1] & opcode->mask[1]) != opcode->opcode[1]
183               || (buffer[2] & opcode->mask[2]) != opcode->opcode[2]
184               || (buffer[3] & opcode->mask[3]) != opcode->opcode[3]
185               || (buffer[4] & opcode->mask[4]) != opcode->opcode[4]
186               || (buffer[5] & opcode->mask[5]) != opcode->opcode[5])
187             continue;
188
189           /* The instruction is valid.  */
190           if (opcode->operands[0] != 0)
191             (*info->fprintf_func) (info->stream, "%s\t", opcode->name);
192           else
193             (*info->fprintf_func) (info->stream, "%s", opcode->name);
194
195           /* Extract the operands.  */
196           separator = 0;
197           for (opindex = opcode->operands; *opindex != 0; opindex++)
198             {
199               operand = s390_operands + *opindex;
200               value = s390_extract_operand (buffer, operand);
201
202               if ((operand->flags & S390_OPERAND_INDEX) && value == 0)
203                 continue;
204               if ((operand->flags & S390_OPERAND_BASE) &&
205                   value == 0 && separator == '(')
206                 {
207                   separator = ',';
208                   continue;
209                 }
210
211               if (separator)
212                 (*info->fprintf_func) (info->stream, "%c", separator);
213
214               if (operand->flags & S390_OPERAND_GPR)
215                 (*info->fprintf_func) (info->stream, "%%r%i", value);
216               else if (operand->flags & S390_OPERAND_FPR)
217                 (*info->fprintf_func) (info->stream, "%%f%i", value);
218               else if (operand->flags & S390_OPERAND_AR)
219                 (*info->fprintf_func) (info->stream, "%%a%i", value);
220               else if (operand->flags & S390_OPERAND_CR)
221                 (*info->fprintf_func) (info->stream, "%%c%i", value);
222               else if (operand->flags & S390_OPERAND_PCREL)
223                 (*info->print_address_func) (memaddr + (int)value + (int)value,
224                                              info);
225               else if (operand->flags & S390_OPERAND_SIGNED)
226                 (*info->fprintf_func) (info->stream, "%i", (int) value);
227               else
228                 (*info->fprintf_func) (info->stream, "%u", value);
229
230               if (operand->flags & S390_OPERAND_DISP)
231                 {
232                   separator = '(';
233                 }
234               else if (operand->flags & S390_OPERAND_BASE)
235                 {
236                   (*info->fprintf_func) (info->stream, ")");
237                   separator = ',';
238                 }
239               else
240                 separator = ',';
241             }
242
243           /* Found instruction, printed it, return its size.  */
244           return opsize;
245         }
246       /* No matching instruction found, fall through to hex print.  */
247     }
248
249   if (bufsize >= 4)
250     {
251       value = (unsigned int) buffer[0];
252       value = (value << 8) + (unsigned int) buffer[1];
253       value = (value << 8) + (unsigned int) buffer[2];
254       value = (value << 8) + (unsigned int) buffer[3];
255       (*info->fprintf_func) (info->stream, ".long\t0x%08x", value);
256       return 4;
257     }
258   else if (bufsize >= 2)
259     {
260       value = (unsigned int) buffer[0];
261       value = (value << 8) + (unsigned int) buffer[1];
262       (*info->fprintf_func) (info->stream, ".short\t0x%04x", value);
263       return 2;
264     }
265   else
266     {
267       value = (unsigned int) buffer[0];
268       (*info->fprintf_func) (info->stream, ".byte\t0x%02x", value);
269       return 1;
270     }
271 }
272
273 void
274 print_s390_disassembler_options (FILE *stream)
275 {
276   fprintf (stream, _("\n\
277 The following S/390 specific disassembler options are supported for use\n\
278 with the -M switch (multiple options should be separated by commas):\n"));
279
280   fprintf (stream, _("  esa         Disassemble in ESA architecture mode\n"));
281   fprintf (stream, _("  zarch       Disassemble in z/Architecture mode\n"));
282 }