00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026 #include <stdio.h>
00027 #include "sysdep.h"
00028 #include "dis-asm.h"
00029 #include "opcode/ppc.h"
00030
00031
00032
00033
00034
00035
00036
00037 static int print_insn_powerpc (bfd_vma, struct disassemble_info *, int, int);
00038
00039 struct dis_private {
00040
00041 int dialect;
00042 };
00043
00044
00045
00046
00047
00048 static int
00049 powerpc_dialect (struct disassemble_info *info)
00050 {
00051 int dialect = PPC_OPCODE_PPC;
00052
00053 if (BFD_DEFAULT_TARGET_SIZE == 64)
00054 dialect |= PPC_OPCODE_64;
00055
00056 if (info->disassembler_options
00057 && strstr (info->disassembler_options, "booke") != NULL)
00058 dialect |= PPC_OPCODE_BOOKE | PPC_OPCODE_BOOKE64;
00059 else if ((info->mach == bfd_mach_ppc_e500)
00060 || (info->disassembler_options
00061 && strstr (info->disassembler_options, "e500") != NULL))
00062 dialect |= (PPC_OPCODE_BOOKE
00063 | PPC_OPCODE_SPE | PPC_OPCODE_ISEL
00064 | PPC_OPCODE_EFS | PPC_OPCODE_BRLOCK
00065 | PPC_OPCODE_PMR | PPC_OPCODE_CACHELCK
00066 | PPC_OPCODE_RFMCI);
00067 else if (info->disassembler_options
00068 && strstr (info->disassembler_options, "efs") != NULL)
00069 dialect |= PPC_OPCODE_EFS;
00070 else
00071 dialect |= (PPC_OPCODE_403 | PPC_OPCODE_601 | PPC_OPCODE_CLASSIC
00072 | PPC_OPCODE_COMMON | PPC_OPCODE_ALTIVEC);
00073
00074 if (info->disassembler_options
00075 && strstr (info->disassembler_options, "power4") != NULL)
00076 dialect |= PPC_OPCODE_POWER4;
00077
00078 if (info->disassembler_options
00079 && strstr (info->disassembler_options, "any") != NULL)
00080 dialect |= PPC_OPCODE_ANY;
00081
00082 if (info->disassembler_options)
00083 {
00084 if (strstr (info->disassembler_options, "32") != NULL)
00085 dialect &= ~PPC_OPCODE_64;
00086 else if (strstr (info->disassembler_options, "64") != NULL)
00087 dialect |= PPC_OPCODE_64;
00088 }
00089
00090 ((struct dis_private *) &info->private_data)->dialect = dialect;
00091 return dialect;
00092 }
00093
00094
00095
00096 int
00097 print_insn_big_powerpc (bfd_vma memaddr, struct disassemble_info *info)
00098 {
00099 int dialect = ((struct dis_private *) &info->private_data)->dialect;
00100 return print_insn_powerpc (memaddr, info, 1, dialect);
00101 }
00102
00103
00104
00105 int
00106 print_insn_little_powerpc (bfd_vma memaddr, struct disassemble_info *info)
00107 {
00108 int dialect = ((struct dis_private *) &info->private_data)->dialect;
00109 return print_insn_powerpc (memaddr, info, 0, dialect);
00110 }
00111
00112
00113
00114 int
00115 print_insn_rs6000 (bfd_vma memaddr, struct disassemble_info *info)
00116 {
00117 return print_insn_powerpc (memaddr, info, 1, PPC_OPCODE_POWER);
00118 }
00119
00120
00121
00122 static int
00123 print_insn_powerpc (bfd_vma memaddr,
00124 struct disassemble_info *info,
00125 int bigendian,
00126 int dialect)
00127 {
00128 bfd_byte buffer[4];
00129 int status;
00130 unsigned long insn;
00131 const struct powerpc_opcode *opcode;
00132 const struct powerpc_opcode *opcode_end;
00133 unsigned long op;
00134
00135 if (dialect == 0)
00136 dialect = powerpc_dialect (info);
00137
00138 status = (*info->read_memory_func) (memaddr, buffer, 4, info);
00139 if (status != 0)
00140 {
00141 (*info->memory_error_func) (status, memaddr, info);
00142 return -1;
00143 }
00144
00145 if (bigendian)
00146 insn = bfd_getb32 (buffer);
00147 else
00148 insn = bfd_getl32 (buffer);
00149
00150
00151 op = PPC_OP (insn);
00152
00153
00154
00155 opcode_end = powerpc_opcodes + powerpc_num_opcodes;
00156 again:
00157 for (opcode = powerpc_opcodes; opcode < opcode_end; opcode++)
00158 {
00159 unsigned long table_op;
00160 const unsigned char *opindex;
00161 const struct powerpc_operand *operand;
00162 int invalid;
00163 int need_comma;
00164 int need_paren;
00165
00166 table_op = PPC_OP (opcode->opcode);
00167 if (op < table_op)
00168 break;
00169 if (op > table_op)
00170 continue;
00171
00172 if ((insn & opcode->mask) != opcode->opcode
00173 || (opcode->flags & dialect) == 0)
00174 continue;
00175
00176
00177
00178
00179 invalid = 0;
00180 for (opindex = opcode->operands; *opindex != 0; opindex++)
00181 {
00182 operand = powerpc_operands + *opindex;
00183 if (operand->extract)
00184 (*operand->extract) (insn, dialect, &invalid);
00185 }
00186 if (invalid)
00187 continue;
00188
00189
00190 if (opcode->operands[0] != 0)
00191 (*info->fprintf_func) (info->stream, "%-7s ", opcode->name);
00192 else
00193 (*info->fprintf_func) (info->stream, "%s", opcode->name);
00194
00195
00196 need_comma = 0;
00197 need_paren = 0;
00198 for (opindex = opcode->operands; *opindex != 0; opindex++)
00199 {
00200 long value;
00201
00202 operand = powerpc_operands + *opindex;
00203
00204
00205
00206
00207 if ((operand->flags & PPC_OPERAND_FAKE) != 0)
00208 continue;
00209
00210
00211 if (operand->extract)
00212 value = (*operand->extract) (insn, dialect, &invalid);
00213 else
00214 {
00215 value = (insn >> operand->shift) & ((1 << operand->bits) - 1);
00216 if ((operand->flags & PPC_OPERAND_SIGNED) != 0
00217 && (value & (1 << (operand->bits - 1))) != 0)
00218 value -= 1 << operand->bits;
00219 }
00220
00221
00222
00223 if ((operand->flags & PPC_OPERAND_OPTIONAL) != 0
00224 && (operand->flags & PPC_OPERAND_NEXT) == 0
00225 && value == 0)
00226 continue;
00227
00228 if (need_comma)
00229 {
00230 (*info->fprintf_func) (info->stream, ",");
00231 need_comma = 0;
00232 }
00233
00234
00235 if ((operand->flags & PPC_OPERAND_GPR) != 0
00236 || ((operand->flags & PPC_OPERAND_GPR_0) != 0 && value != 0))
00237 (*info->fprintf_func) (info->stream, "r%ld", value);
00238 else if ((operand->flags & PPC_OPERAND_FPR) != 0)
00239 (*info->fprintf_func) (info->stream, "f%ld", value);
00240 else if ((operand->flags & PPC_OPERAND_VR) != 0)
00241 (*info->fprintf_func) (info->stream, "v%ld", value);
00242 else if ((operand->flags & PPC_OPERAND_RELATIVE) != 0)
00243 (*info->print_address_func) (memaddr + value, info);
00244 else if ((operand->flags & PPC_OPERAND_ABSOLUTE) != 0)
00245 (*info->print_address_func) ((bfd_vma) value & 0xffffffff, info);
00246 else if ((operand->flags & PPC_OPERAND_CR) == 0
00247 || (dialect & PPC_OPCODE_PPC) == 0)
00248 (*info->fprintf_func) (info->stream, "%ld", value);
00249 else
00250 {
00251 if (operand->bits == 3)
00252 (*info->fprintf_func) (info->stream, "cr%d", value);
00253 else
00254 {
00255 static const char *cbnames[4] = { "lt", "gt", "eq", "so" };
00256 int cr;
00257 int cc;
00258
00259 cr = value >> 2;
00260 if (cr != 0)
00261 (*info->fprintf_func) (info->stream, "4*cr%d+", cr);
00262 cc = value & 3;
00263 (*info->fprintf_func) (info->stream, "%s", cbnames[cc]);
00264 }
00265 }
00266
00267 if (need_paren)
00268 {
00269 (*info->fprintf_func) (info->stream, ")");
00270 need_paren = 0;
00271 }
00272
00273 if ((operand->flags & PPC_OPERAND_PARENS) == 0)
00274 need_comma = 1;
00275 else
00276 {
00277 (*info->fprintf_func) (info->stream, "(");
00278 need_paren = 1;
00279 }
00280 }
00281
00282
00283 return 4;
00284 }
00285
00286 if ((dialect & PPC_OPCODE_ANY) != 0)
00287 {
00288 dialect = ~PPC_OPCODE_ANY;
00289 goto again;
00290 }
00291
00292
00293 (*info->fprintf_func) (info->stream, ".long 0x%lx", insn);
00294
00295 return 4;
00296 }
00297
00298 void
00299 print_ppc_disassembler_options (FILE *stream)
00300 {
00301 fprintf (stream, "\n\
00302 The following PPC specific disassembler options are supported for use with\n\
00303 the -M switch:\n");
00304
00305 fprintf (stream, " booke|booke32|booke64 Disassemble the BookE instructions\n");
00306 fprintf (stream, " e500|e500x2 Disassemble the e500 instructions\n");
00307 fprintf (stream, " efs Disassemble the EFS instructions\n");
00308 fprintf (stream, " power4 Disassemble the Power4 instructions\n");
00309 fprintf (stream, " 32 Do not disassemble 64-bit instructions\n");
00310 fprintf (stream, " 64 Allow disassembly of 64-bit instructions\n");
00311 }