1 /* s390-dis.c -- Disassemble S390 instructions
2 Copyright (C) 2000-2016 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
;
110 const bfd_byte
*orig_insn
= insn
;
112 /* Extract fragments of the operand byte for byte. */
113 insn
+= operand
->shift
/ 8;
114 bits
= (operand
->shift
& 7) + operand
->bits
;
119 val
|= (unsigned int) *insn
++;
124 val
&= ((1U << (operand
->bits
- 1)) << 1) - 1;
126 /* Check for special long displacement case. */
127 if (operand
->bits
== 20 && operand
->shift
== 20)
128 val
= (val
& 0xff) << 12 | (val
& 0xfff00) >> 8;
130 /* Sign extend value if the operand is signed or pc relative. Avoid
131 integer overflows. */
132 if (operand
->flags
& (S390_OPERAND_SIGNED
| S390_OPERAND_PCREL
))
134 unsigned int m
= 1U << (operand
->bits
- 1);
137 ret
.i
= (int) (val
- m
) - 1 - (int) (m
- 1U);
141 else if (operand
->flags
& S390_OPERAND_LENGTH
)
142 /* Length x in an instruction has real length x + 1. */
145 else if (operand
->flags
& S390_OPERAND_VR
)
147 /* Extract the extra bits for a vector register operand stored
149 unsigned vr
= operand
->shift
== 32 ? 3
150 : (unsigned) operand
->shift
/ 4 - 2;
152 ret
.u
= val
| ((orig_insn
[4] & (1 << (3 - vr
))) << (vr
+ 1));
160 /* Print the S390 instruction in BUFFER, assuming that it matches the
164 s390_print_insn_with_opcode (bfd_vma memaddr
,
165 struct disassemble_info
*info
,
166 const bfd_byte
*buffer
,
167 const struct s390_opcode
*opcode
)
169 const unsigned char *opindex
;
173 info
->fprintf_func (info
->stream
, "%s", opcode
->name
);
177 for (opindex
= opcode
->operands
; *opindex
!= 0; opindex
++)
179 const struct s390_operand
*operand
= s390_operands
+ *opindex
;
180 union operand_value val
= s390_extract_operand (buffer
, operand
);
181 unsigned long flags
= operand
->flags
;
183 if ((flags
& S390_OPERAND_INDEX
) && val
.u
== 0)
185 if ((flags
& S390_OPERAND_BASE
) &&
186 val
.u
== 0 && separator
== '(')
192 /* For instructions with a last optional operand don't print it
194 if ((opcode
->flags
& S390_INSTR_FLAG_OPTPARM
)
199 if (flags
& S390_OPERAND_GPR
)
200 info
->fprintf_func (info
->stream
, "%c%%r%u", separator
, val
.u
);
201 else if (flags
& S390_OPERAND_FPR
)
202 info
->fprintf_func (info
->stream
, "%c%%f%u", separator
, val
.u
);
203 else if (flags
& S390_OPERAND_VR
)
204 info
->fprintf_func (info
->stream
, "%c%%v%i", separator
, val
.u
);
205 else if (flags
& S390_OPERAND_AR
)
206 info
->fprintf_func (info
->stream
, "%c%%a%u", separator
, val
.u
);
207 else if (flags
& S390_OPERAND_CR
)
208 info
->fprintf_func (info
->stream
, "%c%%c%u", separator
, val
.u
);
209 else if (flags
& S390_OPERAND_PCREL
)
211 info
->fprintf_func (info
->stream
, "%c", separator
);
212 info
->print_address_func (memaddr
+ val
.i
+ val
.i
, info
);
214 else if (flags
& S390_OPERAND_SIGNED
)
215 info
->fprintf_func (info
->stream
, "%c%i", separator
, val
.i
);
218 if (flags
& S390_OPERAND_OR1
)
220 if (flags
& S390_OPERAND_OR2
)
222 if (flags
& S390_OPERAND_OR8
)
225 if ((opcode
->flags
& S390_INSTR_FLAG_OPTPARM
)
229 info
->fprintf_func (info
->stream
, "%c%u", separator
, val
.u
);
232 if (flags
& S390_OPERAND_DISP
)
234 else if (flags
& S390_OPERAND_BASE
)
236 info
->fprintf_func (info
->stream
, ")");
244 /* Check whether opcode A's mask is more specific than that of B. */
247 opcode_mask_more_specific (const struct s390_opcode
*a
,
248 const struct s390_opcode
*b
)
250 return (((int) a
->mask
[0] + a
->mask
[1] + a
->mask
[2]
251 + a
->mask
[3] + a
->mask
[4] + a
->mask
[5])
252 > ((int) b
->mask
[0] + b
->mask
[1] + b
->mask
[2]
253 + b
->mask
[3] + b
->mask
[4] + b
->mask
[5]));
256 /* Print a S390 instruction. */
259 print_insn_s390 (bfd_vma memaddr
, struct disassemble_info
*info
)
262 const struct s390_opcode
*opcode
= NULL
;
264 int status
, opsize
, bufsize
;
269 /* The output looks better if we put 6 bytes on a line. */
270 info
->bytes_per_line
= 6;
272 /* Every S390 instruction is max 6 bytes long. */
273 memset (buffer
, 0, 6);
274 status
= info
->read_memory_func (memaddr
, buffer
, 6, info
);
277 for (bufsize
= 0; bufsize
< 6; bufsize
++)
278 if (info
->read_memory_func (memaddr
, buffer
, bufsize
+ 1, info
) != 0)
282 info
->memory_error_func (status
, memaddr
, info
);
285 opsize
= s390_insn_length (buffer
);
286 status
= opsize
> bufsize
;
291 opsize
= s390_insn_length (buffer
);
296 const struct s390_opcode
*op
;
298 /* Find the "best match" in the opcode table. */
299 for (op
= s390_opcodes
+ opc_index
[buffer
[0]];
300 op
!= s390_opcodes
+ s390_num_opcodes
301 && op
->opcode
[0] == buffer
[0];
304 if ((op
->modes
& current_arch_mask
)
305 && s390_insn_matches_opcode (buffer
, op
)
307 || opcode_mask_more_specific (op
, opcode
)))
314 /* The instruction is valid. Print it and return its size. */
315 s390_print_insn_with_opcode (memaddr
, info
, buffer
, opcode
);
319 /* Fall back to hex print. */
322 value
= (unsigned int) buffer
[0];
323 value
= (value
<< 8) + (unsigned int) buffer
[1];
324 value
= (value
<< 8) + (unsigned int) buffer
[2];
325 value
= (value
<< 8) + (unsigned int) buffer
[3];
326 info
->fprintf_func (info
->stream
, ".long\t0x%08x", value
);
329 else if (bufsize
>= 2)
331 value
= (unsigned int) buffer
[0];
332 value
= (value
<< 8) + (unsigned int) buffer
[1];
333 info
->fprintf_func (info
->stream
, ".short\t0x%04x", value
);
338 value
= (unsigned int) buffer
[0];
339 info
->fprintf_func (info
->stream
, ".byte\t0x%02x", value
);
345 print_s390_disassembler_options (FILE *stream
)
347 fprintf (stream
, _("\n\
348 The following S/390 specific disassembler options are supported for use\n\
349 with the -M switch (multiple options should be separated by commas):\n"));
351 fprintf (stream
, _(" esa Disassemble in ESA architecture mode\n"));
352 fprintf (stream
, _(" zarch Disassemble in z/Architecture mode\n"));