]> git.ipfire.org Git - thirdparty/binutils-gdb.git/blame - opcodes/s390-dis.c
This commit was manufactured by cvs2svn to create branch
[thirdparty/binutils-gdb.git] / opcodes / s390-dis.c
CommitLineData
a85d7ed0 1/* s390-dis.c -- Disassemble S390 instructions
9b201bb5 2 Copyright 2000, 2001, 2002, 2003, 2005, 2007 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
NC
21
22#include <stdio.h>
23#include "ansidecl.h"
24#include "sysdep.h"
25#include "dis-asm.h"
112b7c50 26#include "opintl.h"
a85d7ed0
NC
27#include "opcode/s390.h"
28
29static int init_flag = 0;
30static int opc_index[256];
31static int current_arch_mask = 0;
32
44f2a95d
KH
33/* Set up index table for first opcode byte. */
34
35static void
47b0e7ad 36init_disasm (struct disassemble_info *info)
a85d7ed0
NC
37{
38 const struct s390_opcode *opcode;
39 const struct s390_opcode *opcode_end;
112b7c50 40 const char *p;
a85d7ed0 41
44f2a95d 42 memset (opc_index, 0, sizeof (opc_index));
a85d7ed0 43 opcode_end = s390_opcodes + s390_num_opcodes;
44f2a95d
KH
44 for (opcode = s390_opcodes; opcode < opcode_end; opcode++)
45 {
46 opc_index[(int) opcode->opcode[0]] = opcode - s390_opcodes;
47 while ((opcode < opcode_end) &&
48 (opcode[1].opcode[0] == opcode->opcode[0]))
49 opcode++;
50 }
112b7c50
AK
51
52 for (p = info->disassembler_options; p != NULL; )
44f2a95d 53 {
112b7c50
AK
54 if (CONST_STRNEQ (p, "esa"))
55 current_arch_mask = 1 << S390_OPCODE_ESA;
56 else if (CONST_STRNEQ (p, "zarch"))
57 current_arch_mask = 1 << S390_OPCODE_ZARCH;
58 else
59 fprintf (stderr, "Unknown S/390 disassembler option: %s\n", p);
60
61 p = strchr (p, ',');
62 if (p != NULL)
63 p++;
44f2a95d 64 }
112b7c50
AK
65
66 if (!current_arch_mask)
67 switch (info->mach)
68 {
69 case bfd_mach_s390_31:
70 current_arch_mask = 1 << S390_OPCODE_ESA;
71 break;
72 case bfd_mach_s390_64:
73 current_arch_mask = 1 << S390_OPCODE_ZARCH;
74 break;
75 default:
76 abort ();
77 }
78
a85d7ed0
NC
79 init_flag = 1;
80}
81
82/* Extracts an operand value from an instruction. */
83
84static inline unsigned int
47b0e7ad 85s390_extract_operand (unsigned char *insn, const struct s390_operand *operand)
a85d7ed0
NC
86{
87 unsigned int val;
88 int bits;
89
44f2a95d
KH
90 /* Extract fragments of the operand byte for byte. */
91 insn += operand->shift / 8;
a85d7ed0
NC
92 bits = (operand->shift & 7) + operand->bits;
93 val = 0;
44f2a95d
KH
94 do
95 {
96 val <<= 8;
97 val |= (unsigned int) *insn++;
98 bits -= 8;
99 }
100 while (bits > 0);
a85d7ed0 101 val >>= -bits;
44f2a95d
KH
102 val &= ((1U << (operand->bits - 1)) << 1) - 1;
103
bac02689
MS
104 /* Check for special long displacement case. */
105 if (operand->bits == 20 && operand->shift == 20)
106 val = (val & 0xff) << 12 | (val & 0xfff00) >> 8;
107
44f2a95d
KH
108 /* Sign extend value if the operand is signed or pc relative. */
109 if ((operand->flags & (S390_OPERAND_SIGNED | S390_OPERAND_PCREL))
110 && (val & (1U << (operand->bits - 1))))
111 val |= (-1U << (operand->bits - 1)) << 1;
112
113 /* Double value if the operand is pc relative. */
a85d7ed0
NC
114 if (operand->flags & S390_OPERAND_PCREL)
115 val <<= 1;
44f2a95d 116
47b0e7ad 117 /* Length x in an instructions has real length x + 1. */
a85d7ed0
NC
118 if (operand->flags & S390_OPERAND_LENGTH)
119 val++;
120 return val;
121}
122
123/* Print a S390 instruction. */
124
125int
47b0e7ad 126print_insn_s390 (bfd_vma memaddr, struct disassemble_info *info)
a85d7ed0
NC
127{
128 bfd_byte buffer[6];
129 const struct s390_opcode *opcode;
130 const struct s390_opcode *opcode_end;
131 unsigned int value;
132 int status, opsize, bufsize;
133 char separator;
134
135 if (init_flag == 0)
44f2a95d 136 init_disasm (info);
a85d7ed0
NC
137
138 /* The output looks better if we put 6 bytes on a line. */
139 info->bytes_per_line = 6;
140
141 /* Every S390 instruction is max 6 bytes long. */
44f2a95d 142 memset (buffer, 0, 6);
a85d7ed0 143 status = (*info->read_memory_func) (memaddr, buffer, 6, info);
44f2a95d
KH
144 if (status != 0)
145 {
146 for (bufsize = 0; bufsize < 6; bufsize++)
147 if ((*info->read_memory_func) (memaddr, buffer, bufsize + 1, info) != 0)
148 break;
149 if (bufsize <= 0)
150 {
151 (*info->memory_error_func) (status, memaddr, info);
152 return -1;
153 }
154 /* Opsize calculation looks strange but it works
155 00xxxxxx -> 2 bytes, 01xxxxxx/10xxxxxx -> 4 bytes,
156 11xxxxxx -> 6 bytes. */
157 opsize = ((((buffer[0] >> 6) + 1) >> 1) + 1) << 1;
158 status = opsize > bufsize;
159 }
160 else
161 {
162 bufsize = 6;
163 opsize = ((((buffer[0] >> 6) + 1) >> 1) + 1) << 1;
164 }
165
166 if (status == 0)
167 {
168 /* Find the first match in the opcode table. */
169 opcode_end = s390_opcodes + s390_num_opcodes;
170 for (opcode = s390_opcodes + opc_index[(int) buffer[0]];
171 (opcode < opcode_end) && (buffer[0] == opcode->opcode[0]);
172 opcode++)
173 {
174 const struct s390_operand *operand;
175 const unsigned char *opindex;
176
177 /* Check architecture. */
af169f23 178 if (!(opcode->modes & current_arch_mask))
44f2a95d
KH
179 continue;
180 /* Check signature of the opcode. */
181 if ((buffer[1] & opcode->mask[1]) != opcode->opcode[1]
182 || (buffer[2] & opcode->mask[2]) != opcode->opcode[2]
183 || (buffer[3] & opcode->mask[3]) != opcode->opcode[3]
184 || (buffer[4] & opcode->mask[4]) != opcode->opcode[4]
185 || (buffer[5] & opcode->mask[5]) != opcode->opcode[5])
186 continue;
187
188 /* The instruction is valid. */
189 if (opcode->operands[0] != 0)
190 (*info->fprintf_func) (info->stream, "%s\t", opcode->name);
191 else
192 (*info->fprintf_func) (info->stream, "%s", opcode->name);
193
194 /* Extract the operands. */
195 separator = 0;
196 for (opindex = opcode->operands; *opindex != 0; opindex++)
197 {
198 unsigned int value;
199
200 operand = s390_operands + *opindex;
201 value = s390_extract_operand (buffer, operand);
202
203 if ((operand->flags & S390_OPERAND_INDEX) && value == 0)
204 continue;
205 if ((operand->flags & S390_OPERAND_BASE) &&
206 value == 0 && separator == '(')
207 {
208 separator = ',';
209 continue;
210 }
211
212 if (separator)
213 (*info->fprintf_func) (info->stream, "%c", separator);
214
215 if (operand->flags & S390_OPERAND_GPR)
216 (*info->fprintf_func) (info->stream, "%%r%i", value);
217 else if (operand->flags & S390_OPERAND_FPR)
218 (*info->fprintf_func) (info->stream, "%%f%i", value);
219 else if (operand->flags & S390_OPERAND_AR)
220 (*info->fprintf_func) (info->stream, "%%a%i", value);
221 else if (operand->flags & S390_OPERAND_CR)
222 (*info->fprintf_func) (info->stream, "%%c%i", value);
223 else if (operand->flags & S390_OPERAND_PCREL)
224 (*info->print_address_func) (memaddr + (int) value, info);
225 else if (operand->flags & S390_OPERAND_SIGNED)
226 (*info->fprintf_func) (info->stream, "%i", (int) value);
227 else
ad101263 228 (*info->fprintf_func) (info->stream, "%u", value);
44f2a95d
KH
229
230 if (operand->flags & S390_OPERAND_DISP)
231 {
232 separator = '(';
233 }
234 else if (operand->flags & S390_OPERAND_BASE)
235 {
236 (*info->fprintf_func) (info->stream, ")");
237 separator = ',';
238 }
239 else
240 separator = ',';
241 }
242
243 /* Found instruction, printed it, return its size. */
244 return opsize;
245 }
246 /* No matching instruction found, fall through to hex print. */
247 }
248
249 if (bufsize >= 4)
250 {
251 value = (unsigned int) buffer[0];
252 value = (value << 8) + (unsigned int) buffer[1];
253 value = (value << 8) + (unsigned int) buffer[2];
254 value = (value << 8) + (unsigned int) buffer[3];
255 (*info->fprintf_func) (info->stream, ".long\t0x%08x", value);
256 return 4;
257 }
258 else if (bufsize >= 2)
259 {
260 value = (unsigned int) buffer[0];
261 value = (value << 8) + (unsigned int) buffer[1];
262 (*info->fprintf_func) (info->stream, ".short\t0x%04x", value);
263 return 2;
a85d7ed0 264 }
44f2a95d
KH
265 else
266 {
267 value = (unsigned int) buffer[0];
268 (*info->fprintf_func) (info->stream, ".byte\t0x%02x", value);
269 return 1;
a85d7ed0 270 }
a85d7ed0 271}
112b7c50
AK
272
273void
274print_s390_disassembler_options (FILE *stream)
275{
276 fprintf (stream, _("\n\
277The following S/390 specific disassembler options are supported for use\n\
278with the -M switch (multiple options should be separated by commas):\n"));
279
280 fprintf (stream, _(" esa Disassemble in ESA architecture mode\n"));
281 fprintf (stream, _(" zarch Disassemble in z/Architecture mode\n"));
282}