2008-04-10 Andreas Krebbel <krebbel1@de.ibm.com>
[deliverable/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"
26#include "opcode/s390.h"
27
28static int init_flag = 0;
29static int opc_index[256];
30static int current_arch_mask = 0;
31
44f2a95d
KH
32/* Set up index table for first opcode byte. */
33
34static void
47b0e7ad 35init_disasm (struct disassemble_info *info)
a85d7ed0
NC
36{
37 const struct s390_opcode *opcode;
38 const struct s390_opcode *opcode_end;
39
44f2a95d 40 memset (opc_index, 0, sizeof (opc_index));
a85d7ed0 41 opcode_end = s390_opcodes + s390_num_opcodes;
44f2a95d
KH
42 for (opcode = s390_opcodes; opcode < opcode_end; opcode++)
43 {
44 opc_index[(int) opcode->opcode[0]] = opcode - s390_opcodes;
45 while ((opcode < opcode_end) &&
46 (opcode[1].opcode[0] == opcode->opcode[0]))
47 opcode++;
48 }
49 switch (info->mach)
50 {
45b38a80 51 case bfd_mach_s390_31:
44f2a95d
KH
52 current_arch_mask = 1 << S390_OPCODE_ESA;
53 break;
45b38a80 54 case bfd_mach_s390_64:
af169f23 55 current_arch_mask = 1 << S390_OPCODE_ZARCH;
44f2a95d
KH
56 break;
57 default:
58 abort ();
59 }
a85d7ed0
NC
60 init_flag = 1;
61}
62
63/* Extracts an operand value from an instruction. */
64
65static inline unsigned int
47b0e7ad 66s390_extract_operand (unsigned char *insn, const struct s390_operand *operand)
a85d7ed0
NC
67{
68 unsigned int val;
69 int bits;
70
44f2a95d
KH
71 /* Extract fragments of the operand byte for byte. */
72 insn += operand->shift / 8;
a85d7ed0
NC
73 bits = (operand->shift & 7) + operand->bits;
74 val = 0;
44f2a95d
KH
75 do
76 {
77 val <<= 8;
78 val |= (unsigned int) *insn++;
79 bits -= 8;
80 }
81 while (bits > 0);
a85d7ed0 82 val >>= -bits;
44f2a95d
KH
83 val &= ((1U << (operand->bits - 1)) << 1) - 1;
84
bac02689
MS
85 /* Check for special long displacement case. */
86 if (operand->bits == 20 && operand->shift == 20)
87 val = (val & 0xff) << 12 | (val & 0xfff00) >> 8;
88
44f2a95d
KH
89 /* Sign extend value if the operand is signed or pc relative. */
90 if ((operand->flags & (S390_OPERAND_SIGNED | S390_OPERAND_PCREL))
91 && (val & (1U << (operand->bits - 1))))
92 val |= (-1U << (operand->bits - 1)) << 1;
93
94 /* Double value if the operand is pc relative. */
a85d7ed0
NC
95 if (operand->flags & S390_OPERAND_PCREL)
96 val <<= 1;
44f2a95d 97
47b0e7ad 98 /* Length x in an instructions has real length x + 1. */
a85d7ed0
NC
99 if (operand->flags & S390_OPERAND_LENGTH)
100 val++;
101 return val;
102}
103
104/* Print a S390 instruction. */
105
106int
47b0e7ad 107print_insn_s390 (bfd_vma memaddr, struct disassemble_info *info)
a85d7ed0
NC
108{
109 bfd_byte buffer[6];
110 const struct s390_opcode *opcode;
111 const struct s390_opcode *opcode_end;
112 unsigned int value;
113 int status, opsize, bufsize;
114 char separator;
115
116 if (init_flag == 0)
44f2a95d 117 init_disasm (info);
a85d7ed0
NC
118
119 /* The output looks better if we put 6 bytes on a line. */
120 info->bytes_per_line = 6;
121
122 /* Every S390 instruction is max 6 bytes long. */
44f2a95d 123 memset (buffer, 0, 6);
a85d7ed0 124 status = (*info->read_memory_func) (memaddr, buffer, 6, info);
44f2a95d
KH
125 if (status != 0)
126 {
127 for (bufsize = 0; bufsize < 6; bufsize++)
128 if ((*info->read_memory_func) (memaddr, buffer, bufsize + 1, info) != 0)
129 break;
130 if (bufsize <= 0)
131 {
132 (*info->memory_error_func) (status, memaddr, info);
133 return -1;
134 }
135 /* Opsize calculation looks strange but it works
136 00xxxxxx -> 2 bytes, 01xxxxxx/10xxxxxx -> 4 bytes,
137 11xxxxxx -> 6 bytes. */
138 opsize = ((((buffer[0] >> 6) + 1) >> 1) + 1) << 1;
139 status = opsize > bufsize;
140 }
141 else
142 {
143 bufsize = 6;
144 opsize = ((((buffer[0] >> 6) + 1) >> 1) + 1) << 1;
145 }
146
147 if (status == 0)
148 {
149 /* Find the first match in the opcode table. */
150 opcode_end = s390_opcodes + s390_num_opcodes;
151 for (opcode = s390_opcodes + opc_index[(int) buffer[0]];
152 (opcode < opcode_end) && (buffer[0] == opcode->opcode[0]);
153 opcode++)
154 {
155 const struct s390_operand *operand;
156 const unsigned char *opindex;
157
158 /* Check architecture. */
af169f23 159 if (!(opcode->modes & current_arch_mask))
44f2a95d
KH
160 continue;
161 /* Check signature of the opcode. */
162 if ((buffer[1] & opcode->mask[1]) != opcode->opcode[1]
163 || (buffer[2] & opcode->mask[2]) != opcode->opcode[2]
164 || (buffer[3] & opcode->mask[3]) != opcode->opcode[3]
165 || (buffer[4] & opcode->mask[4]) != opcode->opcode[4]
166 || (buffer[5] & opcode->mask[5]) != opcode->opcode[5])
167 continue;
168
169 /* The instruction is valid. */
170 if (opcode->operands[0] != 0)
171 (*info->fprintf_func) (info->stream, "%s\t", opcode->name);
172 else
173 (*info->fprintf_func) (info->stream, "%s", opcode->name);
174
175 /* Extract the operands. */
176 separator = 0;
177 for (opindex = opcode->operands; *opindex != 0; opindex++)
178 {
179 unsigned int value;
180
181 operand = s390_operands + *opindex;
182 value = s390_extract_operand (buffer, operand);
183
184 if ((operand->flags & S390_OPERAND_INDEX) && value == 0)
185 continue;
186 if ((operand->flags & S390_OPERAND_BASE) &&
187 value == 0 && separator == '(')
188 {
189 separator = ',';
190 continue;
191 }
192
193 if (separator)
194 (*info->fprintf_func) (info->stream, "%c", separator);
195
196 if (operand->flags & S390_OPERAND_GPR)
197 (*info->fprintf_func) (info->stream, "%%r%i", value);
198 else if (operand->flags & S390_OPERAND_FPR)
199 (*info->fprintf_func) (info->stream, "%%f%i", value);
200 else if (operand->flags & S390_OPERAND_AR)
201 (*info->fprintf_func) (info->stream, "%%a%i", value);
202 else if (operand->flags & S390_OPERAND_CR)
203 (*info->fprintf_func) (info->stream, "%%c%i", value);
204 else if (operand->flags & S390_OPERAND_PCREL)
205 (*info->print_address_func) (memaddr + (int) value, info);
206 else if (operand->flags & S390_OPERAND_SIGNED)
207 (*info->fprintf_func) (info->stream, "%i", (int) value);
208 else
ad101263 209 (*info->fprintf_func) (info->stream, "%u", value);
44f2a95d
KH
210
211 if (operand->flags & S390_OPERAND_DISP)
212 {
213 separator = '(';
214 }
215 else if (operand->flags & S390_OPERAND_BASE)
216 {
217 (*info->fprintf_func) (info->stream, ")");
218 separator = ',';
219 }
220 else
221 separator = ',';
222 }
223
224 /* Found instruction, printed it, return its size. */
225 return opsize;
226 }
227 /* No matching instruction found, fall through to hex print. */
228 }
229
230 if (bufsize >= 4)
231 {
232 value = (unsigned int) buffer[0];
233 value = (value << 8) + (unsigned int) buffer[1];
234 value = (value << 8) + (unsigned int) buffer[2];
235 value = (value << 8) + (unsigned int) buffer[3];
236 (*info->fprintf_func) (info->stream, ".long\t0x%08x", value);
237 return 4;
238 }
239 else if (bufsize >= 2)
240 {
241 value = (unsigned int) buffer[0];
242 value = (value << 8) + (unsigned int) buffer[1];
243 (*info->fprintf_func) (info->stream, ".short\t0x%04x", value);
244 return 2;
a85d7ed0 245 }
44f2a95d
KH
246 else
247 {
248 value = (unsigned int) buffer[0];
249 (*info->fprintf_func) (info->stream, ".byte\t0x%02x", value);
250 return 1;
a85d7ed0 251 }
a85d7ed0 252}
This page took 0.774097 seconds and 4 git commands to generate.