* libtool.m4 (_LT_ENABLE_LOCK <ld -m flags>): Remove non-canonical
[deliverable/binutils-gdb.git] / opcodes / s390-dis.c
CommitLineData
a85d7ed0 1/* s390-dis.c -- Disassemble S390 instructions
df7b86aa 2 Copyright 2000, 2001, 2002, 2003, 2005, 2007, 2008, 2012
aa820537 3 Free Software Foundation, Inc.
a85d7ed0
NC
4 Contributed by Martin Schwidefsky (schwidefsky@de.ibm.com).
5
9b201bb5 6 This file is part of the GNU opcodes library.
a85d7ed0 7
9b201bb5 8 This library is free software; you can redistribute it and/or modify
a85d7ed0 9 it under the terms of the GNU General Public License as published by
9b201bb5
NC
10 the Free Software Foundation; either version 3, or (at your option)
11 any later version.
a85d7ed0 12
9b201bb5
NC
13 It is distributed in the hope that it will be useful, but WITHOUT
14 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
15 or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
16 License for more details.
a85d7ed0
NC
17
18 You should have received a copy of the GNU General Public License
9b201bb5
NC
19 along with this file; see the file COPYING. If not, write to the
20 Free Software Foundation, 51 Franklin Street - Fifth Floor, Boston,
21 MA 02110-1301, USA. */
a85d7ed0 22
df7b86aa 23#include "sysdep.h"
a85d7ed0
NC
24#include <stdio.h>
25#include "ansidecl.h"
a85d7ed0 26#include "dis-asm.h"
112b7c50 27#include "opintl.h"
a85d7ed0
NC
28#include "opcode/s390.h"
29
30static int init_flag = 0;
31static int opc_index[256];
32static int current_arch_mask = 0;
33
44f2a95d
KH
34/* Set up index table for first opcode byte. */
35
36static void
47b0e7ad 37init_disasm (struct disassemble_info *info)
a85d7ed0
NC
38{
39 const struct s390_opcode *opcode;
40 const struct s390_opcode *opcode_end;
112b7c50 41 const char *p;
a85d7ed0 42
44f2a95d 43 memset (opc_index, 0, sizeof (opc_index));
a85d7ed0 44 opcode_end = s390_opcodes + s390_num_opcodes;
44f2a95d
KH
45 for (opcode = s390_opcodes; opcode < opcode_end; opcode++)
46 {
47 opc_index[(int) opcode->opcode[0]] = opcode - s390_opcodes;
48 while ((opcode < opcode_end) &&
49 (opcode[1].opcode[0] == opcode->opcode[0]))
50 opcode++;
51 }
112b7c50
AK
52
53 for (p = info->disassembler_options; p != NULL; )
44f2a95d 54 {
112b7c50
AK
55 if (CONST_STRNEQ (p, "esa"))
56 current_arch_mask = 1 << S390_OPCODE_ESA;
57 else if (CONST_STRNEQ (p, "zarch"))
58 current_arch_mask = 1 << S390_OPCODE_ZARCH;
59 else
60 fprintf (stderr, "Unknown S/390 disassembler option: %s\n", p);
61
62 p = strchr (p, ',');
63 if (p != NULL)
64 p++;
44f2a95d 65 }
112b7c50
AK
66
67 if (!current_arch_mask)
68 switch (info->mach)
69 {
70 case bfd_mach_s390_31:
71 current_arch_mask = 1 << S390_OPCODE_ESA;
72 break;
73 case bfd_mach_s390_64:
74 current_arch_mask = 1 << S390_OPCODE_ZARCH;
75 break;
76 default:
77 abort ();
78 }
79
a85d7ed0
NC
80 init_flag = 1;
81}
82
83/* Extracts an operand value from an instruction. */
7330f9c3
AK
84/* We do not perform the shift operation for larl-type address
85 operands here since that would lead to an overflow of the 32 bit
86 integer value. Instead the shift operation is done when printing
87 the operand in print_insn_s390. */
a85d7ed0
NC
88
89static inline unsigned int
47b0e7ad 90s390_extract_operand (unsigned char *insn, const struct s390_operand *operand)
a85d7ed0
NC
91{
92 unsigned int val;
93 int bits;
94
44f2a95d
KH
95 /* Extract fragments of the operand byte for byte. */
96 insn += operand->shift / 8;
a85d7ed0
NC
97 bits = (operand->shift & 7) + operand->bits;
98 val = 0;
44f2a95d
KH
99 do
100 {
101 val <<= 8;
102 val |= (unsigned int) *insn++;
103 bits -= 8;
104 }
105 while (bits > 0);
a85d7ed0 106 val >>= -bits;
44f2a95d
KH
107 val &= ((1U << (operand->bits - 1)) << 1) - 1;
108
bac02689
MS
109 /* Check for special long displacement case. */
110 if (operand->bits == 20 && operand->shift == 20)
111 val = (val & 0xff) << 12 | (val & 0xfff00) >> 8;
112
44f2a95d
KH
113 /* Sign extend value if the operand is signed or pc relative. */
114 if ((operand->flags & (S390_OPERAND_SIGNED | S390_OPERAND_PCREL))
115 && (val & (1U << (operand->bits - 1))))
116 val |= (-1U << (operand->bits - 1)) << 1;
117
47b0e7ad 118 /* Length x in an instructions has real length x + 1. */
a85d7ed0
NC
119 if (operand->flags & S390_OPERAND_LENGTH)
120 val++;
121 return val;
122}
123
124/* Print a S390 instruction. */
125
126int
47b0e7ad 127print_insn_s390 (bfd_vma memaddr, struct disassemble_info *info)
a85d7ed0
NC
128{
129 bfd_byte buffer[6];
130 const struct s390_opcode *opcode;
131 const struct s390_opcode *opcode_end;
132 unsigned int value;
133 int status, opsize, bufsize;
134 char separator;
135
136 if (init_flag == 0)
44f2a95d 137 init_disasm (info);
a85d7ed0
NC
138
139 /* The output looks better if we put 6 bytes on a line. */
140 info->bytes_per_line = 6;
141
142 /* Every S390 instruction is max 6 bytes long. */
44f2a95d 143 memset (buffer, 0, 6);
a85d7ed0 144 status = (*info->read_memory_func) (memaddr, buffer, 6, info);
44f2a95d
KH
145 if (status != 0)
146 {
147 for (bufsize = 0; bufsize < 6; bufsize++)
148 if ((*info->read_memory_func) (memaddr, buffer, bufsize + 1, info) != 0)
149 break;
150 if (bufsize <= 0)
151 {
152 (*info->memory_error_func) (status, memaddr, info);
153 return -1;
154 }
155 /* Opsize calculation looks strange but it works
156 00xxxxxx -> 2 bytes, 01xxxxxx/10xxxxxx -> 4 bytes,
157 11xxxxxx -> 6 bytes. */
158 opsize = ((((buffer[0] >> 6) + 1) >> 1) + 1) << 1;
159 status = opsize > bufsize;
160 }
161 else
162 {
163 bufsize = 6;
164 opsize = ((((buffer[0] >> 6) + 1) >> 1) + 1) << 1;
165 }
166
167 if (status == 0)
168 {
02cbf767
AK
169 const struct s390_opcode *op;
170
44f2a95d
KH
171 /* Find the first match in the opcode table. */
172 opcode_end = s390_opcodes + s390_num_opcodes;
173 for (opcode = s390_opcodes + opc_index[(int) buffer[0]];
174 (opcode < opcode_end) && (buffer[0] == opcode->opcode[0]);
175 opcode++)
176 {
177 const struct s390_operand *operand;
178 const unsigned char *opindex;
179
180 /* Check architecture. */
af169f23 181 if (!(opcode->modes & current_arch_mask))
44f2a95d 182 continue;
02cbf767 183
44f2a95d
KH
184 /* Check signature of the opcode. */
185 if ((buffer[1] & opcode->mask[1]) != opcode->opcode[1]
186 || (buffer[2] & opcode->mask[2]) != opcode->opcode[2]
187 || (buffer[3] & opcode->mask[3]) != opcode->opcode[3]
188 || (buffer[4] & opcode->mask[4]) != opcode->opcode[4]
189 || (buffer[5] & opcode->mask[5]) != opcode->opcode[5])
190 continue;
191
02cbf767
AK
192 /* Advance to an opcode with a more specific mask. */
193 for (op = opcode + 1; op < opcode_end; op++)
194 {
195 if ((buffer[0] & op->mask[0]) != op->opcode[0])
196 break;
197
198 if ((buffer[1] & op->mask[1]) != op->opcode[1]
199 || (buffer[2] & op->mask[2]) != op->opcode[2]
200 || (buffer[3] & op->mask[3]) != op->opcode[3]
201 || (buffer[4] & op->mask[4]) != op->opcode[4]
202 || (buffer[5] & op->mask[5]) != op->opcode[5])
203 continue;
204
205 if (((int)opcode->mask[0] + opcode->mask[1] +
206 opcode->mask[2] + opcode->mask[3] +
207 opcode->mask[4] + opcode->mask[5]) <
208 ((int)op->mask[0] + op->mask[1] +
209 op->mask[2] + op->mask[3] +
210 op->mask[4] + op->mask[5]))
211 opcode = op;
212 }
213
44f2a95d
KH
214 /* The instruction is valid. */
215 if (opcode->operands[0] != 0)
216 (*info->fprintf_func) (info->stream, "%s\t", opcode->name);
217 else
218 (*info->fprintf_func) (info->stream, "%s", opcode->name);
219
220 /* Extract the operands. */
221 separator = 0;
222 for (opindex = opcode->operands; *opindex != 0; opindex++)
223 {
44f2a95d
KH
224 operand = s390_operands + *opindex;
225 value = s390_extract_operand (buffer, operand);
226
227 if ((operand->flags & S390_OPERAND_INDEX) && value == 0)
228 continue;
229 if ((operand->flags & S390_OPERAND_BASE) &&
230 value == 0 && separator == '(')
231 {
232 separator = ',';
233 continue;
234 }
235
236 if (separator)
237 (*info->fprintf_func) (info->stream, "%c", separator);
238
239 if (operand->flags & S390_OPERAND_GPR)
240 (*info->fprintf_func) (info->stream, "%%r%i", value);
241 else if (operand->flags & S390_OPERAND_FPR)
242 (*info->fprintf_func) (info->stream, "%%f%i", value);
243 else if (operand->flags & S390_OPERAND_AR)
244 (*info->fprintf_func) (info->stream, "%%a%i", value);
245 else if (operand->flags & S390_OPERAND_CR)
246 (*info->fprintf_func) (info->stream, "%%c%i", value);
247 else if (operand->flags & S390_OPERAND_PCREL)
c8676ae4
AK
248 (*info->print_address_func) (memaddr + (int)value + (int)value,
249 info);
44f2a95d
KH
250 else if (operand->flags & S390_OPERAND_SIGNED)
251 (*info->fprintf_func) (info->stream, "%i", (int) value);
252 else
ad101263 253 (*info->fprintf_func) (info->stream, "%u", value);
44f2a95d
KH
254
255 if (operand->flags & S390_OPERAND_DISP)
256 {
257 separator = '(';
258 }
259 else if (operand->flags & S390_OPERAND_BASE)
260 {
261 (*info->fprintf_func) (info->stream, ")");
262 separator = ',';
263 }
264 else
265 separator = ',';
266 }
267
268 /* Found instruction, printed it, return its size. */
269 return opsize;
270 }
271 /* No matching instruction found, fall through to hex print. */
272 }
273
274 if (bufsize >= 4)
275 {
276 value = (unsigned int) buffer[0];
277 value = (value << 8) + (unsigned int) buffer[1];
278 value = (value << 8) + (unsigned int) buffer[2];
279 value = (value << 8) + (unsigned int) buffer[3];
280 (*info->fprintf_func) (info->stream, ".long\t0x%08x", value);
281 return 4;
282 }
283 else if (bufsize >= 2)
284 {
285 value = (unsigned int) buffer[0];
286 value = (value << 8) + (unsigned int) buffer[1];
287 (*info->fprintf_func) (info->stream, ".short\t0x%04x", value);
288 return 2;
a85d7ed0 289 }
44f2a95d
KH
290 else
291 {
292 value = (unsigned int) buffer[0];
293 (*info->fprintf_func) (info->stream, ".byte\t0x%02x", value);
294 return 1;
a85d7ed0 295 }
a85d7ed0 296}
112b7c50
AK
297
298void
299print_s390_disassembler_options (FILE *stream)
300{
301 fprintf (stream, _("\n\
302The following S/390 specific disassembler options are supported for use\n\
303with the -M switch (multiple options should be separated by commas):\n"));
304
305 fprintf (stream, _(" esa Disassemble in ESA architecture mode\n"));
306 fprintf (stream, _(" zarch Disassemble in z/Architecture mode\n"));
307}
This page took 0.691787 seconds and 4 git commands to generate.