1 /* s390-dis.c -- Disassemble S390 instructions 2 Copyright 2000, 2001, 2002, 2003, 2005 Free Software Foundation, Inc. 3 Contributed by Martin Schwidefsky (schwidefsky@de.ibm.com). 4 5 This file is part of GDB, GAS and the GNU binutils. 6 7 This program 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 2 of the License, or 10 (at your option) any later version. 11 12 This program is distributed in the hope that it will be useful, 13 but WITHOUT ANY WARRANTY; without even the implied warranty of 14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 GNU General Public License for more details. 16 17 You should have received a copy of the GNU General Public License 18 along with this program; if not, write to the Free Software 19 Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 20 02110-1301, USA. */ 21 22 #include <stdio.h> 23 #include "ansidecl.h" 24 #include "sysdep.h" 25 #include "dis-asm.h" 26 #include "opcode/s390.h" 27 28 static int init_flag = 0; 29 static int opc_index[256]; 30 static int current_arch_mask = 0; 31 32 /* Set up index table for first opcode byte. */ 33 34 static void 35 init_disasm (struct disassemble_info *info) 36 { 37 const struct s390_opcode *opcode; 38 const struct s390_opcode *opcode_end; 39 40 memset (opc_index, 0, sizeof (opc_index)); 41 opcode_end = s390_opcodes + s390_num_opcodes; 42 for (opcode = s390_opcodes; opcode < opcode_end; opcode++) 43 { 44 opc_index[(int) opcode->opcode[0]] = opcode - s390_opcodes; 45 while ((opcode < opcode_end) && 46 (opcode[1].opcode[0] == opcode->opcode[0])) 47 opcode++; 48 } 49 switch (info->mach) 50 { 51 case bfd_mach_s390_31: 52 current_arch_mask = 1 << S390_OPCODE_ESA; 53 break; 54 case bfd_mach_s390_64: 55 current_arch_mask = 1 << S390_OPCODE_ZARCH; 56 break; 57 default: 58 abort (); 59 } 60 init_flag = 1; 61 } 62 63 /* Extracts an operand value from an instruction. */ 64 65 static inline unsigned int 66 s390_extract_operand (unsigned char *insn, const struct s390_operand *operand) 67 { 68 unsigned int val; 69 int bits; 70 71 /* Extract fragments of the operand byte for byte. */ 72 insn += operand->shift / 8; 73 bits = (operand->shift & 7) + operand->bits; 74 val = 0; 75 do 76 { 77 val <<= 8; 78 val |= (unsigned int) *insn++; 79 bits -= 8; 80 } 81 while (bits > 0); 82 val >>= -bits; 83 val &= ((1U << (operand->bits - 1)) << 1) - 1; 84 85 /* Check for special long displacement case. */ 86 if (operand->bits == 20 && operand->shift == 20) 87 val = (val & 0xff) << 12 | (val & 0xfff00) >> 8; 88 89 /* Sign extend value if the operand is signed or pc relative. */ 90 if ((operand->flags & (S390_OPERAND_SIGNED | S390_OPERAND_PCREL)) 91 && (val & (1U << (operand->bits - 1)))) 92 val |= (-1U << (operand->bits - 1)) << 1; 93 94 /* Double value if the operand is pc relative. */ 95 if (operand->flags & S390_OPERAND_PCREL) 96 val <<= 1; 97 98 /* Length x in an instructions has real length x + 1. */ 99 if (operand->flags & S390_OPERAND_LENGTH) 100 val++; 101 return val; 102 } 103 104 /* Print a S390 instruction. */ 105 106 int 107 print_insn_s390 (bfd_vma memaddr, struct disassemble_info *info) 108 { 109 bfd_byte buffer[6]; 110 const struct s390_opcode *opcode; 111 const struct s390_opcode *opcode_end; 112 unsigned int value; 113 int status, opsize, bufsize; 114 char separator; 115 116 if (init_flag == 0) 117 init_disasm (info); 118 119 /* The output looks better if we put 6 bytes on a line. */ 120 info->bytes_per_line = 6; 121 122 /* Every S390 instruction is max 6 bytes long. */ 123 memset (buffer, 0, 6); 124 status = (*info->read_memory_func) (memaddr, buffer, 6, info); 125 if (status != 0) 126 { 127 for (bufsize = 0; bufsize < 6; bufsize++) 128 if ((*info->read_memory_func) (memaddr, buffer, bufsize + 1, info) != 0) 129 break; 130 if (bufsize <= 0) 131 { 132 (*info->memory_error_func) (status, memaddr, info); 133 return -1; 134 } 135 /* Opsize calculation looks strange but it works 136 00xxxxxx -> 2 bytes, 01xxxxxx/10xxxxxx -> 4 bytes, 137 11xxxxxx -> 6 bytes. */ 138 opsize = ((((buffer[0] >> 6) + 1) >> 1) + 1) << 1; 139 status = opsize > bufsize; 140 } 141 else 142 { 143 bufsize = 6; 144 opsize = ((((buffer[0] >> 6) + 1) >> 1) + 1) << 1; 145 } 146 147 if (status == 0) 148 { 149 /* Find the first match in the opcode table. */ 150 opcode_end = s390_opcodes + s390_num_opcodes; 151 for (opcode = s390_opcodes + opc_index[(int) buffer[0]]; 152 (opcode < opcode_end) && (buffer[0] == opcode->opcode[0]); 153 opcode++) 154 { 155 const struct s390_operand *operand; 156 const unsigned char *opindex; 157 158 /* Check architecture. */ 159 if (!(opcode->modes & current_arch_mask)) 160 continue; 161 /* Check signature of the opcode. */ 162 if ((buffer[1] & opcode->mask[1]) != opcode->opcode[1] 163 || (buffer[2] & opcode->mask[2]) != opcode->opcode[2] 164 || (buffer[3] & opcode->mask[3]) != opcode->opcode[3] 165 || (buffer[4] & opcode->mask[4]) != opcode->opcode[4] 166 || (buffer[5] & opcode->mask[5]) != opcode->opcode[5]) 167 continue; 168 169 /* The instruction is valid. */ 170 if (opcode->operands[0] != 0) 171 (*info->fprintf_func) (info->stream, "%s\t", opcode->name); 172 else 173 (*info->fprintf_func) (info->stream, "%s", opcode->name); 174 175 /* Extract the operands. */ 176 separator = 0; 177 for (opindex = opcode->operands; *opindex != 0; opindex++) 178 { 179 unsigned int value; 180 181 operand = s390_operands + *opindex; 182 value = s390_extract_operand (buffer, operand); 183 184 if ((operand->flags & S390_OPERAND_INDEX) && value == 0) 185 continue; 186 if ((operand->flags & S390_OPERAND_BASE) && 187 value == 0 && separator == '(') 188 { 189 separator = ','; 190 continue; 191 } 192 193 if (separator) 194 (*info->fprintf_func) (info->stream, "%c", separator); 195 196 if (operand->flags & S390_OPERAND_GPR) 197 (*info->fprintf_func) (info->stream, "%%r%i", value); 198 else if (operand->flags & S390_OPERAND_FPR) 199 (*info->fprintf_func) (info->stream, "%%f%i", value); 200 else if (operand->flags & S390_OPERAND_AR) 201 (*info->fprintf_func) (info->stream, "%%a%i", value); 202 else if (operand->flags & S390_OPERAND_CR) 203 (*info->fprintf_func) (info->stream, "%%c%i", value); 204 else if (operand->flags & S390_OPERAND_PCREL) 205 (*info->print_address_func) (memaddr + (int) value, info); 206 else if (operand->flags & S390_OPERAND_SIGNED) 207 (*info->fprintf_func) (info->stream, "%i", (int) value); 208 else 209 (*info->fprintf_func) (info->stream, "%u", value); 210 211 if (operand->flags & S390_OPERAND_DISP) 212 { 213 separator = '('; 214 } 215 else if (operand->flags & S390_OPERAND_BASE) 216 { 217 (*info->fprintf_func) (info->stream, ")"); 218 separator = ','; 219 } 220 else 221 separator = ','; 222 } 223 224 /* Found instruction, printed it, return its size. */ 225 return opsize; 226 } 227 /* No matching instruction found, fall through to hex print. */ 228 } 229 230 if (bufsize >= 4) 231 { 232 value = (unsigned int) buffer[0]; 233 value = (value << 8) + (unsigned int) buffer[1]; 234 value = (value << 8) + (unsigned int) buffer[2]; 235 value = (value << 8) + (unsigned int) buffer[3]; 236 (*info->fprintf_func) (info->stream, ".long\t0x%08x", value); 237 return 4; 238 } 239 else if (bufsize >= 2) 240 { 241 value = (unsigned int) buffer[0]; 242 value = (value << 8) + (unsigned int) buffer[1]; 243 (*info->fprintf_func) (info->stream, ".short\t0x%04x", value); 244 return 2; 245 } 246 else 247 { 248 value = (unsigned int) buffer[0]; 249 (*info->fprintf_func) (info->stream, ".byte\t0x%02x", value); 250 return 1; 251 } 252 } 253