1 /* s390-dis.c -- Disassemble S390 instructions
2 Copyright 2000, 2001, 2002, 2003, 2005, 2007, 2008
3 Free Software Foundation, Inc.
4 Contributed by Martin Schwidefsky (schwidefsky@de.ibm.com).
6 This file is part of the GNU opcodes library.
8 This library is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 3, or (at your option)
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.
18 You should have received a copy of the GNU General Public License
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. */
28 #include "opcode/s390.h"
30 static int init_flag = 0;
31 static int opc_index[256];
32 static int current_arch_mask = 0;
34 /* Set up index table for first opcode byte. */
37 init_disasm (struct disassemble_info *info)
39 const struct s390_opcode *opcode;
40 const struct s390_opcode *opcode_end;
43 memset (opc_index, 0, sizeof (opc_index));
44 opcode_end = s390_opcodes + s390_num_opcodes;
45 for (opcode = s390_opcodes; opcode < opcode_end; opcode++)
47 opc_index[(int) opcode->opcode[0]] = opcode - s390_opcodes;
48 while ((opcode < opcode_end) &&
49 (opcode[1].opcode[0] == opcode->opcode[0]))
53 for (p = info->disassembler_options; p != NULL; )
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;
60 fprintf (stderr, "Unknown S/390 disassembler option: %s\n", p);
67 if (!current_arch_mask)
70 case bfd_mach_s390_31:
71 current_arch_mask = 1 << S390_OPCODE_ESA;
73 case bfd_mach_s390_64:
74 current_arch_mask = 1 << S390_OPCODE_ZARCH;
83 /* Extracts an operand value from an instruction. */
84 /* We do not perform the shift operation for larl-type address
85 operands here since that would lead to an overflow of the 32 bit
86 integer value. Instead the shift operation is done when printing
87 the operand in print_insn_s390. */
89 static inline unsigned int
90 s390_extract_operand (unsigned char *insn, const struct s390_operand *operand)
95 /* Extract fragments of the operand byte for byte. */
96 insn += operand->shift / 8;
97 bits = (operand->shift & 7) + operand->bits;
102 val |= (unsigned int) *insn++;
107 val &= ((1U << (operand->bits - 1)) << 1) - 1;
109 /* Check for special long displacement case. */
110 if (operand->bits == 20 && operand->shift == 20)
111 val = (val & 0xff) << 12 | (val & 0xfff00) >> 8;
113 /* Sign extend value if the operand is signed or pc relative. */
114 if ((operand->flags & (S390_OPERAND_SIGNED | S390_OPERAND_PCREL))
115 && (val & (1U << (operand->bits - 1))))
116 val |= (-1U << (operand->bits - 1)) << 1;
118 /* Length x in an instructions has real length x + 1. */
119 if (operand->flags & S390_OPERAND_LENGTH)
124 /* Print a S390 instruction. */
127 print_insn_s390 (bfd_vma memaddr, struct disassemble_info *info)
130 const struct s390_opcode *opcode;
131 const struct s390_opcode *opcode_end;
133 int status, opsize, bufsize;
139 /* The output looks better if we put 6 bytes on a line. */
140 info->bytes_per_line = 6;
142 /* Every S390 instruction is max 6 bytes long. */
143 memset (buffer, 0, 6);
144 status = (*info->read_memory_func) (memaddr, buffer, 6, info);
147 for (bufsize = 0; bufsize < 6; bufsize++)
148 if ((*info->read_memory_func) (memaddr, buffer, bufsize + 1, info) != 0)
152 (*info->memory_error_func) (status, memaddr, info);
155 /* Opsize calculation looks strange but it works
156 00xxxxxx -> 2 bytes, 01xxxxxx/10xxxxxx -> 4 bytes,
157 11xxxxxx -> 6 bytes. */
158 opsize = ((((buffer[0] >> 6) + 1) >> 1) + 1) << 1;
159 status = opsize > bufsize;
164 opsize = ((((buffer[0] >> 6) + 1) >> 1) + 1) << 1;
169 const struct s390_opcode *op;
171 /* Find the first match in the opcode table. */
172 opcode_end = s390_opcodes + s390_num_opcodes;
173 for (opcode = s390_opcodes + opc_index[(int) buffer[0]];
174 (opcode < opcode_end) && (buffer[0] == opcode->opcode[0]);
177 const struct s390_operand *operand;
178 const unsigned char *opindex;
180 /* Check architecture. */
181 if (!(opcode->modes & current_arch_mask))
184 /* Check signature of the opcode. */
185 if ((buffer[1] & opcode->mask[1]) != opcode->opcode[1]
186 || (buffer[2] & opcode->mask[2]) != opcode->opcode[2]
187 || (buffer[3] & opcode->mask[3]) != opcode->opcode[3]
188 || (buffer[4] & opcode->mask[4]) != opcode->opcode[4]
189 || (buffer[5] & opcode->mask[5]) != opcode->opcode[5])
192 /* Advance to an opcode with a more specific mask. */
193 for (op = opcode + 1; op < opcode_end; op++)
195 if ((buffer[0] & op->mask[0]) != op->opcode[0])
198 if ((buffer[1] & op->mask[1]) != op->opcode[1]
199 || (buffer[2] & op->mask[2]) != op->opcode[2]
200 || (buffer[3] & op->mask[3]) != op->opcode[3]
201 || (buffer[4] & op->mask[4]) != op->opcode[4]
202 || (buffer[5] & op->mask[5]) != op->opcode[5])
205 if (((int)opcode->mask[0] + opcode->mask[1] +
206 opcode->mask[2] + opcode->mask[3] +
207 opcode->mask[4] + opcode->mask[5]) <
208 ((int)op->mask[0] + op->mask[1] +
209 op->mask[2] + op->mask[3] +
210 op->mask[4] + op->mask[5]))
214 /* The instruction is valid. */
215 if (opcode->operands[0] != 0)
216 (*info->fprintf_func) (info->stream, "%s\t", opcode->name);
218 (*info->fprintf_func) (info->stream, "%s", opcode->name);
220 /* Extract the operands. */
222 for (opindex = opcode->operands; *opindex != 0; opindex++)
224 operand = s390_operands + *opindex;
225 value = s390_extract_operand (buffer, operand);
227 if ((operand->flags & S390_OPERAND_INDEX) && value == 0)
229 if ((operand->flags & S390_OPERAND_BASE) &&
230 value == 0 && separator == '(')
237 (*info->fprintf_func) (info->stream, "%c", separator);
239 if (operand->flags & S390_OPERAND_GPR)
240 (*info->fprintf_func) (info->stream, "%%r%i", value);
241 else if (operand->flags & S390_OPERAND_FPR)
242 (*info->fprintf_func) (info->stream, "%%f%i", value);
243 else if (operand->flags & S390_OPERAND_AR)
244 (*info->fprintf_func) (info->stream, "%%a%i", value);
245 else if (operand->flags & S390_OPERAND_CR)
246 (*info->fprintf_func) (info->stream, "%%c%i", value);
247 else if (operand->flags & S390_OPERAND_PCREL)
248 (*info->print_address_func) (memaddr + (int)value + (int)value,
250 else if (operand->flags & S390_OPERAND_SIGNED)
251 (*info->fprintf_func) (info->stream, "%i", (int) value);
253 (*info->fprintf_func) (info->stream, "%u", value);
255 if (operand->flags & S390_OPERAND_DISP)
259 else if (operand->flags & S390_OPERAND_BASE)
261 (*info->fprintf_func) (info->stream, ")");
268 /* Found instruction, printed it, return its size. */
271 /* No matching instruction found, fall through to hex print. */
276 value = (unsigned int) buffer[0];
277 value = (value << 8) + (unsigned int) buffer[1];
278 value = (value << 8) + (unsigned int) buffer[2];
279 value = (value << 8) + (unsigned int) buffer[3];
280 (*info->fprintf_func) (info->stream, ".long\t0x%08x", value);
283 else if (bufsize >= 2)
285 value = (unsigned int) buffer[0];
286 value = (value << 8) + (unsigned int) buffer[1];
287 (*info->fprintf_func) (info->stream, ".short\t0x%04x", value);
292 value = (unsigned int) buffer[0];
293 (*info->fprintf_func) (info->stream, ".byte\t0x%02x", value);
299 print_s390_disassembler_options (FILE *stream)
301 fprintf (stream, _("\n\
302 The following S/390 specific disassembler options are supported for use\n\
303 with the -M switch (multiple options should be separated by commas):\n"));
305 fprintf (stream, _(" esa Disassemble in ESA architecture mode\n"));
306 fprintf (stream, _(" zarch Disassemble in z/Architecture mode\n"));