1 /* s390-dis.c -- Disassemble S390 instructions
2 Copyright (C) 2000-2018 Free Software Foundation, Inc.
3 Contributed by Martin Schwidefsky (schwidefsky@de.ibm.com).
5 This file is part of the GNU opcodes library.
7 This library is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 3, or (at your option)
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.
17 You should have received a copy of the GNU General Public License
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. */
25 #include "disassemble.h"
27 #include "opcode/s390.h"
28 #include "libiberty.h"
30 static int opc_index[256];
31 static int current_arch_mask = 0;
32 static int option_use_insn_len_bits_p = 0;
37 const char *description;
40 static const s390_options_t options[] =
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") }
48 /* Set up index table for first opcode byte. */
51 disassemble_init_s390 (struct disassemble_info *info)
56 memset (opc_index, 0, sizeof (opc_index));
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;
63 current_arch_mask = 1 << S390_OPCODE_ZARCH;
64 option_use_insn_len_bits_p = 0;
66 for (p = info->disassembler_options; p != NULL; )
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;
72 else if (CONST_STRNEQ (p, "insnlength"))
73 option_use_insn_len_bits_p = 1;
75 fprintf (stderr, "Unknown S/390 disassembler option: %s\n", p);
83 /* Derive the length of an instruction from its first byte. */
86 s390_insn_length (const bfd_byte *buffer)
88 /* 00xxxxxx -> 2, 01xxxxxx/10xxxxxx -> 4, 11xxxxxx -> 6. */
89 return ((buffer[0] >> 6) + 3) & ~1U;
92 /* Match the instruction in BUFFER against the given OPCODE, excluding
96 s390_insn_matches_opcode (const bfd_byte *buffer,
97 const struct s390_opcode *opcode)
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];
112 /* Extracts an operand value from an instruction. */
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
118 static inline union operand_value
119 s390_extract_operand (const bfd_byte *insn,
120 const struct s390_operand *operand)
122 union operand_value ret;
125 const bfd_byte *orig_insn = insn;
127 /* Extract fragments of the operand byte for byte. */
128 insn += operand->shift / 8;
129 bits = (operand->shift & 7) + operand->bits;
134 val |= (unsigned int) *insn++;
139 val &= ((1U << (operand->bits - 1)) << 1) - 1;
141 /* Check for special long displacement case. */
142 if (operand->bits == 20 && operand->shift == 20)
143 val = (val & 0xff) << 12 | (val & 0xfff00) >> 8;
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))
149 unsigned int m = 1U << (operand->bits - 1);
152 ret.i = (int) (val - m) - 1 - (int) (m - 1U);
156 else if (operand->flags & S390_OPERAND_LENGTH)
157 /* Length x in an instruction has real length x + 1. */
160 else if (operand->flags & S390_OPERAND_VR)
162 /* Extract the extra bits for a vector register operand stored
164 unsigned vr = operand->shift == 32 ? 3
165 : (unsigned) operand->shift / 4 - 2;
167 ret.u = val | ((orig_insn[4] & (1 << (3 - vr))) << (vr + 1));
175 /* Print the S390 instruction in BUFFER, assuming that it matches the
179 s390_print_insn_with_opcode (bfd_vma memaddr,
180 struct disassemble_info *info,
181 const bfd_byte *buffer,
182 const struct s390_opcode *opcode)
184 const unsigned char *opindex;
188 info->fprintf_func (info->stream, "%s", opcode->name);
192 for (opindex = opcode->operands; *opindex != 0; opindex++)
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;
198 if ((flags & S390_OPERAND_INDEX) && val.u == 0)
200 if ((flags & S390_OPERAND_BASE) &&
201 val.u == 0 && separator == '(')
207 /* For instructions with a last optional operand don't print it
209 if ((opcode->flags & (S390_INSTR_FLAG_OPTPARM | S390_INSTR_FLAG_OPTPARM2))
214 if ((opcode->flags & S390_INSTR_FLAG_OPTPARM2)
215 && val.u == 0 && opindex[1] != 0 && opindex[2] == 0)
217 union operand_value next_op_val =
218 s390_extract_operand (buffer, s390_operands + opindex[1]);
219 if (next_op_val.u == 0)
223 if (flags & S390_OPERAND_GPR)
224 info->fprintf_func (info->stream, "%c%%r%u", separator, val.u);
225 else if (flags & S390_OPERAND_FPR)
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);
229 else if (flags & S390_OPERAND_AR)
230 info->fprintf_func (info->stream, "%c%%a%u", separator, val.u);
231 else if (flags & S390_OPERAND_CR)
232 info->fprintf_func (info->stream, "%c%%c%u", separator, val.u);
233 else if (flags & S390_OPERAND_PCREL)
235 info->fprintf_func (info->stream, "%c", separator);
236 info->print_address_func (memaddr + val.i + val.i, info);
238 else if (flags & S390_OPERAND_SIGNED)
239 info->fprintf_func (info->stream, "%c%i", separator, val.i);
242 if (flags & S390_OPERAND_OR1)
244 if (flags & S390_OPERAND_OR2)
246 if (flags & S390_OPERAND_OR8)
249 if ((opcode->flags & S390_INSTR_FLAG_OPTPARM)
253 info->fprintf_func (info->stream, "%c%u", separator, val.u);
256 if (flags & S390_OPERAND_DISP)
258 else if (flags & S390_OPERAND_BASE)
260 info->fprintf_func (info->stream, ")");
268 /* Check whether opcode A's mask is more specific than that of B. */
271 opcode_mask_more_specific (const struct s390_opcode *a,
272 const struct s390_opcode *b)
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]));
280 /* Print a S390 instruction. */
283 print_insn_s390 (bfd_vma memaddr, struct disassemble_info *info)
286 const struct s390_opcode *opcode = NULL;
288 int status, opsize, bufsize, bytes_to_dump, i;
290 /* The output looks better if we put 6 bytes on a line. */
291 info->bytes_per_line = 6;
293 /* Every S390 instruction is max 6 bytes long. */
294 memset (buffer, 0, 6);
295 status = info->read_memory_func (memaddr, buffer, 6, info);
298 for (bufsize = 0; bufsize < 6; bufsize++)
299 if (info->read_memory_func (memaddr, buffer, bufsize + 1, info) != 0)
303 info->memory_error_func (status, memaddr, info);
306 opsize = s390_insn_length (buffer);
307 status = opsize > bufsize;
312 opsize = s390_insn_length (buffer);
317 const struct s390_opcode *op;
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];
325 if ((op->modes & current_arch_mask)
326 && s390_insn_matches_opcode (buffer, op)
328 || opcode_mask_more_specific (op, opcode)))
334 /* The instruction is valid. Print it and return its size. */
335 s390_print_insn_with_opcode (memaddr, info, buffer, opcode);
340 /* For code sections it makes sense to skip unknown instructions
341 according to their length bits. */
343 && option_use_insn_len_bits_p
344 && info->section != NULL
345 && (info->section->flags & SEC_CODE))
346 bytes_to_dump = opsize;
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;
352 if (bytes_to_dump == 0)
355 /* Fall back to hex print. */
356 switch (bytes_to_dump)
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];
363 info->fprintf_func (info->stream, ".long\t0x%08x", value);
366 value = (unsigned int) buffer[0];
367 value = (value << 8) + (unsigned int) buffer[1];
368 info->fprintf_func (info->stream, ".short\t0x%04x", value);
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;
381 const disasm_options_t *
382 disassembler_options_s390 (void)
384 static disasm_options_t *opts = NULL;
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++)
394 opts->name[i] = options[i].name;
395 opts->description[i] = _(options[i].description);
397 /* The array we return must be NULL terminated. */
398 opts->name[i] = NULL;
399 opts->description[i] = NULL;
406 print_s390_disassembler_options (FILE *stream)
408 unsigned int i, max_len = 0;
409 fprintf (stream, _("\n\
410 The following S/390 specific disassembler options are supported for use\n\
411 with the -M switch (multiple options should be separated by commas):\n"));
413 for (i = 0; i < ARRAY_SIZE (options); i++)
415 unsigned int len = strlen (options[i].name);
420 for (i = 0, max_len++; i < ARRAY_SIZE (options); i++)
421 fprintf (stream, " %s%*c %s\n",
423 (int)(max_len - strlen (options[i].name)), ' ',
424 _(options[i].description));