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