Compile rsp-low.c for IPA
[deliverable/binutils-gdb.git] / opcodes / s390-dis.c
CommitLineData
a85d7ed0 1/* s390-dis.c -- Disassemble S390 instructions
df7b86aa 2 Copyright 2000, 2001, 2002, 2003, 2005, 2007, 2008, 2012
aa820537 3 Free Software Foundation, Inc.
a85d7ed0
NC
4 Contributed by Martin Schwidefsky (schwidefsky@de.ibm.com).
5
9b201bb5 6 This file is part of the GNU opcodes library.
a85d7ed0 7
9b201bb5 8 This library is free software; you can redistribute it and/or modify
a85d7ed0 9 it under the terms of the GNU General Public License as published by
9b201bb5
NC
10 the Free Software Foundation; either version 3, or (at your option)
11 any later version.
a85d7ed0 12
9b201bb5
NC
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.
a85d7ed0
NC
17
18 You should have received a copy of the GNU General Public License
9b201bb5
NC
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. */
a85d7ed0 22
df7b86aa 23#include "sysdep.h"
a85d7ed0
NC
24#include <stdio.h>
25#include "ansidecl.h"
a85d7ed0 26#include "dis-asm.h"
112b7c50 27#include "opintl.h"
a85d7ed0
NC
28#include "opcode/s390.h"
29
30static int init_flag = 0;
31static int opc_index[256];
32static int current_arch_mask = 0;
33
44f2a95d
KH
34/* Set up index table for first opcode byte. */
35
36static void
47b0e7ad 37init_disasm (struct disassemble_info *info)
a85d7ed0
NC
38{
39 const struct s390_opcode *opcode;
40 const struct s390_opcode *opcode_end;
112b7c50 41 const char *p;
a85d7ed0 42
44f2a95d 43 memset (opc_index, 0, sizeof (opc_index));
a85d7ed0 44 opcode_end = s390_opcodes + s390_num_opcodes;
44f2a95d
KH
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 }
112b7c50
AK
52
53 for (p = info->disassembler_options; p != NULL; )
44f2a95d 54 {
112b7c50
AK
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++;
44f2a95d 65 }
112b7c50
AK
66
67 if (!current_arch_mask)
7d4a7d10 68 current_arch_mask = 1 << S390_OPCODE_ZARCH;
112b7c50 69
a85d7ed0
NC
70 init_flag = 1;
71}
72
73/* Extracts an operand value from an instruction. */
7330f9c3
AK
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. */
a85d7ed0
NC
78
79static inline unsigned int
47b0e7ad 80s390_extract_operand (unsigned char *insn, const struct s390_operand *operand)
a85d7ed0
NC
81{
82 unsigned int val;
83 int bits;
84
44f2a95d
KH
85 /* Extract fragments of the operand byte for byte. */
86 insn += operand->shift / 8;
a85d7ed0
NC
87 bits = (operand->shift & 7) + operand->bits;
88 val = 0;
44f2a95d
KH
89 do
90 {
91 val <<= 8;
92 val |= (unsigned int) *insn++;
93 bits -= 8;
94 }
95 while (bits > 0);
a85d7ed0 96 val >>= -bits;
44f2a95d
KH
97 val &= ((1U << (operand->bits - 1)) << 1) - 1;
98
bac02689
MS
99 /* Check for special long displacement case. */
100 if (operand->bits == 20 && operand->shift == 20)
101 val = (val & 0xff) << 12 | (val & 0xfff00) >> 8;
102
44f2a95d
KH
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
47b0e7ad 108 /* Length x in an instructions has real length x + 1. */
a85d7ed0
NC
109 if (operand->flags & S390_OPERAND_LENGTH)
110 val++;
111 return val;
112}
113
114/* Print a S390 instruction. */
115
116int
47b0e7ad 117print_insn_s390 (bfd_vma memaddr, struct disassemble_info *info)
a85d7ed0
NC
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)
44f2a95d 127 init_disasm (info);
a85d7ed0
NC
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. */
44f2a95d 133 memset (buffer, 0, 6);
a85d7ed0 134 status = (*info->read_memory_func) (memaddr, buffer, 6, info);
44f2a95d
KH
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 {
02cbf767
AK
159 const struct s390_opcode *op;
160
44f2a95d
KH
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. */
af169f23 171 if (!(opcode->modes & current_arch_mask))
44f2a95d 172 continue;
02cbf767 173
44f2a95d
KH
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
02cbf767
AK
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
44f2a95d
KH
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 {
44f2a95d
KH
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)
c8676ae4
AK
238 (*info->print_address_func) (memaddr + (int)value + (int)value,
239 info);
44f2a95d
KH
240 else if (operand->flags & S390_OPERAND_SIGNED)
241 (*info->fprintf_func) (info->stream, "%i", (int) value);
242 else
ad101263 243 (*info->fprintf_func) (info->stream, "%u", value);
44f2a95d
KH
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;
a85d7ed0 279 }
44f2a95d
KH
280 else
281 {
282 value = (unsigned int) buffer[0];
283 (*info->fprintf_func) (info->stream, ".byte\t0x%02x", value);
284 return 1;
a85d7ed0 285 }
a85d7ed0 286}
112b7c50
AK
287
288void
289print_s390_disassembler_options (FILE *stream)
290{
291 fprintf (stream, _("\n\
292The following S/390 specific disassembler options are supported for use\n\
293with 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}
This page took 0.732269 seconds and 4 git commands to generate.