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