1 /* s390-dis.c -- Disassemble S390 instructions
2 Copyright (C) 2000-2020 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 /* xgettext:c-format */
76 opcodes_error_handler (_("unknown S/390 disassembler option: %s"), p
);
84 /* Derive the length of an instruction from its first byte. */
87 s390_insn_length (const bfd_byte
*buffer
)
89 /* 00xxxxxx -> 2, 01xxxxxx/10xxxxxx -> 4, 11xxxxxx -> 6. */
90 return ((buffer
[0] >> 6) + 3) & ~1U;
93 /* Match the instruction in BUFFER against the given OPCODE, excluding
97 s390_insn_matches_opcode (const bfd_byte
*buffer
,
98 const struct s390_opcode
*opcode
)
100 return (buffer
[1] & opcode
->mask
[1]) == opcode
->opcode
[1]
101 && (buffer
[2] & opcode
->mask
[2]) == opcode
->opcode
[2]
102 && (buffer
[3] & opcode
->mask
[3]) == opcode
->opcode
[3]
103 && (buffer
[4] & opcode
->mask
[4]) == opcode
->opcode
[4]
104 && (buffer
[5] & opcode
->mask
[5]) == opcode
->opcode
[5];
113 /* Extracts an operand value from an instruction. */
114 /* We do not perform the shift operation for larl-type address
115 operands here since that would lead to an overflow of the 32 bit
116 integer value. Instead the shift operation is done when printing
119 static inline union operand_value
120 s390_extract_operand (const bfd_byte
*insn
,
121 const struct s390_operand
*operand
)
123 union operand_value ret
;
126 const bfd_byte
*orig_insn
= insn
;
128 /* Extract fragments of the operand byte for byte. */
129 insn
+= operand
->shift
/ 8;
130 bits
= (operand
->shift
& 7) + operand
->bits
;
135 val
|= (unsigned int) *insn
++;
140 val
&= ((1U << (operand
->bits
- 1)) << 1) - 1;
142 /* Check for special long displacement case. */
143 if (operand
->bits
== 20 && operand
->shift
== 20)
144 val
= (val
& 0xff) << 12 | (val
& 0xfff00) >> 8;
146 /* Sign extend value if the operand is signed or pc relative. Avoid
147 integer overflows. */
148 if (operand
->flags
& (S390_OPERAND_SIGNED
| S390_OPERAND_PCREL
))
150 unsigned int m
= 1U << (operand
->bits
- 1);
153 ret
.i
= (int) (val
- m
) - 1 - (int) (m
- 1U);
157 else if (operand
->flags
& S390_OPERAND_LENGTH
)
158 /* Length x in an instruction has real length x + 1. */
161 else if (operand
->flags
& S390_OPERAND_VR
)
163 /* Extract the extra bits for a vector register operand stored
165 unsigned vr
= operand
->shift
== 32 ? 3
166 : (unsigned) operand
->shift
/ 4 - 2;
168 ret
.u
= val
| ((orig_insn
[4] & (1 << (3 - vr
))) << (vr
+ 1));
176 /* Print the S390 instruction in BUFFER, assuming that it matches the
180 s390_print_insn_with_opcode (bfd_vma memaddr
,
181 struct disassemble_info
*info
,
182 const bfd_byte
*buffer
,
183 const struct s390_opcode
*opcode
)
185 const unsigned char *opindex
;
189 info
->fprintf_func (info
->stream
, "%s", opcode
->name
);
193 for (opindex
= opcode
->operands
; *opindex
!= 0; opindex
++)
195 const struct s390_operand
*operand
= s390_operands
+ *opindex
;
196 union operand_value val
= s390_extract_operand (buffer
, operand
);
197 unsigned long flags
= operand
->flags
;
199 if ((flags
& S390_OPERAND_INDEX
) && val
.u
== 0)
201 if ((flags
& S390_OPERAND_BASE
) &&
202 val
.u
== 0 && separator
== '(')
208 /* For instructions with a last optional operand don't print it
210 if ((opcode
->flags
& (S390_INSTR_FLAG_OPTPARM
| S390_INSTR_FLAG_OPTPARM2
))
215 if ((opcode
->flags
& S390_INSTR_FLAG_OPTPARM2
)
216 && val
.u
== 0 && opindex
[1] != 0 && opindex
[2] == 0)
218 union operand_value next_op_val
=
219 s390_extract_operand (buffer
, s390_operands
+ opindex
[1]);
220 if (next_op_val
.u
== 0)
224 if (flags
& S390_OPERAND_GPR
)
225 info
->fprintf_func (info
->stream
, "%c%%r%u", separator
, val
.u
);
226 else if (flags
& S390_OPERAND_FPR
)
227 info
->fprintf_func (info
->stream
, "%c%%f%u", separator
, val
.u
);
228 else if (flags
& S390_OPERAND_VR
)
229 info
->fprintf_func (info
->stream
, "%c%%v%i", separator
, val
.u
);
230 else if (flags
& S390_OPERAND_AR
)
231 info
->fprintf_func (info
->stream
, "%c%%a%u", separator
, val
.u
);
232 else if (flags
& S390_OPERAND_CR
)
233 info
->fprintf_func (info
->stream
, "%c%%c%u", separator
, val
.u
);
234 else if (flags
& S390_OPERAND_PCREL
)
236 info
->fprintf_func (info
->stream
, "%c", separator
);
237 info
->print_address_func (memaddr
+ val
.i
+ val
.i
, info
);
239 else if (flags
& S390_OPERAND_SIGNED
)
240 info
->fprintf_func (info
->stream
, "%c%i", separator
, val
.i
);
243 if (flags
& S390_OPERAND_OR1
)
245 if (flags
& S390_OPERAND_OR2
)
247 if (flags
& S390_OPERAND_OR8
)
250 if ((opcode
->flags
& S390_INSTR_FLAG_OPTPARM
)
254 info
->fprintf_func (info
->stream
, "%c%u", separator
, val
.u
);
257 if (flags
& S390_OPERAND_DISP
)
259 else if (flags
& S390_OPERAND_BASE
)
261 info
->fprintf_func (info
->stream
, ")");
269 /* Check whether opcode A's mask is more specific than that of B. */
272 opcode_mask_more_specific (const struct s390_opcode
*a
,
273 const struct s390_opcode
*b
)
275 return (((int) a
->mask
[0] + a
->mask
[1] + a
->mask
[2]
276 + a
->mask
[3] + a
->mask
[4] + a
->mask
[5])
277 > ((int) b
->mask
[0] + b
->mask
[1] + b
->mask
[2]
278 + b
->mask
[3] + b
->mask
[4] + b
->mask
[5]));
281 /* Print a S390 instruction. */
284 print_insn_s390 (bfd_vma memaddr
, struct disassemble_info
*info
)
287 const struct s390_opcode
*opcode
= NULL
;
289 int status
, opsize
, bufsize
, bytes_to_dump
, i
;
291 /* The output looks better if we put 6 bytes on a line. */
292 info
->bytes_per_line
= 6;
294 /* Every S390 instruction is max 6 bytes long. */
295 memset (buffer
, 0, 6);
296 status
= info
->read_memory_func (memaddr
, buffer
, 6, info
);
299 for (bufsize
= 0; bufsize
< 6; bufsize
++)
300 if (info
->read_memory_func (memaddr
, buffer
, bufsize
+ 1, info
) != 0)
304 info
->memory_error_func (status
, memaddr
, info
);
307 opsize
= s390_insn_length (buffer
);
308 status
= opsize
> bufsize
;
313 opsize
= s390_insn_length (buffer
);
318 const struct s390_opcode
*op
;
320 /* Find the "best match" in the opcode table. */
321 for (op
= s390_opcodes
+ opc_index
[buffer
[0]];
322 op
!= s390_opcodes
+ s390_num_opcodes
323 && op
->opcode
[0] == buffer
[0];
326 if ((op
->modes
& current_arch_mask
)
327 && s390_insn_matches_opcode (buffer
, op
)
329 || opcode_mask_more_specific (op
, opcode
)))
335 /* The instruction is valid. Print it and return its size. */
336 s390_print_insn_with_opcode (memaddr
, info
, buffer
, opcode
);
341 /* For code sections it makes sense to skip unknown instructions
342 according to their length bits. */
344 && option_use_insn_len_bits_p
345 && info
->section
!= NULL
346 && (info
->section
->flags
& SEC_CODE
))
347 bytes_to_dump
= opsize
;
349 /* By default unknown instructions are printed as .long's/.short'
350 depending on how many bytes are available. */
351 bytes_to_dump
= bufsize
>= 4 ? 4 : bufsize
;
353 if (bytes_to_dump
== 0)
356 /* Fall back to hex print. */
357 switch (bytes_to_dump
)
360 value
= (unsigned int) buffer
[0];
361 value
= (value
<< 8) + (unsigned int) buffer
[1];
362 value
= (value
<< 8) + (unsigned int) buffer
[2];
363 value
= (value
<< 8) + (unsigned int) buffer
[3];
364 info
->fprintf_func (info
->stream
, ".long\t0x%08x", value
);
367 value
= (unsigned int) buffer
[0];
368 value
= (value
<< 8) + (unsigned int) buffer
[1];
369 info
->fprintf_func (info
->stream
, ".short\t0x%04x", value
);
372 info
->fprintf_func (info
->stream
, ".byte\t0x%02x",
373 (unsigned int) buffer
[0]);
374 for (i
= 1; i
< bytes_to_dump
; i
++)
375 info
->fprintf_func (info
->stream
, ",0x%02x",
376 (unsigned int) buffer
[i
]);
377 return bytes_to_dump
;
382 const disasm_options_and_args_t
*
383 disassembler_options_s390 (void)
385 static disasm_options_and_args_t
*opts_and_args
;
387 if (opts_and_args
== NULL
)
389 size_t i
, num_options
= ARRAY_SIZE (options
);
390 disasm_options_t
*opts
;
392 opts_and_args
= XNEW (disasm_options_and_args_t
);
393 opts_and_args
->args
= NULL
;
395 opts
= &opts_and_args
->options
;
396 opts
->name
= XNEWVEC (const char *, num_options
+ 1);
397 opts
->description
= XNEWVEC (const char *, num_options
+ 1);
399 for (i
= 0; i
< num_options
; i
++)
401 opts
->name
[i
] = options
[i
].name
;
402 opts
->description
[i
] = _(options
[i
].description
);
404 /* The array we return must be NULL terminated. */
405 opts
->name
[i
] = NULL
;
406 opts
->description
[i
] = NULL
;
409 return opts_and_args
;
413 print_s390_disassembler_options (FILE *stream
)
415 unsigned int i
, max_len
= 0;
416 fprintf (stream
, _("\n\
417 The following S/390 specific disassembler options are supported for use\n\
418 with the -M switch (multiple options should be separated by commas):\n"));
420 for (i
= 0; i
< ARRAY_SIZE (options
); i
++)
422 unsigned int len
= strlen (options
[i
].name
);
427 for (i
= 0, max_len
++; i
< ARRAY_SIZE (options
); i
++)
428 fprintf (stream
, " %s%*c %s\n",
430 (int)(max_len
- strlen (options
[i
].name
)), ' ',
431 _(options
[i
].description
));