s390-dis.c revision 1.1.1.1
1/* s390-dis.c -- Disassemble S390 instructions 2 Copyright 2000, 2001, 2002 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., 59 Temple Place - Suite 330, Boston, MA 20 02111-1307, 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 28static int init_flag = 0; 29static int opc_index[256]; 30static int current_arch_mask = 0; 31 32static void init_disasm PARAMS ((struct disassemble_info *)); 33static unsigned int s390_extract_operand 34 PARAMS ((unsigned char *, const struct s390_operand *)); 35 36/* Set up index table for first opcode byte. */ 37 38static void 39init_disasm (info) 40 struct disassemble_info *info; 41{ 42 const struct s390_opcode *opcode; 43 const struct s390_opcode *opcode_end; 44 45 memset (opc_index, 0, sizeof (opc_index)); 46 opcode_end = s390_opcodes + s390_num_opcodes; 47 for (opcode = s390_opcodes; opcode < opcode_end; opcode++) 48 { 49 opc_index[(int) opcode->opcode[0]] = opcode - s390_opcodes; 50 while ((opcode < opcode_end) && 51 (opcode[1].opcode[0] == opcode->opcode[0])) 52 opcode++; 53 } 54 switch (info->mach) 55 { 56 case bfd_mach_s390_31: 57 current_arch_mask = 1 << S390_OPCODE_ESA; 58 break; 59 case bfd_mach_s390_64: 60 current_arch_mask = 1 << S390_OPCODE_ZARCH; 61 break; 62 default: 63 abort (); 64 } 65 init_flag = 1; 66} 67 68/* Extracts an operand value from an instruction. */ 69 70static inline unsigned int 71s390_extract_operand (insn, operand) 72 unsigned char *insn; 73 const struct s390_operand *operand; 74{ 75 unsigned int val; 76 int bits; 77 78 /* Extract fragments of the operand byte for byte. */ 79 insn += operand->shift / 8; 80 bits = (operand->shift & 7) + operand->bits; 81 val = 0; 82 do 83 { 84 val <<= 8; 85 val |= (unsigned int) *insn++; 86 bits -= 8; 87 } 88 while (bits > 0); 89 val >>= -bits; 90 val &= ((1U << (operand->bits - 1)) << 1) - 1; 91 92 /* Sign extend value if the operand is signed or pc relative. */ 93 if ((operand->flags & (S390_OPERAND_SIGNED | S390_OPERAND_PCREL)) 94 && (val & (1U << (operand->bits - 1)))) 95 val |= (-1U << (operand->bits - 1)) << 1; 96 97 /* Double value if the operand is pc relative. */ 98 if (operand->flags & S390_OPERAND_PCREL) 99 val <<= 1; 100 101 /* Length x in an instructions has real length x+1. */ 102 if (operand->flags & S390_OPERAND_LENGTH) 103 val++; 104 return val; 105} 106 107/* Print a S390 instruction. */ 108 109int 110print_insn_s390 (memaddr, info) 111 bfd_vma memaddr; 112 struct disassemble_info *info; 113{ 114 bfd_byte buffer[6]; 115 const struct s390_opcode *opcode; 116 const struct s390_opcode *opcode_end; 117 unsigned int value; 118 int status, opsize, bufsize; 119 char separator; 120 121 if (init_flag == 0) 122 init_disasm (info); 123 124 /* The output looks better if we put 6 bytes on a line. */ 125 info->bytes_per_line = 6; 126 127 /* Every S390 instruction is max 6 bytes long. */ 128 memset (buffer, 0, 6); 129 status = (*info->read_memory_func) (memaddr, buffer, 6, info); 130 if (status != 0) 131 { 132 for (bufsize = 0; bufsize < 6; bufsize++) 133 if ((*info->read_memory_func) (memaddr, buffer, bufsize + 1, info) != 0) 134 break; 135 if (bufsize <= 0) 136 { 137 (*info->memory_error_func) (status, memaddr, info); 138 return -1; 139 } 140 /* Opsize calculation looks strange but it works 141 00xxxxxx -> 2 bytes, 01xxxxxx/10xxxxxx -> 4 bytes, 142 11xxxxxx -> 6 bytes. */ 143 opsize = ((((buffer[0] >> 6) + 1) >> 1) + 1) << 1; 144 status = opsize > bufsize; 145 } 146 else 147 { 148 bufsize = 6; 149 opsize = ((((buffer[0] >> 6) + 1) >> 1) + 1) << 1; 150 } 151 152 if (status == 0) 153 { 154 /* Find the first match in the opcode table. */ 155 opcode_end = s390_opcodes + s390_num_opcodes; 156 for (opcode = s390_opcodes + opc_index[(int) buffer[0]]; 157 (opcode < opcode_end) && (buffer[0] == opcode->opcode[0]); 158 opcode++) 159 { 160 const struct s390_operand *operand; 161 const unsigned char *opindex; 162 163 /* Check architecture. */ 164 if (!(opcode->modes & current_arch_mask)) 165 continue; 166 /* Check signature of the opcode. */ 167 if ((buffer[1] & opcode->mask[1]) != opcode->opcode[1] 168 || (buffer[2] & opcode->mask[2]) != opcode->opcode[2] 169 || (buffer[3] & opcode->mask[3]) != opcode->opcode[3] 170 || (buffer[4] & opcode->mask[4]) != opcode->opcode[4] 171 || (buffer[5] & opcode->mask[5]) != opcode->opcode[5]) 172 continue; 173 174 /* The instruction is valid. */ 175 if (opcode->operands[0] != 0) 176 (*info->fprintf_func) (info->stream, "%s\t", opcode->name); 177 else 178 (*info->fprintf_func) (info->stream, "%s", opcode->name); 179 180 /* Extract the operands. */ 181 separator = 0; 182 for (opindex = opcode->operands; *opindex != 0; opindex++) 183 { 184 unsigned int value; 185 186 operand = s390_operands + *opindex; 187 value = s390_extract_operand (buffer, operand); 188 189 if ((operand->flags & S390_OPERAND_INDEX) && value == 0) 190 continue; 191 if ((operand->flags & S390_OPERAND_BASE) && 192 value == 0 && separator == '(') 193 { 194 separator = ','; 195 continue; 196 } 197 198 if (separator) 199 (*info->fprintf_func) (info->stream, "%c", separator); 200 201 if (operand->flags & S390_OPERAND_GPR) 202 (*info->fprintf_func) (info->stream, "%%r%i", value); 203 else if (operand->flags & S390_OPERAND_FPR) 204 (*info->fprintf_func) (info->stream, "%%f%i", value); 205 else if (operand->flags & S390_OPERAND_AR) 206 (*info->fprintf_func) (info->stream, "%%a%i", value); 207 else if (operand->flags & S390_OPERAND_CR) 208 (*info->fprintf_func) (info->stream, "%%c%i", value); 209 else if (operand->flags & S390_OPERAND_PCREL) 210 (*info->print_address_func) (memaddr + (int) value, info); 211 else if (operand->flags & S390_OPERAND_SIGNED) 212 (*info->fprintf_func) (info->stream, "%i", (int) value); 213 else 214 (*info->fprintf_func) (info->stream, "%i", value); 215 216 if (operand->flags & S390_OPERAND_DISP) 217 { 218 separator = '('; 219 } 220 else if (operand->flags & S390_OPERAND_BASE) 221 { 222 (*info->fprintf_func) (info->stream, ")"); 223 separator = ','; 224 } 225 else 226 separator = ','; 227 } 228 229 /* Found instruction, printed it, return its size. */ 230 return opsize; 231 } 232 /* No matching instruction found, fall through to hex print. */ 233 } 234 235 if (bufsize >= 4) 236 { 237 value = (unsigned int) buffer[0]; 238 value = (value << 8) + (unsigned int) buffer[1]; 239 value = (value << 8) + (unsigned int) buffer[2]; 240 value = (value << 8) + (unsigned int) buffer[3]; 241 (*info->fprintf_func) (info->stream, ".long\t0x%08x", value); 242 return 4; 243 } 244 else if (bufsize >= 2) 245 { 246 value = (unsigned int) buffer[0]; 247 value = (value << 8) + (unsigned int) buffer[1]; 248 (*info->fprintf_func) (info->stream, ".short\t0x%04x", value); 249 return 2; 250 } 251 else 252 { 253 value = (unsigned int) buffer[0]; 254 (*info->fprintf_func) (info->stream, ".byte\t0x%02x", value); 255 return 1; 256 } 257} 258