1/* s390-dis.c -- Disassemble S390 instructions 2 Copyright 2000, 2001, 2002, 2003, 2005, 2007, 2008 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 <stdio.h> 24#include "ansidecl.h" 25#include "sysdep.h" 26#include "dis-asm.h" 27#include "opintl.h" 28#include "opcode/s390.h" 29 30static int init_flag = 0; 31static int opc_index[256]; 32static int current_arch_mask = 0; 33 34/* Set up index table for first opcode byte. */ 35 36static void 37init_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 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 80 init_flag = 1; 81} 82 83/* Extracts an operand value from an instruction. */ 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. */ 88 89static inline unsigned int 90s390_extract_operand (unsigned char *insn, const struct s390_operand *operand) 91{ 92 unsigned int val; 93 int bits; 94 95 /* Extract fragments of the operand byte for byte. */ 96 insn += operand->shift / 8; 97 bits = (operand->shift & 7) + operand->bits; 98 val = 0; 99 do 100 { 101 val <<= 8; 102 val |= (unsigned int) *insn++; 103 bits -= 8; 104 } 105 while (bits > 0); 106 val >>= -bits; 107 val &= ((1U << (operand->bits - 1)) << 1) - 1; 108 109 /* Check for special long displacement case. */ 110 if (operand->bits == 20 && operand->shift == 20) 111 val = (val & 0xff) << 12 | (val & 0xfff00) >> 8; 112 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 118 /* Length x in an instructions has real length x + 1. */ 119 if (operand->flags & S390_OPERAND_LENGTH) 120 val++; 121 return val; 122} 123 124/* Print a S390 instruction. */ 125 126int 127print_insn_s390 (bfd_vma memaddr, struct disassemble_info *info) 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) 137 init_disasm (info); 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. */ 143 memset (buffer, 0, 6); 144 status = (*info->read_memory_func) (memaddr, buffer, 6, info); 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 { 169 const struct s390_opcode *op; 170 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. */ 181 if (!(opcode->modes & current_arch_mask)) 182 continue; 183 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 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 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 { 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) 248 (*info->print_address_func) (memaddr + (int)value + (int)value, 249 info); 250 else if (operand->flags & S390_OPERAND_SIGNED) 251 (*info->fprintf_func) (info->stream, "%i", (int) value); 252 else 253 (*info->fprintf_func) (info->stream, "%u", value); 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; 289 } 290 else 291 { 292 value = (unsigned int) buffer[0]; 293 (*info->fprintf_func) (info->stream, ".byte\t0x%02x", value); 294 return 1; 295 } 296} 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} 308