]> git.ipfire.org Git - thirdparty/binutils-gdb.git/blame - opcodes/s390-dis.c
Update year range in copyright notice of binutils files
[thirdparty/binutils-gdb.git] / opcodes / s390-dis.c
CommitLineData
a85d7ed0 1/* s390-dis.c -- Disassemble S390 instructions
d87bef3a 2 Copyright (C) 2000-2023 Free Software Foundation, Inc.
a85d7ed0
NC
3 Contributed by Martin Schwidefsky (schwidefsky@de.ibm.com).
4
9b201bb5 5 This file is part of the GNU opcodes library.
a85d7ed0 6
9b201bb5 7 This library is free software; you can redistribute it and/or modify
a85d7ed0 8 it under the terms of the GNU General Public License as published by
9b201bb5
NC
9 the Free Software Foundation; either version 3, or (at your option)
10 any later version.
a85d7ed0 11
9b201bb5
NC
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.
a85d7ed0
NC
16
17 You should have received a copy of the GNU General Public License
9b201bb5
NC
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. */
a85d7ed0 21
df7b86aa 22#include "sysdep.h"
a85d7ed0
NC
23#include <stdio.h>
24#include "ansidecl.h"
88c1242d 25#include "disassemble.h"
112b7c50 26#include "opintl.h"
a85d7ed0 27#include "opcode/s390.h"
65b48a81 28#include "libiberty.h"
a85d7ed0 29
a85d7ed0
NC
30static int opc_index[256];
31static int current_arch_mask = 0;
b2cc3f6f 32static int option_use_insn_len_bits_p = 0;
a85d7ed0 33
65b48a81
PB
34typedef struct
35{
36 const char *name;
37 const char *description;
38} s390_options_t;
39
40static const s390_options_t options[] =
41{
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") }
46};
47
44f2a95d
KH
48/* Set up index table for first opcode byte. */
49
65b48a81
PB
50void
51disassemble_init_s390 (struct disassemble_info *info)
a85d7ed0 52{
9ace48f3 53 int i;
112b7c50 54 const char *p;
a85d7ed0 55
44f2a95d 56 memset (opc_index, 0, sizeof (opc_index));
9ace48f3
AA
57
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;
112b7c50 62
65b48a81
PB
63 current_arch_mask = 1 << S390_OPCODE_ZARCH;
64 option_use_insn_len_bits_p = 0;
65
112b7c50 66 for (p = info->disassembler_options; p != NULL; )
44f2a95d 67 {
08dedd66 68 if (startswith (p, "esa"))
112b7c50 69 current_arch_mask = 1 << S390_OPCODE_ESA;
08dedd66 70 else if (startswith (p, "zarch"))
112b7c50 71 current_arch_mask = 1 << S390_OPCODE_ZARCH;
08dedd66 72 else if (startswith (p, "insnlength"))
b2cc3f6f 73 option_use_insn_len_bits_p = 1;
112b7c50 74 else
a6743a54
AM
75 /* xgettext:c-format */
76 opcodes_error_handler (_("unknown S/390 disassembler option: %s"), p);
112b7c50
AK
77
78 p = strchr (p, ',');
79 if (p != NULL)
80 p++;
44f2a95d 81 }
a85d7ed0
NC
82}
83
9ace48f3
AA
84/* Derive the length of an instruction from its first byte. */
85
86static inline int
87s390_insn_length (const bfd_byte *buffer)
88{
89 /* 00xxxxxx -> 2, 01xxxxxx/10xxxxxx -> 4, 11xxxxxx -> 6. */
90 return ((buffer[0] >> 6) + 3) & ~1U;
91}
92
93/* Match the instruction in BUFFER against the given OPCODE, excluding
94 the first byte. */
95
96static inline int
97s390_insn_matches_opcode (const bfd_byte *buffer,
98 const struct s390_opcode *opcode)
99{
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];
105}
106
107union operand_value
108{
109 int i;
110 unsigned int u;
111};
112
a85d7ed0 113/* Extracts an operand value from an instruction. */
7330f9c3
AK
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
9ace48f3 117 the operand. */
a85d7ed0 118
9ace48f3
AA
119static inline union operand_value
120s390_extract_operand (const bfd_byte *insn,
121 const struct s390_operand *operand)
a85d7ed0 122{
9ace48f3 123 union operand_value ret;
a85d7ed0
NC
124 unsigned int val;
125 int bits;
1e2e8c52 126 const bfd_byte *orig_insn = insn;
a85d7ed0 127
44f2a95d
KH
128 /* Extract fragments of the operand byte for byte. */
129 insn += operand->shift / 8;
a85d7ed0
NC
130 bits = (operand->shift & 7) + operand->bits;
131 val = 0;
44f2a95d
KH
132 do
133 {
134 val <<= 8;
135 val |= (unsigned int) *insn++;
136 bits -= 8;
137 }
138 while (bits > 0);
a85d7ed0 139 val >>= -bits;
44f2a95d
KH
140 val &= ((1U << (operand->bits - 1)) << 1) - 1;
141
bac02689
MS
142 /* Check for special long displacement case. */
143 if (operand->bits == 20 && operand->shift == 20)
144 val = (val & 0xff) << 12 | (val & 0xfff00) >> 8;
145
9ace48f3
AA
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))
149 {
150 unsigned int m = 1U << (operand->bits - 1);
151
152 if (val >= m)
153 ret.i = (int) (val - m) - 1 - (int) (m - 1U);
154 else
155 ret.i = (int) val;
156 }
157 else if (operand->flags & S390_OPERAND_LENGTH)
158 /* Length x in an instruction has real length x + 1. */
159 ret.u = val + 1;
1e2e8c52
AK
160
161 else if (operand->flags & S390_OPERAND_VR)
162 {
163 /* Extract the extra bits for a vector register operand stored
164 in the RXB field. */
165 unsigned vr = operand->shift == 32 ? 3
166 : (unsigned) operand->shift / 4 - 2;
167
168 ret.u = val | ((orig_insn[4] & (1 << (3 - vr))) << (vr + 1));
169 }
9ace48f3
AA
170 else
171 ret.u = val;
172
173 return ret;
174}
175
176/* Print the S390 instruction in BUFFER, assuming that it matches the
177 given OPCODE. */
178
179static void
180s390_print_insn_with_opcode (bfd_vma memaddr,
181 struct disassemble_info *info,
182 const bfd_byte *buffer,
183 const struct s390_opcode *opcode)
184{
185 const unsigned char *opindex;
186 char separator;
187
188 /* Mnemonic. */
ec54dc91
AB
189 info->fprintf_styled_func (info->stream, dis_style_mnemonic,
190 "%s", opcode->name);
9ace48f3
AA
191
192 /* Operands. */
193 separator = '\t';
194 for (opindex = opcode->operands; *opindex != 0; opindex++)
195 {
196 const struct s390_operand *operand = s390_operands + *opindex;
197 union operand_value val = s390_extract_operand (buffer, operand);
198 unsigned long flags = operand->flags;
199
200 if ((flags & S390_OPERAND_INDEX) && val.u == 0)
201 continue;
202 if ((flags & S390_OPERAND_BASE) &&
203 val.u == 0 && separator == '(')
204 {
205 separator = ',';
206 continue;
207 }
208
1e2e8c52
AK
209 /* For instructions with a last optional operand don't print it
210 if zero. */
a09f2586 211 if ((opcode->flags & (S390_INSTR_FLAG_OPTPARM | S390_INSTR_FLAG_OPTPARM2))
1e2e8c52
AK
212 && val.u == 0
213 && opindex[1] == 0)
214 break;
9ace48f3 215
a09f2586
AK
216 if ((opcode->flags & S390_INSTR_FLAG_OPTPARM2)
217 && val.u == 0 && opindex[1] != 0 && opindex[2] == 0)
218 {
219 union operand_value next_op_val =
220 s390_extract_operand (buffer, s390_operands + opindex[1]);
221 if (next_op_val.u == 0)
222 break;
223 }
224
9ace48f3 225 if (flags & S390_OPERAND_GPR)
ec54dc91
AB
226 {
227 info->fprintf_styled_func (info->stream, dis_style_text,
228 "%c", separator);
229 info->fprintf_styled_func (info->stream, dis_style_register,
230 "%%r%u", val.u);
231 }
9ace48f3 232 else if (flags & S390_OPERAND_FPR)
ec54dc91
AB
233 {
234 info->fprintf_styled_func (info->stream, dis_style_text,
235 "%c", separator);
236 info->fprintf_styled_func (info->stream, dis_style_register,
237 "%%f%u", val.u);
238 }
1e2e8c52 239 else if (flags & S390_OPERAND_VR)
ec54dc91
AB
240 {
241 info->fprintf_styled_func (info->stream, dis_style_text,
242 "%c", separator);
243 info->fprintf_styled_func (info->stream, dis_style_register,
244 "%%v%i", val.u);
245 }
9ace48f3 246 else if (flags & S390_OPERAND_AR)
ec54dc91
AB
247 {
248 info->fprintf_styled_func (info->stream, dis_style_text,
249 "%c", separator);
250 info->fprintf_styled_func (info->stream, dis_style_register,
251 "%%a%u", val.u);
252 }
9ace48f3 253 else if (flags & S390_OPERAND_CR)
ec54dc91
AB
254 {
255 info->fprintf_styled_func (info->stream, dis_style_text,
256 "%c", separator);
257 info->fprintf_styled_func (info->stream, dis_style_register,
258 "%%c%u", val.u);
259 }
9ace48f3 260 else if (flags & S390_OPERAND_PCREL)
1e2e8c52 261 {
ec54dc91
AB
262 info->fprintf_styled_func (info->stream, dis_style_text,
263 "%c", separator);
1e2e8c52
AK
264 info->print_address_func (memaddr + val.i + val.i, info);
265 }
9ace48f3 266 else if (flags & S390_OPERAND_SIGNED)
ec54dc91
AB
267 {
268 enum disassembler_style style;
269
270 info->fprintf_styled_func (info->stream, dis_style_text,
271 "%c", separator);
272 style = ((flags & S390_OPERAND_DISP)
273 ? dis_style_address_offset : dis_style_immediate);
274 info->fprintf_styled_func (info->stream, style, "%i", val.i);
275 }
9ace48f3 276 else
1e2e8c52 277 {
ec54dc91
AB
278 enum disassembler_style style;
279
1e2e8c52
AK
280 if (flags & S390_OPERAND_OR1)
281 val.u &= ~1;
282 if (flags & S390_OPERAND_OR2)
283 val.u &= ~2;
284 if (flags & S390_OPERAND_OR8)
285 val.u &= ~8;
286
287 if ((opcode->flags & S390_INSTR_FLAG_OPTPARM)
288 && val.u == 0
289 && opindex[1] == 0)
290 break;
ec54dc91
AB
291 info->fprintf_styled_func (info->stream, dis_style_text,
292 "%c", separator);
293 style = ((flags & S390_OPERAND_DISP)
294 ? dis_style_address_offset : dis_style_immediate);
295 info->fprintf_styled_func (info->stream, style, "%u", val.u);
1e2e8c52 296 }
9ace48f3
AA
297
298 if (flags & S390_OPERAND_DISP)
299 separator = '(';
300 else if (flags & S390_OPERAND_BASE)
301 {
ec54dc91 302 info->fprintf_styled_func (info->stream, dis_style_text, ")");
9ace48f3
AA
303 separator = ',';
304 }
305 else
306 separator = ',';
307 }
308}
309
310/* Check whether opcode A's mask is more specific than that of B. */
44f2a95d 311
9ace48f3
AA
312static int
313opcode_mask_more_specific (const struct s390_opcode *a,
314 const struct s390_opcode *b)
315{
316 return (((int) a->mask[0] + a->mask[1] + a->mask[2]
317 + a->mask[3] + a->mask[4] + a->mask[5])
318 > ((int) b->mask[0] + b->mask[1] + b->mask[2]
319 + b->mask[3] + b->mask[4] + b->mask[5]));
a85d7ed0
NC
320}
321
322/* Print a S390 instruction. */
323
324int
47b0e7ad 325print_insn_s390 (bfd_vma memaddr, struct disassemble_info *info)
a85d7ed0
NC
326{
327 bfd_byte buffer[6];
9ace48f3 328 const struct s390_opcode *opcode = NULL;
a85d7ed0 329 unsigned int value;
b2cc3f6f 330 int status, opsize, bufsize, bytes_to_dump, i;
a85d7ed0 331
a85d7ed0
NC
332 /* The output looks better if we put 6 bytes on a line. */
333 info->bytes_per_line = 6;
334
335 /* Every S390 instruction is max 6 bytes long. */
44f2a95d 336 memset (buffer, 0, 6);
9ace48f3 337 status = info->read_memory_func (memaddr, buffer, 6, info);
44f2a95d
KH
338 if (status != 0)
339 {
340 for (bufsize = 0; bufsize < 6; bufsize++)
9ace48f3 341 if (info->read_memory_func (memaddr, buffer, bufsize + 1, info) != 0)
44f2a95d
KH
342 break;
343 if (bufsize <= 0)
344 {
9ace48f3 345 info->memory_error_func (status, memaddr, info);
44f2a95d
KH
346 return -1;
347 }
9ace48f3 348 opsize = s390_insn_length (buffer);
44f2a95d
KH
349 status = opsize > bufsize;
350 }
351 else
352 {
353 bufsize = 6;
9ace48f3 354 opsize = s390_insn_length (buffer);
44f2a95d
KH
355 }
356
357 if (status == 0)
358 {
02cbf767
AK
359 const struct s390_opcode *op;
360
9ace48f3
AA
361 /* Find the "best match" in the opcode table. */
362 for (op = s390_opcodes + opc_index[buffer[0]];
363 op != s390_opcodes + s390_num_opcodes
364 && op->opcode[0] == buffer[0];
365 op++)
44f2a95d 366 {
9ace48f3
AA
367 if ((op->modes & current_arch_mask)
368 && s390_insn_matches_opcode (buffer, op)
369 && (opcode == NULL
370 || opcode_mask_more_specific (op, opcode)))
371 opcode = op;
44f2a95d 372 }
44f2a95d 373
b2cc3f6f
AK
374 if (opcode != NULL)
375 {
376 /* The instruction is valid. Print it and return its size. */
377 s390_print_insn_with_opcode (memaddr, info, buffer, opcode);
378 return opsize;
379 }
9ace48f3
AA
380 }
381
b2cc3f6f
AK
382 /* For code sections it makes sense to skip unknown instructions
383 according to their length bits. */
384 if (status == 0
385 && option_use_insn_len_bits_p
386 && info->section != NULL
387 && (info->section->flags & SEC_CODE))
388 bytes_to_dump = opsize;
389 else
390 /* By default unknown instructions are printed as .long's/.short'
391 depending on how many bytes are available. */
392 bytes_to_dump = bufsize >= 4 ? 4 : bufsize;
393
394 if (bytes_to_dump == 0)
395 return 0;
396
9ace48f3 397 /* Fall back to hex print. */
b2cc3f6f 398 switch (bytes_to_dump)
44f2a95d 399 {
b2cc3f6f 400 case 4:
44f2a95d
KH
401 value = (unsigned int) buffer[0];
402 value = (value << 8) + (unsigned int) buffer[1];
403 value = (value << 8) + (unsigned int) buffer[2];
404 value = (value << 8) + (unsigned int) buffer[3];
ec54dc91
AB
405 info->fprintf_styled_func (info->stream, dis_style_assembler_directive,
406 ".long");
407 info->fprintf_styled_func (info->stream, dis_style_text,
408 "\t");
409 info->fprintf_styled_func (info->stream, dis_style_immediate,
410 "0x%08x", value);
44f2a95d 411 return 4;
b2cc3f6f 412 case 2:
44f2a95d
KH
413 value = (unsigned int) buffer[0];
414 value = (value << 8) + (unsigned int) buffer[1];
ec54dc91
AB
415 info->fprintf_styled_func (info->stream, dis_style_assembler_directive,
416 ".short");
417 info->fprintf_styled_func (info->stream, dis_style_text,
418 "\t");
419 info->fprintf_styled_func (info->stream, dis_style_immediate,
420 "0x%04x", value);
44f2a95d 421 return 2;
b2cc3f6f 422 default:
ec54dc91
AB
423 info->fprintf_styled_func (info->stream, dis_style_assembler_directive,
424 ".byte");
425 info->fprintf_styled_func (info->stream, dis_style_text,
426 "\t");
427 info->fprintf_styled_func (info->stream, dis_style_immediate,
428 "0x%02x", (unsigned int) buffer[0]);
b2cc3f6f 429 for (i = 1; i < bytes_to_dump; i++)
ec54dc91
AB
430 info->fprintf_styled_func (info->stream, dis_style_immediate,
431 "0x%02x", (unsigned int) buffer[i]);
b2cc3f6f 432 return bytes_to_dump;
a85d7ed0 433 }
b2cc3f6f 434 return 0;
a85d7ed0 435}
112b7c50 436
471b9d15 437const disasm_options_and_args_t *
65b48a81
PB
438disassembler_options_s390 (void)
439{
471b9d15 440 static disasm_options_and_args_t *opts_and_args;
65b48a81 441
471b9d15 442 if (opts_and_args == NULL)
65b48a81
PB
443 {
444 size_t i, num_options = ARRAY_SIZE (options);
471b9d15
MR
445 disasm_options_t *opts;
446
447 opts_and_args = XNEW (disasm_options_and_args_t);
448 opts_and_args->args = NULL;
449
450 opts = &opts_and_args->options;
65b48a81
PB
451 opts->name = XNEWVEC (const char *, num_options + 1);
452 opts->description = XNEWVEC (const char *, num_options + 1);
471b9d15 453 opts->arg = NULL;
65b48a81
PB
454 for (i = 0; i < num_options; i++)
455 {
456 opts->name[i] = options[i].name;
457 opts->description[i] = _(options[i].description);
458 }
459 /* The array we return must be NULL terminated. */
460 opts->name[i] = NULL;
461 opts->description[i] = NULL;
462 }
463
471b9d15 464 return opts_and_args;
65b48a81
PB
465}
466
112b7c50
AK
467void
468print_s390_disassembler_options (FILE *stream)
469{
65b48a81 470 unsigned int i, max_len = 0;
112b7c50
AK
471 fprintf (stream, _("\n\
472The following S/390 specific disassembler options are supported for use\n\
473with the -M switch (multiple options should be separated by commas):\n"));
474
65b48a81
PB
475 for (i = 0; i < ARRAY_SIZE (options); i++)
476 {
477 unsigned int len = strlen (options[i].name);
478 if (max_len < len)
479 max_len = len;
480 }
481
482 for (i = 0, max_len++; i < ARRAY_SIZE (options); i++)
483 fprintf (stream, " %s%*c %s\n",
484 options[i].name,
485 (int)(max_len - strlen (options[i].name)), ' ',
486 _(options[i].description));
112b7c50 487}