1 /* s390-dis.c -- Disassemble S390 instructions
2 Copyright (C) 2000-2014 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. */
27 #include "opcode/s390.h"
29 static int init_flag = 0;
30 static int opc_index[256];
31 static int current_arch_mask = 0;
33 /* Set up index table for first opcode byte. */
36 init_disasm (struct disassemble_info *info)
41 memset (opc_index, 0, sizeof (opc_index));
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;
48 for (p = info->disassembler_options; p != NULL; )
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;
55 fprintf (stderr, "Unknown S/390 disassembler option: %s\n", p);
62 if (!current_arch_mask)
63 current_arch_mask = 1 << S390_OPCODE_ZARCH;
68 /* Derive the length of an instruction from its first byte. */
71 s390_insn_length (const bfd_byte *buffer)
73 /* 00xxxxxx -> 2, 01xxxxxx/10xxxxxx -> 4, 11xxxxxx -> 6. */
74 return ((buffer[0] >> 6) + 3) & ~1U;
77 /* Match the instruction in BUFFER against the given OPCODE, excluding
81 s390_insn_matches_opcode (const bfd_byte *buffer,
82 const struct s390_opcode *opcode)
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];
97 /* Extracts an operand value from an instruction. */
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
103 static inline union operand_value
104 s390_extract_operand (const bfd_byte *insn,
105 const struct s390_operand *operand)
107 union operand_value ret;
111 /* Extract fragments of the operand byte for byte. */
112 insn += operand->shift / 8;
113 bits = (operand->shift & 7) + operand->bits;
118 val |= (unsigned int) *insn++;
123 val &= ((1U << (operand->bits - 1)) << 1) - 1;
125 /* Check for special long displacement case. */
126 if (operand->bits == 20 && operand->shift == 20)
127 val = (val & 0xff) << 12 | (val & 0xfff00) >> 8;
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))
133 unsigned int m = 1U << (operand->bits - 1);
136 ret.i = (int) (val - m) - 1 - (int) (m - 1U);
140 else if (operand->flags & S390_OPERAND_LENGTH)
141 /* Length x in an instruction has real length x + 1. */
149 /* Print the S390 instruction in BUFFER, assuming that it matches the
153 s390_print_insn_with_opcode (bfd_vma memaddr,
154 struct disassemble_info *info,
155 const bfd_byte *buffer,
156 const struct s390_opcode *opcode)
158 const unsigned char *opindex;
162 info->fprintf_func (info->stream, "%s", opcode->name);
166 for (opindex = opcode->operands; *opindex != 0; opindex++)
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;
172 if ((flags & S390_OPERAND_INDEX) && val.u == 0)
174 if ((flags & S390_OPERAND_BASE) &&
175 val.u == 0 && separator == '(')
181 info->fprintf_func (info->stream, "%c", separator);
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);
196 info->fprintf_func (info->stream, "%u", val.u);
198 if (flags & S390_OPERAND_DISP)
200 else if (flags & S390_OPERAND_BASE)
202 info->fprintf_func (info->stream, ")");
210 /* Check whether opcode A's mask is more specific than that of B. */
213 opcode_mask_more_specific (const struct s390_opcode *a,
214 const struct s390_opcode *b)
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]));
222 /* Print a S390 instruction. */
225 print_insn_s390 (bfd_vma memaddr, struct disassemble_info *info)
228 const struct s390_opcode *opcode = NULL;
230 int status, opsize, bufsize;
235 /* The output looks better if we put 6 bytes on a line. */
236 info->bytes_per_line = 6;
238 /* Every S390 instruction is max 6 bytes long. */
239 memset (buffer, 0, 6);
240 status = info->read_memory_func (memaddr, buffer, 6, info);
243 for (bufsize = 0; bufsize < 6; bufsize++)
244 if (info->read_memory_func (memaddr, buffer, bufsize + 1, info) != 0)
248 info->memory_error_func (status, memaddr, info);
251 opsize = s390_insn_length (buffer);
252 status = opsize > bufsize;
257 opsize = s390_insn_length (buffer);
262 const struct s390_opcode *op;
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];
270 if ((op->modes & current_arch_mask)
271 && s390_insn_matches_opcode (buffer, op)
273 || opcode_mask_more_specific (op, opcode)))
280 /* The instruction is valid. Print it and return its size. */
281 s390_print_insn_with_opcode (memaddr, info, buffer, opcode);
285 /* Fall back to hex print. */
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];
292 info->fprintf_func (info->stream, ".long\t0x%08x", value);
295 else if (bufsize >= 2)
297 value = (unsigned int) buffer[0];
298 value = (value << 8) + (unsigned int) buffer[1];
299 info->fprintf_func (info->stream, ".short\t0x%04x", value);
304 value = (unsigned int) buffer[0];
305 info->fprintf_func (info->stream, ".byte\t0x%02x", value);
311 print_s390_disassembler_options (FILE *stream)
313 fprintf (stream, _("\n\
314 The following S/390 specific disassembler options are supported for use\n\
315 with the -M switch (multiple options should be separated by commas):\n"));
317 fprintf (stream, _(" esa Disassemble in ESA architecture mode\n"));
318 fprintf (stream, _(" zarch Disassemble in z/Architecture mode\n"));