OSDN Git Service

Allow lock on cmpxch16b.
[pf3gnuchains/pf3gnuchains3x.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               unsigned int value;
200
201               operand = s390_operands + *opindex;
202               value = s390_extract_operand (buffer, operand);
203
204               if ((operand->flags & S390_OPERAND_INDEX) && value == 0)
205                 continue;
206               if ((operand->flags & S390_OPERAND_BASE) &&
207                   value == 0 && separator == '(')
208                 {
209                   separator = ',';
210                   continue;
211                 }
212
213               if (separator)
214                 (*info->fprintf_func) (info->stream, "%c", separator);
215
216               if (operand->flags & S390_OPERAND_GPR)
217                 (*info->fprintf_func) (info->stream, "%%r%i", value);
218               else if (operand->flags & S390_OPERAND_FPR)
219                 (*info->fprintf_func) (info->stream, "%%f%i", value);
220               else if (operand->flags & S390_OPERAND_AR)
221                 (*info->fprintf_func) (info->stream, "%%a%i", value);
222               else if (operand->flags & S390_OPERAND_CR)
223                 (*info->fprintf_func) (info->stream, "%%c%i", value);
224               else if (operand->flags & S390_OPERAND_PCREL)
225                 (*info->print_address_func) (memaddr + (int)value + (int)value,
226                                              info);
227               else if (operand->flags & S390_OPERAND_SIGNED)
228                 (*info->fprintf_func) (info->stream, "%i", (int) value);
229               else
230                 (*info->fprintf_func) (info->stream, "%u", value);
231
232               if (operand->flags & S390_OPERAND_DISP)
233                 {
234                   separator = '(';
235                 }
236               else if (operand->flags & S390_OPERAND_BASE)
237                 {
238                   (*info->fprintf_func) (info->stream, ")");
239                   separator = ',';
240                 }
241               else
242                 separator = ',';
243             }
244
245           /* Found instruction, printed it, return its size.  */
246           return opsize;
247         }
248       /* No matching instruction found, fall through to hex print.  */
249     }
250
251   if (bufsize >= 4)
252     {
253       value = (unsigned int) buffer[0];
254       value = (value << 8) + (unsigned int) buffer[1];
255       value = (value << 8) + (unsigned int) buffer[2];
256       value = (value << 8) + (unsigned int) buffer[3];
257       (*info->fprintf_func) (info->stream, ".long\t0x%08x", value);
258       return 4;
259     }
260   else if (bufsize >= 2)
261     {
262       value = (unsigned int) buffer[0];
263       value = (value << 8) + (unsigned int) buffer[1];
264       (*info->fprintf_func) (info->stream, ".short\t0x%04x", value);
265       return 2;
266     }
267   else
268     {
269       value = (unsigned int) buffer[0];
270       (*info->fprintf_func) (info->stream, ".byte\t0x%02x", value);
271       return 1;
272     }
273 }
274
275 void
276 print_s390_disassembler_options (FILE *stream)
277 {
278   fprintf (stream, _("\n\
279 The following S/390 specific disassembler options are supported for use\n\
280 with the -M switch (multiple options should be separated by commas):\n"));
281
282   fprintf (stream, _("  esa         Disassemble in ESA architecture mode\n"));
283   fprintf (stream, _("  zarch       Disassemble in z/Architecture mode\n"));
284 }