1 /* s390-dis.c -- Disassemble S390 instructions 2 Copyright (C) 2000-2018 Free Software Foundation, Inc. 3 Contributed by Martin Schwidefsky (schwidefsky@de.ibm.com). 4 5 This file is part of the GNU opcodes library. 6 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) 10 any later version. 11 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. 16 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. */ 21 22 #include "sysdep.h" 23 #include <stdio.h> 24 #include "ansidecl.h" 25 #include "disassemble.h" 26 #include "opintl.h" 27 #include "opcode/s390.h" 28 #include "libiberty.h" 29 30 static int opc_index[256]; 31 static int current_arch_mask = 0; 32 static int option_use_insn_len_bits_p = 0; 33 34 typedef struct 35 { 36 const char *name; 37 const char *description; 38 } s390_options_t; 39 40 static const s390_options_t options[] = 41 { 42 { "esa" , N_("Disassemble in ESA architecture mode") }, 43 { "zarch", N_("Disassemble in z/Architecture mode") }, 44 { "insnlength", N_("Print unknown instructions according to " 45 "length from first two bits") } 46 }; 47 48 /* Set up index table for first opcode byte. */ 49 50 void 51 disassemble_init_s390 (struct disassemble_info *info) 52 { 53 int i; 54 const char *p; 55 56 memset (opc_index, 0, sizeof (opc_index)); 57 58 /* Reverse order, such that each opc_index ends up pointing to the 59 first matching entry instead of the last. */ 60 for (i = s390_num_opcodes; i--; ) 61 opc_index[s390_opcodes[i].opcode[0]] = i; 62 63 current_arch_mask = 1 << S390_OPCODE_ZARCH; 64 option_use_insn_len_bits_p = 0; 65 66 for (p = info->disassembler_options; p != NULL; ) 67 { 68 if (CONST_STRNEQ (p, "esa")) 69 current_arch_mask = 1 << S390_OPCODE_ESA; 70 else if (CONST_STRNEQ (p, "zarch")) 71 current_arch_mask = 1 << S390_OPCODE_ZARCH; 72 else if (CONST_STRNEQ (p, "insnlength")) 73 option_use_insn_len_bits_p = 1; 74 else 75 fprintf (stderr, "Unknown S/390 disassembler option: %s\n", p); 76 77 p = strchr (p, ','); 78 if (p != NULL) 79 p++; 80 } 81 } 82 83 /* Derive the length of an instruction from its first byte. */ 84 85 static inline int 86 s390_insn_length (const bfd_byte *buffer) 87 { 88 /* 00xxxxxx -> 2, 01xxxxxx/10xxxxxx -> 4, 11xxxxxx -> 6. */ 89 return ((buffer[0] >> 6) + 3) & ~1U; 90 } 91 92 /* Match the instruction in BUFFER against the given OPCODE, excluding 93 the first byte. */ 94 95 static inline int 96 s390_insn_matches_opcode (const bfd_byte *buffer, 97 const struct s390_opcode *opcode) 98 { 99 return (buffer[1] & opcode->mask[1]) == opcode->opcode[1] 100 && (buffer[2] & opcode->mask[2]) == opcode->opcode[2] 101 && (buffer[3] & opcode->mask[3]) == opcode->opcode[3] 102 && (buffer[4] & opcode->mask[4]) == opcode->opcode[4] 103 && (buffer[5] & opcode->mask[5]) == opcode->opcode[5]; 104 } 105 106 union operand_value 107 { 108 int i; 109 unsigned int u; 110 }; 111 112 /* Extracts an operand value from an instruction. */ 113 /* We do not perform the shift operation for larl-type address 114 operands here since that would lead to an overflow of the 32 bit 115 integer value. Instead the shift operation is done when printing 116 the operand. */ 117 118 static inline union operand_value 119 s390_extract_operand (const bfd_byte *insn, 120 const struct s390_operand *operand) 121 { 122 union operand_value ret; 123 unsigned int val; 124 int bits; 125 const bfd_byte *orig_insn = insn; 126 127 /* Extract fragments of the operand byte for byte. */ 128 insn += operand->shift / 8; 129 bits = (operand->shift & 7) + operand->bits; 130 val = 0; 131 do 132 { 133 val <<= 8; 134 val |= (unsigned int) *insn++; 135 bits -= 8; 136 } 137 while (bits > 0); 138 val >>= -bits; 139 val &= ((1U << (operand->bits - 1)) << 1) - 1; 140 141 /* Check for special long displacement case. */ 142 if (operand->bits == 20 && operand->shift == 20) 143 val = (val & 0xff) << 12 | (val & 0xfff00) >> 8; 144 145 /* Sign extend value if the operand is signed or pc relative. Avoid 146 integer overflows. */ 147 if (operand->flags & (S390_OPERAND_SIGNED | S390_OPERAND_PCREL)) 148 { 149 unsigned int m = 1U << (operand->bits - 1); 150 151 if (val >= m) 152 ret.i = (int) (val - m) - 1 - (int) (m - 1U); 153 else 154 ret.i = (int) val; 155 } 156 else if (operand->flags & S390_OPERAND_LENGTH) 157 /* Length x in an instruction has real length x + 1. */ 158 ret.u = val + 1; 159 160 else if (operand->flags & S390_OPERAND_VR) 161 { 162 /* Extract the extra bits for a vector register operand stored 163 in the RXB field. */ 164 unsigned vr = operand->shift == 32 ? 3 165 : (unsigned) operand->shift / 4 - 2; 166 167 ret.u = val | ((orig_insn[4] & (1 << (3 - vr))) << (vr + 1)); 168 } 169 else 170 ret.u = val; 171 172 return ret; 173 } 174 175 /* Print the S390 instruction in BUFFER, assuming that it matches the 176 given OPCODE. */ 177 178 static void 179 s390_print_insn_with_opcode (bfd_vma memaddr, 180 struct disassemble_info *info, 181 const bfd_byte *buffer, 182 const struct s390_opcode *opcode) 183 { 184 const unsigned char *opindex; 185 char separator; 186 187 /* Mnemonic. */ 188 info->fprintf_func (info->stream, "%s", opcode->name); 189 190 /* Operands. */ 191 separator = '\t'; 192 for (opindex = opcode->operands; *opindex != 0; opindex++) 193 { 194 const struct s390_operand *operand = s390_operands + *opindex; 195 union operand_value val = s390_extract_operand (buffer, operand); 196 unsigned long flags = operand->flags; 197 198 if ((flags & S390_OPERAND_INDEX) && val.u == 0) 199 continue; 200 if ((flags & S390_OPERAND_BASE) && 201 val.u == 0 && separator == '(') 202 { 203 separator = ','; 204 continue; 205 } 206 207 /* For instructions with a last optional operand don't print it 208 if zero. */ 209 if ((opcode->flags & (S390_INSTR_FLAG_OPTPARM | S390_INSTR_FLAG_OPTPARM2)) 210 && val.u == 0 211 && opindex[1] == 0) 212 break; 213 214 if ((opcode->flags & S390_INSTR_FLAG_OPTPARM2) 215 && val.u == 0 && opindex[1] != 0 && opindex[2] == 0) 216 { 217 union operand_value next_op_val = 218 s390_extract_operand (buffer, s390_operands + opindex[1]); 219 if (next_op_val.u == 0) 220 break; 221 } 222 223 if (flags & S390_OPERAND_GPR) 224 info->fprintf_func (info->stream, "%c%%r%u", separator, val.u); 225 else if (flags & S390_OPERAND_FPR) 226 info->fprintf_func (info->stream, "%c%%f%u", separator, val.u); 227 else if (flags & S390_OPERAND_VR) 228 info->fprintf_func (info->stream, "%c%%v%i", separator, val.u); 229 else if (flags & S390_OPERAND_AR) 230 info->fprintf_func (info->stream, "%c%%a%u", separator, val.u); 231 else if (flags & S390_OPERAND_CR) 232 info->fprintf_func (info->stream, "%c%%c%u", separator, val.u); 233 else if (flags & S390_OPERAND_PCREL) 234 { 235 info->fprintf_func (info->stream, "%c", separator); 236 info->print_address_func (memaddr + val.i + val.i, info); 237 } 238 else if (flags & S390_OPERAND_SIGNED) 239 info->fprintf_func (info->stream, "%c%i", separator, val.i); 240 else 241 { 242 if (flags & S390_OPERAND_OR1) 243 val.u &= ~1; 244 if (flags & S390_OPERAND_OR2) 245 val.u &= ~2; 246 if (flags & S390_OPERAND_OR8) 247 val.u &= ~8; 248 249 if ((opcode->flags & S390_INSTR_FLAG_OPTPARM) 250 && val.u == 0 251 && opindex[1] == 0) 252 break; 253 info->fprintf_func (info->stream, "%c%u", separator, val.u); 254 } 255 256 if (flags & S390_OPERAND_DISP) 257 separator = '('; 258 else if (flags & S390_OPERAND_BASE) 259 { 260 info->fprintf_func (info->stream, ")"); 261 separator = ','; 262 } 263 else 264 separator = ','; 265 } 266 } 267 268 /* Check whether opcode A's mask is more specific than that of B. */ 269 270 static int 271 opcode_mask_more_specific (const struct s390_opcode *a, 272 const struct s390_opcode *b) 273 { 274 return (((int) a->mask[0] + a->mask[1] + a->mask[2] 275 + a->mask[3] + a->mask[4] + a->mask[5]) 276 > ((int) b->mask[0] + b->mask[1] + b->mask[2] 277 + b->mask[3] + b->mask[4] + b->mask[5])); 278 } 279 280 /* Print a S390 instruction. */ 281 282 int 283 print_insn_s390 (bfd_vma memaddr, struct disassemble_info *info) 284 { 285 bfd_byte buffer[6]; 286 const struct s390_opcode *opcode = NULL; 287 unsigned int value; 288 int status, opsize, bufsize, bytes_to_dump, i; 289 290 /* The output looks better if we put 6 bytes on a line. */ 291 info->bytes_per_line = 6; 292 293 /* Every S390 instruction is max 6 bytes long. */ 294 memset (buffer, 0, 6); 295 status = info->read_memory_func (memaddr, buffer, 6, info); 296 if (status != 0) 297 { 298 for (bufsize = 0; bufsize < 6; bufsize++) 299 if (info->read_memory_func (memaddr, buffer, bufsize + 1, info) != 0) 300 break; 301 if (bufsize <= 0) 302 { 303 info->memory_error_func (status, memaddr, info); 304 return -1; 305 } 306 opsize = s390_insn_length (buffer); 307 status = opsize > bufsize; 308 } 309 else 310 { 311 bufsize = 6; 312 opsize = s390_insn_length (buffer); 313 } 314 315 if (status == 0) 316 { 317 const struct s390_opcode *op; 318 319 /* Find the "best match" in the opcode table. */ 320 for (op = s390_opcodes + opc_index[buffer[0]]; 321 op != s390_opcodes + s390_num_opcodes 322 && op->opcode[0] == buffer[0]; 323 op++) 324 { 325 if ((op->modes & current_arch_mask) 326 && s390_insn_matches_opcode (buffer, op) 327 && (opcode == NULL 328 || opcode_mask_more_specific (op, opcode))) 329 opcode = op; 330 } 331 332 if (opcode != NULL) 333 { 334 /* The instruction is valid. Print it and return its size. */ 335 s390_print_insn_with_opcode (memaddr, info, buffer, opcode); 336 return opsize; 337 } 338 } 339 340 /* For code sections it makes sense to skip unknown instructions 341 according to their length bits. */ 342 if (status == 0 343 && option_use_insn_len_bits_p 344 && info->section != NULL 345 && (info->section->flags & SEC_CODE)) 346 bytes_to_dump = opsize; 347 else 348 /* By default unknown instructions are printed as .long's/.short' 349 depending on how many bytes are available. */ 350 bytes_to_dump = bufsize >= 4 ? 4 : bufsize; 351 352 if (bytes_to_dump == 0) 353 return 0; 354 355 /* Fall back to hex print. */ 356 switch (bytes_to_dump) 357 { 358 case 4: 359 value = (unsigned int) buffer[0]; 360 value = (value << 8) + (unsigned int) buffer[1]; 361 value = (value << 8) + (unsigned int) buffer[2]; 362 value = (value << 8) + (unsigned int) buffer[3]; 363 info->fprintf_func (info->stream, ".long\t0x%08x", value); 364 return 4; 365 case 2: 366 value = (unsigned int) buffer[0]; 367 value = (value << 8) + (unsigned int) buffer[1]; 368 info->fprintf_func (info->stream, ".short\t0x%04x", value); 369 return 2; 370 default: 371 info->fprintf_func (info->stream, ".byte\t0x%02x", 372 (unsigned int) buffer[0]); 373 for (i = 1; i < bytes_to_dump; i++) 374 info->fprintf_func (info->stream, ",0x%02x", 375 (unsigned int) buffer[i]); 376 return bytes_to_dump; 377 } 378 return 0; 379 } 380 381 const disasm_options_t * 382 disassembler_options_s390 (void) 383 { 384 static disasm_options_t *opts = NULL; 385 386 if (opts == NULL) 387 { 388 size_t i, num_options = ARRAY_SIZE (options); 389 opts = XNEW (disasm_options_t); 390 opts->name = XNEWVEC (const char *, num_options + 1); 391 opts->description = XNEWVEC (const char *, num_options + 1); 392 for (i = 0; i < num_options; i++) 393 { 394 opts->name[i] = options[i].name; 395 opts->description[i] = _(options[i].description); 396 } 397 /* The array we return must be NULL terminated. */ 398 opts->name[i] = NULL; 399 opts->description[i] = NULL; 400 } 401 402 return opts; 403 } 404 405 void 406 print_s390_disassembler_options (FILE *stream) 407 { 408 unsigned int i, max_len = 0; 409 fprintf (stream, _("\n\ 410 The following S/390 specific disassembler options are supported for use\n\ 411 with the -M switch (multiple options should be separated by commas):\n")); 412 413 for (i = 0; i < ARRAY_SIZE (options); i++) 414 { 415 unsigned int len = strlen (options[i].name); 416 if (max_len < len) 417 max_len = len; 418 } 419 420 for (i = 0, max_len++; i < ARRAY_SIZE (options); i++) 421 fprintf (stream, " %s%*c %s\n", 422 options[i].name, 423 (int)(max_len - strlen (options[i].name)), ' ', 424 _(options[i].description)); 425 } 426