Fix build error in gdb/rocm-tdep.c
[deliverable/binutils-gdb.git] / opcodes / s390-dis.c
CommitLineData
a85d7ed0 1/* s390-dis.c -- Disassemble S390 instructions
b3adc24a 2 Copyright (C) 2000-2020 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 {
112b7c50
AK
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;
b2cc3f6f
AK
72 else if (CONST_STRNEQ (p, "insnlength"))
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. */
189 info->fprintf_func (info->stream, "%s", opcode->name);
190
191 /* Operands. */
192 separator = '\t';
193 for (opindex = opcode->operands; *opindex != 0; opindex++)
194 {
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;
198
199 if ((flags & S390_OPERAND_INDEX) && val.u == 0)
200 continue;
201 if ((flags & S390_OPERAND_BASE) &&
202 val.u == 0 && separator == '(')
203 {
204 separator = ',';
205 continue;
206 }
207
1e2e8c52
AK
208 /* For instructions with a last optional operand don't print it
209 if zero. */
a09f2586 210 if ((opcode->flags & (S390_INSTR_FLAG_OPTPARM | S390_INSTR_FLAG_OPTPARM2))
1e2e8c52
AK
211 && val.u == 0
212 && opindex[1] == 0)
213 break;
9ace48f3 214
a09f2586
AK
215 if ((opcode->flags & S390_INSTR_FLAG_OPTPARM2)
216 && val.u == 0 && opindex[1] != 0 && opindex[2] == 0)
217 {
218 union operand_value next_op_val =
219 s390_extract_operand (buffer, s390_operands + opindex[1]);
220 if (next_op_val.u == 0)
221 break;
222 }
223
9ace48f3 224 if (flags & S390_OPERAND_GPR)
1e2e8c52 225 info->fprintf_func (info->stream, "%c%%r%u", separator, val.u);
9ace48f3 226 else if (flags & S390_OPERAND_FPR)
1e2e8c52
AK
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);
9ace48f3 230 else if (flags & S390_OPERAND_AR)
1e2e8c52 231 info->fprintf_func (info->stream, "%c%%a%u", separator, val.u);
9ace48f3 232 else if (flags & S390_OPERAND_CR)
1e2e8c52 233 info->fprintf_func (info->stream, "%c%%c%u", separator, val.u);
9ace48f3 234 else if (flags & S390_OPERAND_PCREL)
1e2e8c52
AK
235 {
236 info->fprintf_func (info->stream, "%c", separator);
237 info->print_address_func (memaddr + val.i + val.i, info);
238 }
9ace48f3 239 else if (flags & S390_OPERAND_SIGNED)
1e2e8c52 240 info->fprintf_func (info->stream, "%c%i", separator, val.i);
9ace48f3 241 else
1e2e8c52
AK
242 {
243 if (flags & S390_OPERAND_OR1)
244 val.u &= ~1;
245 if (flags & S390_OPERAND_OR2)
246 val.u &= ~2;
247 if (flags & S390_OPERAND_OR8)
248 val.u &= ~8;
249
250 if ((opcode->flags & S390_INSTR_FLAG_OPTPARM)
251 && val.u == 0
252 && opindex[1] == 0)
253 break;
254 info->fprintf_func (info->stream, "%c%u", separator, val.u);
255 }
9ace48f3
AA
256
257 if (flags & S390_OPERAND_DISP)
258 separator = '(';
259 else if (flags & S390_OPERAND_BASE)
260 {
261 info->fprintf_func (info->stream, ")");
262 separator = ',';
263 }
264 else
265 separator = ',';
266 }
267}
268
269/* Check whether opcode A's mask is more specific than that of B. */
44f2a95d 270
9ace48f3
AA
271static int
272opcode_mask_more_specific (const struct s390_opcode *a,
273 const struct s390_opcode *b)
274{
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]));
a85d7ed0
NC
279}
280
281/* Print a S390 instruction. */
282
283int
47b0e7ad 284print_insn_s390 (bfd_vma memaddr, struct disassemble_info *info)
a85d7ed0
NC
285{
286 bfd_byte buffer[6];
9ace48f3 287 const struct s390_opcode *opcode = NULL;
a85d7ed0 288 unsigned int value;
b2cc3f6f 289 int status, opsize, bufsize, bytes_to_dump, i;
a85d7ed0 290
a85d7ed0
NC
291 /* The output looks better if we put 6 bytes on a line. */
292 info->bytes_per_line = 6;
293
294 /* Every S390 instruction is max 6 bytes long. */
44f2a95d 295 memset (buffer, 0, 6);
9ace48f3 296 status = info->read_memory_func (memaddr, buffer, 6, info);
44f2a95d
KH
297 if (status != 0)
298 {
299 for (bufsize = 0; bufsize < 6; bufsize++)
9ace48f3 300 if (info->read_memory_func (memaddr, buffer, bufsize + 1, info) != 0)
44f2a95d
KH
301 break;
302 if (bufsize <= 0)
303 {
9ace48f3 304 info->memory_error_func (status, memaddr, info);
44f2a95d
KH
305 return -1;
306 }
9ace48f3 307 opsize = s390_insn_length (buffer);
44f2a95d
KH
308 status = opsize > bufsize;
309 }
310 else
311 {
312 bufsize = 6;
9ace48f3 313 opsize = s390_insn_length (buffer);
44f2a95d
KH
314 }
315
316 if (status == 0)
317 {
02cbf767
AK
318 const struct s390_opcode *op;
319
9ace48f3
AA
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];
324 op++)
44f2a95d 325 {
9ace48f3
AA
326 if ((op->modes & current_arch_mask)
327 && s390_insn_matches_opcode (buffer, op)
328 && (opcode == NULL
329 || opcode_mask_more_specific (op, opcode)))
330 opcode = op;
44f2a95d 331 }
44f2a95d 332
b2cc3f6f
AK
333 if (opcode != NULL)
334 {
335 /* The instruction is valid. Print it and return its size. */
336 s390_print_insn_with_opcode (memaddr, info, buffer, opcode);
337 return opsize;
338 }
9ace48f3
AA
339 }
340
b2cc3f6f
AK
341 /* For code sections it makes sense to skip unknown instructions
342 according to their length bits. */
343 if (status == 0
344 && option_use_insn_len_bits_p
345 && info->section != NULL
346 && (info->section->flags & SEC_CODE))
347 bytes_to_dump = opsize;
348 else
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;
352
353 if (bytes_to_dump == 0)
354 return 0;
355
9ace48f3 356 /* Fall back to hex print. */
b2cc3f6f 357 switch (bytes_to_dump)
44f2a95d 358 {
b2cc3f6f 359 case 4:
44f2a95d
KH
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];
9ace48f3 364 info->fprintf_func (info->stream, ".long\t0x%08x", value);
44f2a95d 365 return 4;
b2cc3f6f 366 case 2:
44f2a95d
KH
367 value = (unsigned int) buffer[0];
368 value = (value << 8) + (unsigned int) buffer[1];
9ace48f3 369 info->fprintf_func (info->stream, ".short\t0x%04x", value);
44f2a95d 370 return 2;
b2cc3f6f
AK
371 default:
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;
a85d7ed0 378 }
b2cc3f6f 379 return 0;
a85d7ed0 380}
112b7c50 381
471b9d15 382const disasm_options_and_args_t *
65b48a81
PB
383disassembler_options_s390 (void)
384{
471b9d15 385 static disasm_options_and_args_t *opts_and_args;
65b48a81 386
471b9d15 387 if (opts_and_args == NULL)
65b48a81
PB
388 {
389 size_t i, num_options = ARRAY_SIZE (options);
471b9d15
MR
390 disasm_options_t *opts;
391
392 opts_and_args = XNEW (disasm_options_and_args_t);
393 opts_and_args->args = NULL;
394
395 opts = &opts_and_args->options;
65b48a81
PB
396 opts->name = XNEWVEC (const char *, num_options + 1);
397 opts->description = XNEWVEC (const char *, num_options + 1);
471b9d15 398 opts->arg = NULL;
65b48a81
PB
399 for (i = 0; i < num_options; i++)
400 {
401 opts->name[i] = options[i].name;
402 opts->description[i] = _(options[i].description);
403 }
404 /* The array we return must be NULL terminated. */
405 opts->name[i] = NULL;
406 opts->description[i] = NULL;
407 }
408
471b9d15 409 return opts_and_args;
65b48a81
PB
410}
411
112b7c50
AK
412void
413print_s390_disassembler_options (FILE *stream)
414{
65b48a81 415 unsigned int i, max_len = 0;
112b7c50
AK
416 fprintf (stream, _("\n\
417The following S/390 specific disassembler options are supported for use\n\
418with the -M switch (multiple options should be separated by commas):\n"));
419
65b48a81
PB
420 for (i = 0; i < ARRAY_SIZE (options); i++)
421 {
422 unsigned int len = strlen (options[i].name);
423 if (max_len < len)
424 max_len = len;
425 }
426
427 for (i = 0, max_len++; i < ARRAY_SIZE (options); i++)
428 fprintf (stream, " %s%*c %s\n",
429 options[i].name,
430 (int)(max_len - strlen (options[i].name)), ' ',
431 _(options[i].description));
112b7c50 432}
This page took 0.91583 seconds and 4 git commands to generate.