Automatic date update in version.in
[deliverable/binutils-gdb.git] / opcodes / s390-dis.c
CommitLineData
a85d7ed0 1/* s390-dis.c -- Disassemble S390 instructions
219d1afa 2 Copyright (C) 2000-2018 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"
88c1242d 25#include "disassemble.h"
112b7c50 26#include "opintl.h"
a85d7ed0 27#include "opcode/s390.h"
65b48a81 28#include "libiberty.h"
a85d7ed0 29
a85d7ed0
NC
30static int opc_index[256];
31static int current_arch_mask = 0;
b2cc3f6f 32static int option_use_insn_len_bits_p = 0;
a85d7ed0 33
65b48a81
PB
34typedef struct
35{
36 const char *name;
37 const char *description;
38} s390_options_t;
39
40static const s390_options_t options[] =
41{
42 { "esa" , N_("Disassemble in ESA architecture mode") },
43 { "zarch", N_("Disassemble in z/Architecture mode") },
44 { "insnlength", N_("Print unknown instructions according to "
45 "length from first two bits") }
46};
47
44f2a95d
KH
48/* Set up index table for first opcode byte. */
49
65b48a81
PB
50void
51disassemble_init_s390 (struct disassemble_info *info)
a85d7ed0 52{
9ace48f3 53 int i;
112b7c50 54 const char *p;
a85d7ed0 55
44f2a95d 56 memset (opc_index, 0, sizeof (opc_index));
9ace48f3
AA
57
58 /* Reverse order, such that each opc_index ends up pointing to the
59 first matching entry instead of the last. */
60 for (i = s390_num_opcodes; i--; )
61 opc_index[s390_opcodes[i].opcode[0]] = i;
112b7c50 62
65b48a81
PB
63 current_arch_mask = 1 << S390_OPCODE_ZARCH;
64 option_use_insn_len_bits_p = 0;
65
112b7c50 66 for (p = info->disassembler_options; p != NULL; )
44f2a95d 67 {
112b7c50
AK
68 if (CONST_STRNEQ (p, "esa"))
69 current_arch_mask = 1 << S390_OPCODE_ESA;
70 else if (CONST_STRNEQ (p, "zarch"))
71 current_arch_mask = 1 << S390_OPCODE_ZARCH;
b2cc3f6f
AK
72 else if (CONST_STRNEQ (p, "insnlength"))
73 option_use_insn_len_bits_p = 1;
112b7c50
AK
74 else
75 fprintf (stderr, "Unknown S/390 disassembler option: %s\n", p);
76
77 p = strchr (p, ',');
78 if (p != NULL)
79 p++;
44f2a95d 80 }
a85d7ed0
NC
81}
82
9ace48f3
AA
83/* Derive the length of an instruction from its first byte. */
84
85static inline int
86s390_insn_length (const bfd_byte *buffer)
87{
88 /* 00xxxxxx -> 2, 01xxxxxx/10xxxxxx -> 4, 11xxxxxx -> 6. */
89 return ((buffer[0] >> 6) + 3) & ~1U;
90}
91
92/* Match the instruction in BUFFER against the given OPCODE, excluding
93 the first byte. */
94
95static inline int
96s390_insn_matches_opcode (const bfd_byte *buffer,
97 const struct s390_opcode *opcode)
98{
99 return (buffer[1] & opcode->mask[1]) == opcode->opcode[1]
100 && (buffer[2] & opcode->mask[2]) == opcode->opcode[2]
101 && (buffer[3] & opcode->mask[3]) == opcode->opcode[3]
102 && (buffer[4] & opcode->mask[4]) == opcode->opcode[4]
103 && (buffer[5] & opcode->mask[5]) == opcode->opcode[5];
104}
105
106union operand_value
107{
108 int i;
109 unsigned int u;
110};
111
a85d7ed0 112/* Extracts an operand value from an instruction. */
7330f9c3
AK
113/* We do not perform the shift operation for larl-type address
114 operands here since that would lead to an overflow of the 32 bit
115 integer value. Instead the shift operation is done when printing
9ace48f3 116 the operand. */
a85d7ed0 117
9ace48f3
AA
118static inline union operand_value
119s390_extract_operand (const bfd_byte *insn,
120 const struct s390_operand *operand)
a85d7ed0 121{
9ace48f3 122 union operand_value ret;
a85d7ed0
NC
123 unsigned int val;
124 int bits;
1e2e8c52 125 const bfd_byte *orig_insn = insn;
a85d7ed0 126
44f2a95d
KH
127 /* Extract fragments of the operand byte for byte. */
128 insn += operand->shift / 8;
a85d7ed0
NC
129 bits = (operand->shift & 7) + operand->bits;
130 val = 0;
44f2a95d
KH
131 do
132 {
133 val <<= 8;
134 val |= (unsigned int) *insn++;
135 bits -= 8;
136 }
137 while (bits > 0);
a85d7ed0 138 val >>= -bits;
44f2a95d
KH
139 val &= ((1U << (operand->bits - 1)) << 1) - 1;
140
bac02689
MS
141 /* Check for special long displacement case. */
142 if (operand->bits == 20 && operand->shift == 20)
143 val = (val & 0xff) << 12 | (val & 0xfff00) >> 8;
144
9ace48f3
AA
145 /* Sign extend value if the operand is signed or pc relative. Avoid
146 integer overflows. */
147 if (operand->flags & (S390_OPERAND_SIGNED | S390_OPERAND_PCREL))
148 {
149 unsigned int m = 1U << (operand->bits - 1);
150
151 if (val >= m)
152 ret.i = (int) (val - m) - 1 - (int) (m - 1U);
153 else
154 ret.i = (int) val;
155 }
156 else if (operand->flags & S390_OPERAND_LENGTH)
157 /* Length x in an instruction has real length x + 1. */
158 ret.u = val + 1;
1e2e8c52
AK
159
160 else if (operand->flags & S390_OPERAND_VR)
161 {
162 /* Extract the extra bits for a vector register operand stored
163 in the RXB field. */
164 unsigned vr = operand->shift == 32 ? 3
165 : (unsigned) operand->shift / 4 - 2;
166
167 ret.u = val | ((orig_insn[4] & (1 << (3 - vr))) << (vr + 1));
168 }
9ace48f3
AA
169 else
170 ret.u = val;
171
172 return ret;
173}
174
175/* Print the S390 instruction in BUFFER, assuming that it matches the
176 given OPCODE. */
177
178static void
179s390_print_insn_with_opcode (bfd_vma memaddr,
180 struct disassemble_info *info,
181 const bfd_byte *buffer,
182 const struct s390_opcode *opcode)
183{
184 const unsigned char *opindex;
185 char separator;
186
187 /* Mnemonic. */
188 info->fprintf_func (info->stream, "%s", opcode->name);
189
190 /* Operands. */
191 separator = '\t';
192 for (opindex = opcode->operands; *opindex != 0; opindex++)
193 {
194 const struct s390_operand *operand = s390_operands + *opindex;
195 union operand_value val = s390_extract_operand (buffer, operand);
196 unsigned long flags = operand->flags;
197
198 if ((flags & S390_OPERAND_INDEX) && val.u == 0)
199 continue;
200 if ((flags & S390_OPERAND_BASE) &&
201 val.u == 0 && separator == '(')
202 {
203 separator = ',';
204 continue;
205 }
206
1e2e8c52
AK
207 /* For instructions with a last optional operand don't print it
208 if zero. */
a09f2586 209 if ((opcode->flags & (S390_INSTR_FLAG_OPTPARM | S390_INSTR_FLAG_OPTPARM2))
1e2e8c52
AK
210 && val.u == 0
211 && opindex[1] == 0)
212 break;
9ace48f3 213
a09f2586
AK
214 if ((opcode->flags & S390_INSTR_FLAG_OPTPARM2)
215 && val.u == 0 && opindex[1] != 0 && opindex[2] == 0)
216 {
217 union operand_value next_op_val =
218 s390_extract_operand (buffer, s390_operands + opindex[1]);
219 if (next_op_val.u == 0)
220 break;
221 }
222
9ace48f3 223 if (flags & S390_OPERAND_GPR)
1e2e8c52 224 info->fprintf_func (info->stream, "%c%%r%u", separator, val.u);
9ace48f3 225 else if (flags & S390_OPERAND_FPR)
1e2e8c52
AK
226 info->fprintf_func (info->stream, "%c%%f%u", separator, val.u);
227 else if (flags & S390_OPERAND_VR)
228 info->fprintf_func (info->stream, "%c%%v%i", separator, val.u);
9ace48f3 229 else if (flags & S390_OPERAND_AR)
1e2e8c52 230 info->fprintf_func (info->stream, "%c%%a%u", separator, val.u);
9ace48f3 231 else if (flags & S390_OPERAND_CR)
1e2e8c52 232 info->fprintf_func (info->stream, "%c%%c%u", separator, val.u);
9ace48f3 233 else if (flags & S390_OPERAND_PCREL)
1e2e8c52
AK
234 {
235 info->fprintf_func (info->stream, "%c", separator);
236 info->print_address_func (memaddr + val.i + val.i, info);
237 }
9ace48f3 238 else if (flags & S390_OPERAND_SIGNED)
1e2e8c52 239 info->fprintf_func (info->stream, "%c%i", separator, val.i);
9ace48f3 240 else
1e2e8c52
AK
241 {
242 if (flags & S390_OPERAND_OR1)
243 val.u &= ~1;
244 if (flags & S390_OPERAND_OR2)
245 val.u &= ~2;
246 if (flags & S390_OPERAND_OR8)
247 val.u &= ~8;
248
249 if ((opcode->flags & S390_INSTR_FLAG_OPTPARM)
250 && val.u == 0
251 && opindex[1] == 0)
252 break;
253 info->fprintf_func (info->stream, "%c%u", separator, val.u);
254 }
9ace48f3
AA
255
256 if (flags & S390_OPERAND_DISP)
257 separator = '(';
258 else if (flags & S390_OPERAND_BASE)
259 {
260 info->fprintf_func (info->stream, ")");
261 separator = ',';
262 }
263 else
264 separator = ',';
265 }
266}
267
268/* Check whether opcode A's mask is more specific than that of B. */
44f2a95d 269
9ace48f3
AA
270static int
271opcode_mask_more_specific (const struct s390_opcode *a,
272 const struct s390_opcode *b)
273{
274 return (((int) a->mask[0] + a->mask[1] + a->mask[2]
275 + a->mask[3] + a->mask[4] + a->mask[5])
276 > ((int) b->mask[0] + b->mask[1] + b->mask[2]
277 + b->mask[3] + b->mask[4] + b->mask[5]));
a85d7ed0
NC
278}
279
280/* Print a S390 instruction. */
281
282int
47b0e7ad 283print_insn_s390 (bfd_vma memaddr, struct disassemble_info *info)
a85d7ed0
NC
284{
285 bfd_byte buffer[6];
9ace48f3 286 const struct s390_opcode *opcode = NULL;
a85d7ed0 287 unsigned int value;
b2cc3f6f 288 int status, opsize, bufsize, bytes_to_dump, i;
a85d7ed0 289
a85d7ed0
NC
290 /* The output looks better if we put 6 bytes on a line. */
291 info->bytes_per_line = 6;
292
293 /* Every S390 instruction is max 6 bytes long. */
44f2a95d 294 memset (buffer, 0, 6);
9ace48f3 295 status = info->read_memory_func (memaddr, buffer, 6, info);
44f2a95d
KH
296 if (status != 0)
297 {
298 for (bufsize = 0; bufsize < 6; bufsize++)
9ace48f3 299 if (info->read_memory_func (memaddr, buffer, bufsize + 1, info) != 0)
44f2a95d
KH
300 break;
301 if (bufsize <= 0)
302 {
9ace48f3 303 info->memory_error_func (status, memaddr, info);
44f2a95d
KH
304 return -1;
305 }
9ace48f3 306 opsize = s390_insn_length (buffer);
44f2a95d
KH
307 status = opsize > bufsize;
308 }
309 else
310 {
311 bufsize = 6;
9ace48f3 312 opsize = s390_insn_length (buffer);
44f2a95d
KH
313 }
314
315 if (status == 0)
316 {
02cbf767
AK
317 const struct s390_opcode *op;
318
9ace48f3
AA
319 /* Find the "best match" in the opcode table. */
320 for (op = s390_opcodes + opc_index[buffer[0]];
321 op != s390_opcodes + s390_num_opcodes
322 && op->opcode[0] == buffer[0];
323 op++)
44f2a95d 324 {
9ace48f3
AA
325 if ((op->modes & current_arch_mask)
326 && s390_insn_matches_opcode (buffer, op)
327 && (opcode == NULL
328 || opcode_mask_more_specific (op, opcode)))
329 opcode = op;
44f2a95d 330 }
44f2a95d 331
b2cc3f6f
AK
332 if (opcode != NULL)
333 {
334 /* The instruction is valid. Print it and return its size. */
335 s390_print_insn_with_opcode (memaddr, info, buffer, opcode);
336 return opsize;
337 }
9ace48f3
AA
338 }
339
b2cc3f6f
AK
340 /* For code sections it makes sense to skip unknown instructions
341 according to their length bits. */
342 if (status == 0
343 && option_use_insn_len_bits_p
344 && info->section != NULL
345 && (info->section->flags & SEC_CODE))
346 bytes_to_dump = opsize;
347 else
348 /* By default unknown instructions are printed as .long's/.short'
349 depending on how many bytes are available. */
350 bytes_to_dump = bufsize >= 4 ? 4 : bufsize;
351
352 if (bytes_to_dump == 0)
353 return 0;
354
9ace48f3 355 /* Fall back to hex print. */
b2cc3f6f 356 switch (bytes_to_dump)
44f2a95d 357 {
b2cc3f6f 358 case 4:
44f2a95d
KH
359 value = (unsigned int) buffer[0];
360 value = (value << 8) + (unsigned int) buffer[1];
361 value = (value << 8) + (unsigned int) buffer[2];
362 value = (value << 8) + (unsigned int) buffer[3];
9ace48f3 363 info->fprintf_func (info->stream, ".long\t0x%08x", value);
44f2a95d 364 return 4;
b2cc3f6f 365 case 2:
44f2a95d
KH
366 value = (unsigned int) buffer[0];
367 value = (value << 8) + (unsigned int) buffer[1];
9ace48f3 368 info->fprintf_func (info->stream, ".short\t0x%04x", value);
44f2a95d 369 return 2;
b2cc3f6f
AK
370 default:
371 info->fprintf_func (info->stream, ".byte\t0x%02x",
372 (unsigned int) buffer[0]);
373 for (i = 1; i < bytes_to_dump; i++)
374 info->fprintf_func (info->stream, ",0x%02x",
375 (unsigned int) buffer[i]);
376 return bytes_to_dump;
a85d7ed0 377 }
b2cc3f6f 378 return 0;
a85d7ed0 379}
112b7c50 380
65b48a81
PB
381const disasm_options_t *
382disassembler_options_s390 (void)
383{
384 static disasm_options_t *opts = NULL;
385
386 if (opts == NULL)
387 {
388 size_t i, num_options = ARRAY_SIZE (options);
389 opts = XNEW (disasm_options_t);
390 opts->name = XNEWVEC (const char *, num_options + 1);
391 opts->description = XNEWVEC (const char *, num_options + 1);
392 for (i = 0; i < num_options; i++)
393 {
394 opts->name[i] = options[i].name;
395 opts->description[i] = _(options[i].description);
396 }
397 /* The array we return must be NULL terminated. */
398 opts->name[i] = NULL;
399 opts->description[i] = NULL;
400 }
401
402 return opts;
403}
404
112b7c50
AK
405void
406print_s390_disassembler_options (FILE *stream)
407{
65b48a81 408 unsigned int i, max_len = 0;
112b7c50
AK
409 fprintf (stream, _("\n\
410The following S/390 specific disassembler options are supported for use\n\
411with the -M switch (multiple options should be separated by commas):\n"));
412
65b48a81
PB
413 for (i = 0; i < ARRAY_SIZE (options); i++)
414 {
415 unsigned int len = strlen (options[i].name);
416 if (max_len < len)
417 max_len = len;
418 }
419
420 for (i = 0, max_len++; i < ARRAY_SIZE (options); i++)
421 fprintf (stream, " %s%*c %s\n",
422 options[i].name,
423 (int)(max_len - strlen (options[i].name)), ' ',
424 _(options[i].description));
112b7c50 425}
This page took 0.749969 seconds and 4 git commands to generate.