]> git.ipfire.org Git - thirdparty/binutils-gdb.git/blame - opcodes/s390-dis.c
GDB: Add support for the new set/show disassembler-options commands.
[thirdparty/binutils-gdb.git] / opcodes / s390-dis.c
CommitLineData
a85d7ed0 1/* s390-dis.c -- Disassemble S390 instructions
2571583a 2 Copyright (C) 2000-2017 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"
a85d7ed0 25#include "dis-asm.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
AK
74 else
75 fprintf (stderr, "Unknown S/390 disassembler option: %s\n", p);
76
77 p = strchr (p, ',');
78 if (p != NULL)
79 p++;
44f2a95d 80 }
a85d7ed0
NC
81}
82
9ace48f3
AA
83/* Derive the length of an instruction from its first byte. */
84
85static inline int
86s390_insn_length (const bfd_byte *buffer)
87{
88 /* 00xxxxxx -> 2, 01xxxxxx/10xxxxxx -> 4, 11xxxxxx -> 6. */
89 return ((buffer[0] >> 6) + 3) & ~1U;
90}
91
92/* Match the instruction in BUFFER against the given OPCODE, excluding
93 the first byte. */
94
95static inline int
96s390_insn_matches_opcode (const bfd_byte *buffer,
97 const struct s390_opcode *opcode)
98{
99 return (buffer[1] & opcode->mask[1]) == opcode->opcode[1]
100 && (buffer[2] & opcode->mask[2]) == opcode->opcode[2]
101 && (buffer[3] & opcode->mask[3]) == opcode->opcode[3]
102 && (buffer[4] & opcode->mask[4]) == opcode->opcode[4]
103 && (buffer[5] & opcode->mask[5]) == opcode->opcode[5];
104}
105
106union operand_value
107{
108 int i;
109 unsigned int u;
110};
111
a85d7ed0 112/* Extracts an operand value from an instruction. */
7330f9c3
AK
113/* We do not perform the shift operation for larl-type address
114 operands here since that would lead to an overflow of the 32 bit
115 integer value. Instead the shift operation is done when printing
9ace48f3 116 the operand. */
a85d7ed0 117
9ace48f3
AA
118static inline union operand_value
119s390_extract_operand (const bfd_byte *insn,
120 const struct s390_operand *operand)
a85d7ed0 121{
9ace48f3 122 union operand_value ret;
a85d7ed0
NC
123 unsigned int val;
124 int bits;
1e2e8c52 125 const bfd_byte *orig_insn = insn;
a85d7ed0 126
44f2a95d
KH
127 /* Extract fragments of the operand byte for byte. */
128 insn += operand->shift / 8;
a85d7ed0
NC
129 bits = (operand->shift & 7) + operand->bits;
130 val = 0;
44f2a95d
KH
131 do
132 {
133 val <<= 8;
134 val |= (unsigned int) *insn++;
135 bits -= 8;
136 }
137 while (bits > 0);
a85d7ed0 138 val >>= -bits;
44f2a95d
KH
139 val &= ((1U << (operand->bits - 1)) << 1) - 1;
140
bac02689
MS
141 /* Check for special long displacement case. */
142 if (operand->bits == 20 && operand->shift == 20)
143 val = (val & 0xff) << 12 | (val & 0xfff00) >> 8;
144
9ace48f3
AA
145 /* Sign extend value if the operand is signed or pc relative. Avoid
146 integer overflows. */
147 if (operand->flags & (S390_OPERAND_SIGNED | S390_OPERAND_PCREL))
148 {
149 unsigned int m = 1U << (operand->bits - 1);
150
151 if (val >= m)
152 ret.i = (int) (val - m) - 1 - (int) (m - 1U);
153 else
154 ret.i = (int) val;
155 }
156 else if (operand->flags & S390_OPERAND_LENGTH)
157 /* Length x in an instruction has real length x + 1. */
158 ret.u = val + 1;
1e2e8c52
AK
159
160 else if (operand->flags & S390_OPERAND_VR)
161 {
162 /* Extract the extra bits for a vector register operand stored
163 in the RXB field. */
164 unsigned vr = operand->shift == 32 ? 3
165 : (unsigned) operand->shift / 4 - 2;
166
167 ret.u = val | ((orig_insn[4] & (1 << (3 - vr))) << (vr + 1));
168 }
9ace48f3
AA
169 else
170 ret.u = val;
171
172 return ret;
173}
174
175/* Print the S390 instruction in BUFFER, assuming that it matches the
176 given OPCODE. */
177
178static void
179s390_print_insn_with_opcode (bfd_vma memaddr,
180 struct disassemble_info *info,
181 const bfd_byte *buffer,
182 const struct s390_opcode *opcode)
183{
184 const unsigned char *opindex;
185 char separator;
186
187 /* Mnemonic. */
188 info->fprintf_func (info->stream, "%s", opcode->name);
189
190 /* Operands. */
191 separator = '\t';
192 for (opindex = opcode->operands; *opindex != 0; opindex++)
193 {
194 const struct s390_operand *operand = s390_operands + *opindex;
195 union operand_value val = s390_extract_operand (buffer, operand);
196 unsigned long flags = operand->flags;
197
198 if ((flags & S390_OPERAND_INDEX) && val.u == 0)
199 continue;
200 if ((flags & S390_OPERAND_BASE) &&
201 val.u == 0 && separator == '(')
202 {
203 separator = ',';
204 continue;
205 }
206
1e2e8c52
AK
207 /* For instructions with a last optional operand don't print it
208 if zero. */
209 if ((opcode->flags & S390_INSTR_FLAG_OPTPARM)
210 && val.u == 0
211 && opindex[1] == 0)
212 break;
9ace48f3
AA
213
214 if (flags & S390_OPERAND_GPR)
1e2e8c52 215 info->fprintf_func (info->stream, "%c%%r%u", separator, val.u);
9ace48f3 216 else if (flags & S390_OPERAND_FPR)
1e2e8c52
AK
217 info->fprintf_func (info->stream, "%c%%f%u", separator, val.u);
218 else if (flags & S390_OPERAND_VR)
219 info->fprintf_func (info->stream, "%c%%v%i", separator, val.u);
9ace48f3 220 else if (flags & S390_OPERAND_AR)
1e2e8c52 221 info->fprintf_func (info->stream, "%c%%a%u", separator, val.u);
9ace48f3 222 else if (flags & S390_OPERAND_CR)
1e2e8c52 223 info->fprintf_func (info->stream, "%c%%c%u", separator, val.u);
9ace48f3 224 else if (flags & S390_OPERAND_PCREL)
1e2e8c52
AK
225 {
226 info->fprintf_func (info->stream, "%c", separator);
227 info->print_address_func (memaddr + val.i + val.i, info);
228 }
9ace48f3 229 else if (flags & S390_OPERAND_SIGNED)
1e2e8c52 230 info->fprintf_func (info->stream, "%c%i", separator, val.i);
9ace48f3 231 else
1e2e8c52
AK
232 {
233 if (flags & S390_OPERAND_OR1)
234 val.u &= ~1;
235 if (flags & S390_OPERAND_OR2)
236 val.u &= ~2;
237 if (flags & S390_OPERAND_OR8)
238 val.u &= ~8;
239
240 if ((opcode->flags & S390_INSTR_FLAG_OPTPARM)
241 && val.u == 0
242 && opindex[1] == 0)
243 break;
244 info->fprintf_func (info->stream, "%c%u", separator, val.u);
245 }
9ace48f3
AA
246
247 if (flags & S390_OPERAND_DISP)
248 separator = '(';
249 else if (flags & S390_OPERAND_BASE)
250 {
251 info->fprintf_func (info->stream, ")");
252 separator = ',';
253 }
254 else
255 separator = ',';
256 }
257}
258
259/* Check whether opcode A's mask is more specific than that of B. */
44f2a95d 260
9ace48f3
AA
261static int
262opcode_mask_more_specific (const struct s390_opcode *a,
263 const struct s390_opcode *b)
264{
265 return (((int) a->mask[0] + a->mask[1] + a->mask[2]
266 + a->mask[3] + a->mask[4] + a->mask[5])
267 > ((int) b->mask[0] + b->mask[1] + b->mask[2]
268 + b->mask[3] + b->mask[4] + b->mask[5]));
a85d7ed0
NC
269}
270
271/* Print a S390 instruction. */
272
273int
47b0e7ad 274print_insn_s390 (bfd_vma memaddr, struct disassemble_info *info)
a85d7ed0
NC
275{
276 bfd_byte buffer[6];
9ace48f3 277 const struct s390_opcode *opcode = NULL;
a85d7ed0 278 unsigned int value;
b2cc3f6f 279 int status, opsize, bufsize, bytes_to_dump, i;
a85d7ed0 280
a85d7ed0
NC
281 /* The output looks better if we put 6 bytes on a line. */
282 info->bytes_per_line = 6;
283
284 /* Every S390 instruction is max 6 bytes long. */
44f2a95d 285 memset (buffer, 0, 6);
9ace48f3 286 status = info->read_memory_func (memaddr, buffer, 6, info);
44f2a95d
KH
287 if (status != 0)
288 {
289 for (bufsize = 0; bufsize < 6; bufsize++)
9ace48f3 290 if (info->read_memory_func (memaddr, buffer, bufsize + 1, info) != 0)
44f2a95d
KH
291 break;
292 if (bufsize <= 0)
293 {
9ace48f3 294 info->memory_error_func (status, memaddr, info);
44f2a95d
KH
295 return -1;
296 }
9ace48f3 297 opsize = s390_insn_length (buffer);
44f2a95d
KH
298 status = opsize > bufsize;
299 }
300 else
301 {
302 bufsize = 6;
9ace48f3 303 opsize = s390_insn_length (buffer);
44f2a95d
KH
304 }
305
306 if (status == 0)
307 {
02cbf767
AK
308 const struct s390_opcode *op;
309
9ace48f3
AA
310 /* Find the "best match" in the opcode table. */
311 for (op = s390_opcodes + opc_index[buffer[0]];
312 op != s390_opcodes + s390_num_opcodes
313 && op->opcode[0] == buffer[0];
314 op++)
44f2a95d 315 {
9ace48f3
AA
316 if ((op->modes & current_arch_mask)
317 && s390_insn_matches_opcode (buffer, op)
318 && (opcode == NULL
319 || opcode_mask_more_specific (op, opcode)))
320 opcode = op;
44f2a95d 321 }
44f2a95d 322
b2cc3f6f
AK
323 if (opcode != NULL)
324 {
325 /* The instruction is valid. Print it and return its size. */
326 s390_print_insn_with_opcode (memaddr, info, buffer, opcode);
327 return opsize;
328 }
9ace48f3
AA
329 }
330
b2cc3f6f
AK
331 /* For code sections it makes sense to skip unknown instructions
332 according to their length bits. */
333 if (status == 0
334 && option_use_insn_len_bits_p
335 && info->section != NULL
336 && (info->section->flags & SEC_CODE))
337 bytes_to_dump = opsize;
338 else
339 /* By default unknown instructions are printed as .long's/.short'
340 depending on how many bytes are available. */
341 bytes_to_dump = bufsize >= 4 ? 4 : bufsize;
342
343 if (bytes_to_dump == 0)
344 return 0;
345
9ace48f3 346 /* Fall back to hex print. */
b2cc3f6f 347 switch (bytes_to_dump)
44f2a95d 348 {
b2cc3f6f 349 case 4:
44f2a95d
KH
350 value = (unsigned int) buffer[0];
351 value = (value << 8) + (unsigned int) buffer[1];
352 value = (value << 8) + (unsigned int) buffer[2];
353 value = (value << 8) + (unsigned int) buffer[3];
9ace48f3 354 info->fprintf_func (info->stream, ".long\t0x%08x", value);
44f2a95d 355 return 4;
b2cc3f6f 356 case 2:
44f2a95d
KH
357 value = (unsigned int) buffer[0];
358 value = (value << 8) + (unsigned int) buffer[1];
9ace48f3 359 info->fprintf_func (info->stream, ".short\t0x%04x", value);
44f2a95d 360 return 2;
b2cc3f6f
AK
361 default:
362 info->fprintf_func (info->stream, ".byte\t0x%02x",
363 (unsigned int) buffer[0]);
364 for (i = 1; i < bytes_to_dump; i++)
365 info->fprintf_func (info->stream, ",0x%02x",
366 (unsigned int) buffer[i]);
367 return bytes_to_dump;
a85d7ed0 368 }
b2cc3f6f 369 return 0;
a85d7ed0 370}
112b7c50 371
65b48a81
PB
372const disasm_options_t *
373disassembler_options_s390 (void)
374{
375 static disasm_options_t *opts = NULL;
376
377 if (opts == NULL)
378 {
379 size_t i, num_options = ARRAY_SIZE (options);
380 opts = XNEW (disasm_options_t);
381 opts->name = XNEWVEC (const char *, num_options + 1);
382 opts->description = XNEWVEC (const char *, num_options + 1);
383 for (i = 0; i < num_options; i++)
384 {
385 opts->name[i] = options[i].name;
386 opts->description[i] = _(options[i].description);
387 }
388 /* The array we return must be NULL terminated. */
389 opts->name[i] = NULL;
390 opts->description[i] = NULL;
391 }
392
393 return opts;
394}
395
112b7c50
AK
396void
397print_s390_disassembler_options (FILE *stream)
398{
65b48a81 399 unsigned int i, max_len = 0;
112b7c50
AK
400 fprintf (stream, _("\n\
401The following S/390 specific disassembler options are supported for use\n\
402with the -M switch (multiple options should be separated by commas):\n"));
403
65b48a81
PB
404 for (i = 0; i < ARRAY_SIZE (options); i++)
405 {
406 unsigned int len = strlen (options[i].name);
407 if (max_len < len)
408 max_len = len;
409 }
410
411 for (i = 0, max_len++; i < ARRAY_SIZE (options); i++)
412 fprintf (stream, " %s%*c %s\n",
413 options[i].name,
414 (int)(max_len - strlen (options[i].name)), ' ',
415 _(options[i].description));
112b7c50 416}