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