1 /* s390-dis.c -- Disassemble S390 instructions
2 Copyright (C) 2000-2014 Free Software Foundation, Inc.
3 Contributed by Martin Schwidefsky (schwidefsky@de.ibm.com).
5 This file is part of the GNU opcodes library.
7 This library is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 3, or (at your option)
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.
17 You should have received a copy of the GNU General Public License
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. */
27 #include "opcode/s390.h"
29 static int init_flag
= 0;
30 static int opc_index
[256];
31 static int current_arch_mask
= 0;
33 /* Set up index table for first opcode byte. */
36 init_disasm (struct disassemble_info
*info
)
38 const struct s390_opcode
*opcode
;
39 const struct s390_opcode
*opcode_end
;
42 memset (opc_index
, 0, sizeof (opc_index
));
43 opcode_end
= s390_opcodes
+ s390_num_opcodes
;
44 for (opcode
= s390_opcodes
; opcode
< opcode_end
; opcode
++)
46 opc_index
[(int) opcode
->opcode
[0]] = opcode
- s390_opcodes
;
47 while ((opcode
< opcode_end
) &&
48 (opcode
[1].opcode
[0] == opcode
->opcode
[0]))
52 for (p
= info
->disassembler_options
; p
!= NULL
; )
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
;
59 fprintf (stderr
, "Unknown S/390 disassembler option: %s\n", p
);
66 if (!current_arch_mask
)
67 current_arch_mask
= 1 << S390_OPCODE_ZARCH
;
72 /* Extracts an operand value from an instruction. */
73 /* We do not perform the shift operation for larl-type address
74 operands here since that would lead to an overflow of the 32 bit
75 integer value. Instead the shift operation is done when printing
76 the operand in print_insn_s390. */
78 static inline unsigned int
79 s390_extract_operand (unsigned char *insn
, const struct s390_operand
*operand
)
84 /* Extract fragments of the operand byte for byte. */
85 insn
+= operand
->shift
/ 8;
86 bits
= (operand
->shift
& 7) + operand
->bits
;
91 val
|= (unsigned int) *insn
++;
96 val
&= ((1U << (operand
->bits
- 1)) << 1) - 1;
98 /* Check for special long displacement case. */
99 if (operand
->bits
== 20 && operand
->shift
== 20)
100 val
= (val
& 0xff) << 12 | (val
& 0xfff00) >> 8;
102 /* Sign extend value if the operand is signed or pc relative. */
103 if ((operand
->flags
& (S390_OPERAND_SIGNED
| S390_OPERAND_PCREL
))
104 && (val
& (1U << (operand
->bits
- 1))))
105 val
|= (-1U << (operand
->bits
- 1)) << 1;
107 /* Length x in an instructions has real length x + 1. */
108 if (operand
->flags
& S390_OPERAND_LENGTH
)
113 /* Print a S390 instruction. */
116 print_insn_s390 (bfd_vma memaddr
, struct disassemble_info
*info
)
119 const struct s390_opcode
*opcode
;
120 const struct s390_opcode
*opcode_end
;
122 int status
, opsize
, bufsize
;
128 /* The output looks better if we put 6 bytes on a line. */
129 info
->bytes_per_line
= 6;
131 /* Every S390 instruction is max 6 bytes long. */
132 memset (buffer
, 0, 6);
133 status
= (*info
->read_memory_func
) (memaddr
, buffer
, 6, info
);
136 for (bufsize
= 0; bufsize
< 6; bufsize
++)
137 if ((*info
->read_memory_func
) (memaddr
, buffer
, bufsize
+ 1, info
) != 0)
141 (*info
->memory_error_func
) (status
, memaddr
, info
);
144 /* Opsize calculation looks strange but it works
145 00xxxxxx -> 2 bytes, 01xxxxxx/10xxxxxx -> 4 bytes,
146 11xxxxxx -> 6 bytes. */
147 opsize
= ((((buffer
[0] >> 6) + 1) >> 1) + 1) << 1;
148 status
= opsize
> bufsize
;
153 opsize
= ((((buffer
[0] >> 6) + 1) >> 1) + 1) << 1;
158 const struct s390_opcode
*op
;
160 /* Find the first match in the opcode table. */
161 opcode_end
= s390_opcodes
+ s390_num_opcodes
;
162 for (opcode
= s390_opcodes
+ opc_index
[(int) buffer
[0]];
163 (opcode
< opcode_end
) && (buffer
[0] == opcode
->opcode
[0]);
166 const struct s390_operand
*operand
;
167 const unsigned char *opindex
;
169 /* Check architecture. */
170 if (!(opcode
->modes
& current_arch_mask
))
173 /* Check signature of the opcode. */
174 if ((buffer
[1] & opcode
->mask
[1]) != opcode
->opcode
[1]
175 || (buffer
[2] & opcode
->mask
[2]) != opcode
->opcode
[2]
176 || (buffer
[3] & opcode
->mask
[3]) != opcode
->opcode
[3]
177 || (buffer
[4] & opcode
->mask
[4]) != opcode
->opcode
[4]
178 || (buffer
[5] & opcode
->mask
[5]) != opcode
->opcode
[5])
181 /* Advance to an opcode with a more specific mask. */
182 for (op
= opcode
+ 1; op
< opcode_end
; op
++)
184 if ((buffer
[0] & op
->mask
[0]) != op
->opcode
[0])
187 if ((buffer
[1] & op
->mask
[1]) != op
->opcode
[1]
188 || (buffer
[2] & op
->mask
[2]) != op
->opcode
[2]
189 || (buffer
[3] & op
->mask
[3]) != op
->opcode
[3]
190 || (buffer
[4] & op
->mask
[4]) != op
->opcode
[4]
191 || (buffer
[5] & op
->mask
[5]) != op
->opcode
[5])
194 if (((int)opcode
->mask
[0] + opcode
->mask
[1] +
195 opcode
->mask
[2] + opcode
->mask
[3] +
196 opcode
->mask
[4] + opcode
->mask
[5]) <
197 ((int)op
->mask
[0] + op
->mask
[1] +
198 op
->mask
[2] + op
->mask
[3] +
199 op
->mask
[4] + op
->mask
[5]))
203 /* The instruction is valid. */
204 if (opcode
->operands
[0] != 0)
205 (*info
->fprintf_func
) (info
->stream
, "%s\t", opcode
->name
);
207 (*info
->fprintf_func
) (info
->stream
, "%s", opcode
->name
);
209 /* Extract the operands. */
211 for (opindex
= opcode
->operands
; *opindex
!= 0; opindex
++)
213 operand
= s390_operands
+ *opindex
;
214 value
= s390_extract_operand (buffer
, operand
);
216 if ((operand
->flags
& S390_OPERAND_INDEX
) && value
== 0)
218 if ((operand
->flags
& S390_OPERAND_BASE
) &&
219 value
== 0 && separator
== '(')
226 (*info
->fprintf_func
) (info
->stream
, "%c", separator
);
228 if (operand
->flags
& S390_OPERAND_GPR
)
229 (*info
->fprintf_func
) (info
->stream
, "%%r%i", value
);
230 else if (operand
->flags
& S390_OPERAND_FPR
)
231 (*info
->fprintf_func
) (info
->stream
, "%%f%i", value
);
232 else if (operand
->flags
& S390_OPERAND_AR
)
233 (*info
->fprintf_func
) (info
->stream
, "%%a%i", value
);
234 else if (operand
->flags
& S390_OPERAND_CR
)
235 (*info
->fprintf_func
) (info
->stream
, "%%c%i", value
);
236 else if (operand
->flags
& S390_OPERAND_PCREL
)
237 (*info
->print_address_func
) (memaddr
+ (int)value
+ (int)value
,
239 else if (operand
->flags
& S390_OPERAND_SIGNED
)
240 (*info
->fprintf_func
) (info
->stream
, "%i", (int) value
);
242 (*info
->fprintf_func
) (info
->stream
, "%u", value
);
244 if (operand
->flags
& S390_OPERAND_DISP
)
248 else if (operand
->flags
& S390_OPERAND_BASE
)
250 (*info
->fprintf_func
) (info
->stream
, ")");
257 /* Found instruction, printed it, return its size. */
260 /* No matching instruction found, fall through to hex print. */
265 value
= (unsigned int) buffer
[0];
266 value
= (value
<< 8) + (unsigned int) buffer
[1];
267 value
= (value
<< 8) + (unsigned int) buffer
[2];
268 value
= (value
<< 8) + (unsigned int) buffer
[3];
269 (*info
->fprintf_func
) (info
->stream
, ".long\t0x%08x", value
);
272 else if (bufsize
>= 2)
274 value
= (unsigned int) buffer
[0];
275 value
= (value
<< 8) + (unsigned int) buffer
[1];
276 (*info
->fprintf_func
) (info
->stream
, ".short\t0x%04x", value
);
281 value
= (unsigned int) buffer
[0];
282 (*info
->fprintf_func
) (info
->stream
, ".byte\t0x%02x", value
);
288 print_s390_disassembler_options (FILE *stream
)
290 fprintf (stream
, _("\n\
291 The following S/390 specific disassembler options are supported for use\n\
292 with the -M switch (multiple options should be separated by commas):\n"));
294 fprintf (stream
, _(" esa Disassemble in ESA architecture mode\n"));
295 fprintf (stream
, _(" zarch Disassemble in z/Architecture mode\n"));
This page took 0.047725 seconds and 4 git commands to generate.