Don't deprecate powerpc mftb insn
[deliverable/binutils-gdb.git] / opcodes / s390-dis.c
CommitLineData
a85d7ed0 1/* s390-dis.c -- Disassemble S390 instructions
4b95cf5c 2 Copyright (C) 2000-2014 Free Software Foundation, Inc.
a85d7ed0
NC
3 Contributed by Martin Schwidefsky (schwidefsky@de.ibm.com).
4
9b201bb5 5 This file is part of the GNU opcodes library.
a85d7ed0 6
9b201bb5 7 This library is free software; you can redistribute it and/or modify
a85d7ed0 8 it under the terms of the GNU General Public License as published by
9b201bb5
NC
9 the Free Software Foundation; either version 3, or (at your option)
10 any later version.
a85d7ed0 11
9b201bb5
NC
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.
a85d7ed0
NC
16
17 You should have received a copy of the GNU General Public License
9b201bb5
NC
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. */
a85d7ed0 21
df7b86aa 22#include "sysdep.h"
a85d7ed0
NC
23#include <stdio.h>
24#include "ansidecl.h"
a85d7ed0 25#include "dis-asm.h"
112b7c50 26#include "opintl.h"
a85d7ed0
NC
27#include "opcode/s390.h"
28
29static int init_flag = 0;
30static int opc_index[256];
31static int current_arch_mask = 0;
32
44f2a95d
KH
33/* Set up index table for first opcode byte. */
34
35static void
47b0e7ad 36init_disasm (struct disassemble_info *info)
a85d7ed0 37{
9ace48f3 38 int i;
112b7c50 39 const char *p;
a85d7ed0 40
44f2a95d 41 memset (opc_index, 0, sizeof (opc_index));
9ace48f3
AA
42
43 /* Reverse order, such that each opc_index ends up pointing to the
44 first matching entry instead of the last. */
45 for (i = s390_num_opcodes; i--; )
46 opc_index[s390_opcodes[i].opcode[0]] = i;
112b7c50
AK
47
48 for (p = info->disassembler_options; p != NULL; )
44f2a95d 49 {
112b7c50
AK
50 if (CONST_STRNEQ (p, "esa"))
51 current_arch_mask = 1 << S390_OPCODE_ESA;
52 else if (CONST_STRNEQ (p, "zarch"))
53 current_arch_mask = 1 << S390_OPCODE_ZARCH;
54 else
55 fprintf (stderr, "Unknown S/390 disassembler option: %s\n", p);
56
57 p = strchr (p, ',');
58 if (p != NULL)
59 p++;
44f2a95d 60 }
112b7c50
AK
61
62 if (!current_arch_mask)
7d4a7d10 63 current_arch_mask = 1 << S390_OPCODE_ZARCH;
112b7c50 64
a85d7ed0
NC
65 init_flag = 1;
66}
67
9ace48f3
AA
68/* Derive the length of an instruction from its first byte. */
69
70static inline int
71s390_insn_length (const bfd_byte *buffer)
72{
73 /* 00xxxxxx -> 2, 01xxxxxx/10xxxxxx -> 4, 11xxxxxx -> 6. */
74 return ((buffer[0] >> 6) + 3) & ~1U;
75}
76
77/* Match the instruction in BUFFER against the given OPCODE, excluding
78 the first byte. */
79
80static inline int
81s390_insn_matches_opcode (const bfd_byte *buffer,
82 const struct s390_opcode *opcode)
83{
84 return (buffer[1] & opcode->mask[1]) == opcode->opcode[1]
85 && (buffer[2] & opcode->mask[2]) == opcode->opcode[2]
86 && (buffer[3] & opcode->mask[3]) == opcode->opcode[3]
87 && (buffer[4] & opcode->mask[4]) == opcode->opcode[4]
88 && (buffer[5] & opcode->mask[5]) == opcode->opcode[5];
89}
90
91union operand_value
92{
93 int i;
94 unsigned int u;
95};
96
a85d7ed0 97/* Extracts an operand value from an instruction. */
7330f9c3
AK
98/* We do not perform the shift operation for larl-type address
99 operands here since that would lead to an overflow of the 32 bit
100 integer value. Instead the shift operation is done when printing
9ace48f3 101 the operand. */
a85d7ed0 102
9ace48f3
AA
103static inline union operand_value
104s390_extract_operand (const bfd_byte *insn,
105 const struct s390_operand *operand)
a85d7ed0 106{
9ace48f3 107 union operand_value ret;
a85d7ed0
NC
108 unsigned int val;
109 int bits;
110
44f2a95d
KH
111 /* Extract fragments of the operand byte for byte. */
112 insn += operand->shift / 8;
a85d7ed0
NC
113 bits = (operand->shift & 7) + operand->bits;
114 val = 0;
44f2a95d
KH
115 do
116 {
117 val <<= 8;
118 val |= (unsigned int) *insn++;
119 bits -= 8;
120 }
121 while (bits > 0);
a85d7ed0 122 val >>= -bits;
44f2a95d
KH
123 val &= ((1U << (operand->bits - 1)) << 1) - 1;
124
bac02689
MS
125 /* Check for special long displacement case. */
126 if (operand->bits == 20 && operand->shift == 20)
127 val = (val & 0xff) << 12 | (val & 0xfff00) >> 8;
128
9ace48f3
AA
129 /* Sign extend value if the operand is signed or pc relative. Avoid
130 integer overflows. */
131 if (operand->flags & (S390_OPERAND_SIGNED | S390_OPERAND_PCREL))
132 {
133 unsigned int m = 1U << (operand->bits - 1);
134
135 if (val >= m)
136 ret.i = (int) (val - m) - 1 - (int) (m - 1U);
137 else
138 ret.i = (int) val;
139 }
140 else if (operand->flags & S390_OPERAND_LENGTH)
141 /* Length x in an instruction has real length x + 1. */
142 ret.u = val + 1;
143 else
144 ret.u = val;
145
146 return ret;
147}
148
149/* Print the S390 instruction in BUFFER, assuming that it matches the
150 given OPCODE. */
151
152static void
153s390_print_insn_with_opcode (bfd_vma memaddr,
154 struct disassemble_info *info,
155 const bfd_byte *buffer,
156 const struct s390_opcode *opcode)
157{
158 const unsigned char *opindex;
159 char separator;
160
161 /* Mnemonic. */
162 info->fprintf_func (info->stream, "%s", opcode->name);
163
164 /* Operands. */
165 separator = '\t';
166 for (opindex = opcode->operands; *opindex != 0; opindex++)
167 {
168 const struct s390_operand *operand = s390_operands + *opindex;
169 union operand_value val = s390_extract_operand (buffer, operand);
170 unsigned long flags = operand->flags;
171
172 if ((flags & S390_OPERAND_INDEX) && val.u == 0)
173 continue;
174 if ((flags & S390_OPERAND_BASE) &&
175 val.u == 0 && separator == '(')
176 {
177 separator = ',';
178 continue;
179 }
180
181 info->fprintf_func (info->stream, "%c", separator);
182
183 if (flags & S390_OPERAND_GPR)
184 info->fprintf_func (info->stream, "%%r%u", val.u);
185 else if (flags & S390_OPERAND_FPR)
186 info->fprintf_func (info->stream, "%%f%u", val.u);
187 else if (flags & S390_OPERAND_AR)
188 info->fprintf_func (info->stream, "%%a%u", val.u);
189 else if (flags & S390_OPERAND_CR)
190 info->fprintf_func (info->stream, "%%c%u", val.u);
191 else if (flags & S390_OPERAND_PCREL)
192 info->print_address_func (memaddr + val.i + val.i, info);
193 else if (flags & S390_OPERAND_SIGNED)
194 info->fprintf_func (info->stream, "%i", val.i);
195 else
196 info->fprintf_func (info->stream, "%u", val.u);
197
198 if (flags & S390_OPERAND_DISP)
199 separator = '(';
200 else if (flags & S390_OPERAND_BASE)
201 {
202 info->fprintf_func (info->stream, ")");
203 separator = ',';
204 }
205 else
206 separator = ',';
207 }
208}
209
210/* Check whether opcode A's mask is more specific than that of B. */
44f2a95d 211
9ace48f3
AA
212static int
213opcode_mask_more_specific (const struct s390_opcode *a,
214 const struct s390_opcode *b)
215{
216 return (((int) a->mask[0] + a->mask[1] + a->mask[2]
217 + a->mask[3] + a->mask[4] + a->mask[5])
218 > ((int) b->mask[0] + b->mask[1] + b->mask[2]
219 + b->mask[3] + b->mask[4] + b->mask[5]));
a85d7ed0
NC
220}
221
222/* Print a S390 instruction. */
223
224int
47b0e7ad 225print_insn_s390 (bfd_vma memaddr, struct disassemble_info *info)
a85d7ed0
NC
226{
227 bfd_byte buffer[6];
9ace48f3 228 const struct s390_opcode *opcode = NULL;
a85d7ed0
NC
229 unsigned int value;
230 int status, opsize, bufsize;
a85d7ed0
NC
231
232 if (init_flag == 0)
44f2a95d 233 init_disasm (info);
a85d7ed0
NC
234
235 /* The output looks better if we put 6 bytes on a line. */
236 info->bytes_per_line = 6;
237
238 /* Every S390 instruction is max 6 bytes long. */
44f2a95d 239 memset (buffer, 0, 6);
9ace48f3 240 status = info->read_memory_func (memaddr, buffer, 6, info);
44f2a95d
KH
241 if (status != 0)
242 {
243 for (bufsize = 0; bufsize < 6; bufsize++)
9ace48f3 244 if (info->read_memory_func (memaddr, buffer, bufsize + 1, info) != 0)
44f2a95d
KH
245 break;
246 if (bufsize <= 0)
247 {
9ace48f3 248 info->memory_error_func (status, memaddr, info);
44f2a95d
KH
249 return -1;
250 }
9ace48f3 251 opsize = s390_insn_length (buffer);
44f2a95d
KH
252 status = opsize > bufsize;
253 }
254 else
255 {
256 bufsize = 6;
9ace48f3 257 opsize = s390_insn_length (buffer);
44f2a95d
KH
258 }
259
260 if (status == 0)
261 {
02cbf767
AK
262 const struct s390_opcode *op;
263
9ace48f3
AA
264 /* Find the "best match" in the opcode table. */
265 for (op = s390_opcodes + opc_index[buffer[0]];
266 op != s390_opcodes + s390_num_opcodes
267 && op->opcode[0] == buffer[0];
268 op++)
44f2a95d 269 {
9ace48f3
AA
270 if ((op->modes & current_arch_mask)
271 && s390_insn_matches_opcode (buffer, op)
272 && (opcode == NULL
273 || opcode_mask_more_specific (op, opcode)))
274 opcode = op;
44f2a95d 275 }
44f2a95d
KH
276 }
277
9ace48f3
AA
278 if (opcode != NULL)
279 {
280 /* The instruction is valid. Print it and return its size. */
281 s390_print_insn_with_opcode (memaddr, info, buffer, opcode);
282 return opsize;
283 }
284
285 /* Fall back to hex print. */
44f2a95d
KH
286 if (bufsize >= 4)
287 {
288 value = (unsigned int) buffer[0];
289 value = (value << 8) + (unsigned int) buffer[1];
290 value = (value << 8) + (unsigned int) buffer[2];
291 value = (value << 8) + (unsigned int) buffer[3];
9ace48f3 292 info->fprintf_func (info->stream, ".long\t0x%08x", value);
44f2a95d
KH
293 return 4;
294 }
295 else if (bufsize >= 2)
296 {
297 value = (unsigned int) buffer[0];
298 value = (value << 8) + (unsigned int) buffer[1];
9ace48f3 299 info->fprintf_func (info->stream, ".short\t0x%04x", value);
44f2a95d 300 return 2;
a85d7ed0 301 }
44f2a95d
KH
302 else
303 {
304 value = (unsigned int) buffer[0];
9ace48f3 305 info->fprintf_func (info->stream, ".byte\t0x%02x", value);
44f2a95d 306 return 1;
a85d7ed0 307 }
a85d7ed0 308}
112b7c50
AK
309
310void
311print_s390_disassembler_options (FILE *stream)
312{
313 fprintf (stream, _("\n\
314The following S/390 specific disassembler options are supported for use\n\
315with the -M switch (multiple options should be separated by commas):\n"));
316
317 fprintf (stream, _(" esa Disassemble in ESA architecture mode\n"));
318 fprintf (stream, _(" zarch Disassemble in z/Architecture mode\n"));
319}
This page took 0.610763 seconds and 4 git commands to generate.