X-Git-Url: https://oss.titaniummirror.com/gitweb?p=msp430-binutils.git;a=blobdiff_plain;f=opcodes%2Fppc-dis.c;fp=opcodes%2Fppc-dis.c;h=ac88f7698eac2da4ccc8d4417a47191b6d0e4c46;hp=c03dd54bd91b4d0e4a427cccf25d9a47f8d1ee8b;hb=d5da4f291af551c0b8b79e1d4a9b173d60e5c10e;hpb=7b5ea4fcdf2819e070665ab5610f8b48e3867c10 diff --git a/opcodes/ppc-dis.c b/opcodes/ppc-dis.c index c03dd54..ac88f76 100644 --- a/opcodes/ppc-dis.c +++ b/opcodes/ppc-dis.c @@ -1,6 +1,6 @@ /* ppc-dis.c -- Disassemble PowerPC instructions - Copyright 1994, 1995, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007 - Free Software Foundation, Inc. + Copyright 1994, 1995, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, + 2008, 2009 Free Software Foundation, Inc. Written by Ian Lance Taylor, Cygnus Support This file is part of the GNU opcodes library. @@ -23,6 +23,7 @@ #include #include "sysdep.h" #include "dis-asm.h" +#include "opintl.h" #include "opcode/ppc.h" /* This file provides several disassembler functions, all of which use @@ -30,76 +31,224 @@ are provided because this file handles disassembly for the PowerPC in both big and little endian mode and also for the POWER (RS/6000) chip. */ +static int print_insn_powerpc (bfd_vma, struct disassemble_info *, int, + ppc_cpu_t); -static int print_insn_powerpc (bfd_vma, struct disassemble_info *, int, int); +struct dis_private +{ + /* Stash the result of parsing disassembler_options here. */ + ppc_cpu_t dialect; +}; + +#define POWERPC_DIALECT(INFO) \ + (((struct dis_private *) ((INFO)->private_data))->dialect) + +struct ppc_mopt { + const char *opt; + ppc_cpu_t cpu; + ppc_cpu_t sticky; +}; + +struct ppc_mopt ppc_opts[] = { + { "403", (PPC_OPCODE_PPC | PPC_OPCODE_CLASSIC | PPC_OPCODE_403 + | PPC_OPCODE_32), + 0 }, + { "405", (PPC_OPCODE_PPC | PPC_OPCODE_CLASSIC | PPC_OPCODE_403 + | PPC_OPCODE_405 | PPC_OPCODE_32), + 0 }, + { "440", (PPC_OPCODE_PPC | PPC_OPCODE_BOOKE | PPC_OPCODE_32 + | PPC_OPCODE_440 | PPC_OPCODE_ISEL | PPC_OPCODE_RFMCI), + 0 }, + { "464", (PPC_OPCODE_PPC | PPC_OPCODE_BOOKE | PPC_OPCODE_32 + | PPC_OPCODE_440 | PPC_OPCODE_ISEL | PPC_OPCODE_RFMCI), + 0 }, + { "476", (PPC_OPCODE_PPC | PPC_OPCODE_CLASSIC | PPC_OPCODE_ISEL + | PPC_OPCODE_440 | PPC_OPCODE_476 | PPC_OPCODE_POWER4 + | PPC_OPCODE_POWER5), + 0 }, + { "601", (PPC_OPCODE_PPC | PPC_OPCODE_CLASSIC | PPC_OPCODE_601 + | PPC_OPCODE_32), + 0 }, + { "603", (PPC_OPCODE_PPC | PPC_OPCODE_CLASSIC | PPC_OPCODE_32), + 0 }, + { "604", (PPC_OPCODE_PPC | PPC_OPCODE_CLASSIC | PPC_OPCODE_32), + 0 }, + { "620", (PPC_OPCODE_PPC | PPC_OPCODE_CLASSIC | PPC_OPCODE_64), + 0 }, + { "7400", (PPC_OPCODE_PPC | PPC_OPCODE_CLASSIC | PPC_OPCODE_ALTIVEC + | PPC_OPCODE_32), + 0 }, + { "7410", (PPC_OPCODE_PPC | PPC_OPCODE_CLASSIC | PPC_OPCODE_ALTIVEC + | PPC_OPCODE_32), + 0 }, + { "7450", (PPC_OPCODE_PPC | PPC_OPCODE_CLASSIC | PPC_OPCODE_ALTIVEC + | PPC_OPCODE_32), + 0 }, + { "7455", (PPC_OPCODE_PPC | PPC_OPCODE_CLASSIC | PPC_OPCODE_ALTIVEC + | PPC_OPCODE_32), + 0 }, + { "750cl", (PPC_OPCODE_PPC | PPC_OPCODE_PPCPS) + , 0 }, + { "altivec", (PPC_OPCODE_PPC | PPC_OPCODE_CLASSIC), + PPC_OPCODE_ALTIVEC }, + { "any", 0, + PPC_OPCODE_ANY }, + { "booke", (PPC_OPCODE_PPC | PPC_OPCODE_BOOKE | PPC_OPCODE_32), + 0 }, + { "booke32", (PPC_OPCODE_PPC | PPC_OPCODE_BOOKE | PPC_OPCODE_32), + 0 }, + { "cell", (PPC_OPCODE_PPC | PPC_OPCODE_CLASSIC | PPC_OPCODE_64 + | PPC_OPCODE_POWER4 | PPC_OPCODE_CELL | PPC_OPCODE_ALTIVEC), + 0 }, + { "com", (PPC_OPCODE_COMMON | PPC_OPCODE_32), + 0 }, + { "e300", (PPC_OPCODE_PPC | PPC_OPCODE_CLASSIC | PPC_OPCODE_32 + | PPC_OPCODE_E300), + 0 }, + { "e500", (PPC_OPCODE_PPC | PPC_OPCODE_BOOKE | PPC_OPCODE_SPE + | PPC_OPCODE_ISEL | PPC_OPCODE_EFS | PPC_OPCODE_BRLOCK + | PPC_OPCODE_PMR | PPC_OPCODE_CACHELCK | PPC_OPCODE_RFMCI + | PPC_OPCODE_E500MC), + 0 }, + { "e500mc", (PPC_OPCODE_PPC | PPC_OPCODE_BOOKE | PPC_OPCODE_ISEL + | PPC_OPCODE_PMR | PPC_OPCODE_CACHELCK | PPC_OPCODE_RFMCI + | PPC_OPCODE_E500MC), + 0 }, + { "e500x2", (PPC_OPCODE_PPC | PPC_OPCODE_BOOKE | PPC_OPCODE_SPE + | PPC_OPCODE_ISEL | PPC_OPCODE_EFS | PPC_OPCODE_BRLOCK + | PPC_OPCODE_PMR | PPC_OPCODE_CACHELCK | PPC_OPCODE_RFMCI + | PPC_OPCODE_E500MC), + 0 }, + { "efs", (PPC_OPCODE_PPC | PPC_OPCODE_EFS), + 0 }, + { "power4", (PPC_OPCODE_PPC | PPC_OPCODE_CLASSIC | PPC_OPCODE_64 + | PPC_OPCODE_POWER4), + 0 }, + { "power5", (PPC_OPCODE_PPC | PPC_OPCODE_CLASSIC | PPC_OPCODE_64 + | PPC_OPCODE_POWER4 | PPC_OPCODE_POWER5), + 0 }, + { "power6", (PPC_OPCODE_PPC | PPC_OPCODE_CLASSIC | PPC_OPCODE_64 + | PPC_OPCODE_POWER4 | PPC_OPCODE_POWER5 | PPC_OPCODE_POWER6 + | PPC_OPCODE_ALTIVEC), + 0 }, + { "power7", (PPC_OPCODE_PPC | PPC_OPCODE_CLASSIC | PPC_OPCODE_ISEL + | PPC_OPCODE_64 | PPC_OPCODE_POWER4 | PPC_OPCODE_POWER5 + | PPC_OPCODE_POWER6 | PPC_OPCODE_POWER7 | PPC_OPCODE_ALTIVEC + | PPC_OPCODE_VSX), + 0 }, + { "ppc", (PPC_OPCODE_PPC | PPC_OPCODE_CLASSIC | PPC_OPCODE_32), + 0 }, + { "ppc32", (PPC_OPCODE_PPC | PPC_OPCODE_CLASSIC | PPC_OPCODE_32), + 0 }, + { "ppc64", (PPC_OPCODE_PPC | PPC_OPCODE_CLASSIC | PPC_OPCODE_64), + 0 }, + { "ppc64bridge", (PPC_OPCODE_PPC | PPC_OPCODE_CLASSIC | PPC_OPCODE_64_BRIDGE + | PPC_OPCODE_64), + 0 }, + { "a2", (PPC_OPCODE_PPC | PPC_OPCODE_CLASSIC | PPC_OPCODE_ISEL + | PPC_OPCODE_POWER4 | PPC_OPCODE_POWER5 | PPC_OPCODE_CACHELCK + | PPC_OPCODE_64 | PPC_OPCODE_A2), + 0 }, + { "ppcps", (PPC_OPCODE_PPC | PPC_OPCODE_PPCPS), + 0 }, + { "pwr", (PPC_OPCODE_POWER | PPC_OPCODE_32), + 0 }, + { "pwr2", (PPC_OPCODE_POWER | PPC_OPCODE_POWER2 | PPC_OPCODE_32), + 0 }, + { "pwrx", (PPC_OPCODE_POWER | PPC_OPCODE_POWER2 | PPC_OPCODE_32), + 0 }, + { "spe", (PPC_OPCODE_PPC | PPC_OPCODE_EFS), + PPC_OPCODE_SPE }, + { "vsx", (PPC_OPCODE_PPC | PPC_OPCODE_CLASSIC), + PPC_OPCODE_VSX }, +}; + +/* Handle -m and -M options that set cpu type, and .machine arg. */ + +ppc_cpu_t +ppc_parse_cpu (ppc_cpu_t ppc_cpu, const char *arg) +{ + /* Sticky bits. */ + ppc_cpu_t retain_flags = ppc_cpu & (PPC_OPCODE_ALTIVEC | PPC_OPCODE_VSX + | PPC_OPCODE_SPE | PPC_OPCODE_ANY); + unsigned int i; + + for (i = 0; i < sizeof (ppc_opts) / sizeof (ppc_opts[0]); i++) + if (strcmp (ppc_opts[i].opt, arg) == 0) + { + if (ppc_opts[i].sticky) + { + retain_flags |= ppc_opts[i].sticky; + if ((ppc_cpu & ~(PPC_OPCODE_ALTIVEC | PPC_OPCODE_VSX + | PPC_OPCODE_SPE | PPC_OPCODE_ANY)) != 0) + break; + } + ppc_cpu = ppc_opts[i].cpu; + break; + } + if (i >= sizeof (ppc_opts) / sizeof (ppc_opts[0])) + return 0; -/* Determine which set of machines to disassemble for. PPC403/601 or - BookE. For convenience, also disassemble instructions supported - by the AltiVec vector unit. */ + ppc_cpu |= retain_flags; + return ppc_cpu; +} + +/* Determine which set of machines to disassemble for. */ static int -powerpc_dialect (struct disassemble_info *info) +powerpc_init_dialect (struct disassemble_info *info) { - int dialect = PPC_OPCODE_PPC; - - if (BFD_DEFAULT_TARGET_SIZE == 64) - dialect |= PPC_OPCODE_64; - - if (info->disassembler_options - && strstr (info->disassembler_options, "booke") != NULL) - dialect |= PPC_OPCODE_BOOKE | PPC_OPCODE_BOOKE64; - else if ((info->mach == bfd_mach_ppc_e500) - || (info->disassembler_options - && strstr (info->disassembler_options, "e500") != NULL)) - dialect |= (PPC_OPCODE_BOOKE - | PPC_OPCODE_SPE | PPC_OPCODE_ISEL - | PPC_OPCODE_EFS | PPC_OPCODE_BRLOCK - | PPC_OPCODE_PMR | PPC_OPCODE_CACHELCK - | PPC_OPCODE_RFMCI); - else if (info->disassembler_options - && strstr (info->disassembler_options, "efs") != NULL) - dialect |= PPC_OPCODE_EFS; - else if (info->disassembler_options - && strstr (info->disassembler_options, "e300") != NULL) - dialect |= PPC_OPCODE_E300 | PPC_OPCODE_CLASSIC | PPC_OPCODE_COMMON; - else if (info->disassembler_options - && strstr (info->disassembler_options, "440") != NULL) - dialect |= PPC_OPCODE_BOOKE | PPC_OPCODE_32 - | PPC_OPCODE_440 | PPC_OPCODE_ISEL | PPC_OPCODE_RFMCI; - else - dialect |= (PPC_OPCODE_403 | PPC_OPCODE_601 | PPC_OPCODE_CLASSIC - | PPC_OPCODE_COMMON | PPC_OPCODE_ALTIVEC); + ppc_cpu_t dialect = 0; + char *arg; + struct dis_private *priv = calloc (sizeof (*priv), 1); - if (info->disassembler_options - && strstr (info->disassembler_options, "power4") != NULL) - dialect |= PPC_OPCODE_POWER4; + if (priv == NULL) + return FALSE; - if (info->disassembler_options - && strstr (info->disassembler_options, "power5") != NULL) - dialect |= PPC_OPCODE_POWER4 | PPC_OPCODE_POWER5; + arg = info->disassembler_options; + while (arg != NULL) + { + ppc_cpu_t new_cpu = 0; + char *end = strchr (arg, ','); - if (info->disassembler_options - && strstr (info->disassembler_options, "cell") != NULL) - dialect |= PPC_OPCODE_POWER4 | PPC_OPCODE_CELL | PPC_OPCODE_ALTIVEC; + if (end != NULL) + *end = 0; - if (info->disassembler_options - && strstr (info->disassembler_options, "power6") != NULL) - dialect |= PPC_OPCODE_POWER4 | PPC_OPCODE_POWER5 | PPC_OPCODE_POWER6 | PPC_OPCODE_ALTIVEC; + if ((new_cpu = ppc_parse_cpu (dialect, arg)) != 0) + dialect = new_cpu; + else if (strcmp (arg, "32") == 0) + { + dialect &= ~PPC_OPCODE_64; + dialect |= PPC_OPCODE_32; + } + else if (strcmp (arg, "64") == 0) + { + dialect |= PPC_OPCODE_64; + dialect &= ~PPC_OPCODE_32; + } + else + fprintf (stderr, _("warning: ignoring unknown -M%s option\n"), arg); - if (info->disassembler_options - && strstr (info->disassembler_options, "any") != NULL) - dialect |= PPC_OPCODE_ANY; + if (end != NULL) + *end++ = ','; + arg = end; + } - if (info->disassembler_options) + if ((dialect & ~(PPC_OPCODE_32 | PPC_OPCODE_64)) == 0) { - if (strstr (info->disassembler_options, "32") != NULL) - dialect &= ~PPC_OPCODE_64; - else if (strstr (info->disassembler_options, "64") != NULL) + if (info->mach == bfd_mach_ppc64) dialect |= PPC_OPCODE_64; + else + dialect |= PPC_OPCODE_32; + /* Choose a reasonable default. */ + dialect |= (PPC_OPCODE_PPC | PPC_OPCODE_COMMON | PPC_OPCODE_CLASSIC + | PPC_OPCODE_601 | PPC_OPCODE_ALTIVEC); } - info->private_data = (char *) 0 + dialect; - return dialect; + info->private_data = priv; + POWERPC_DIALECT(info) = dialect; + + return TRUE; } /* Print a big endian PowerPC instruction. */ @@ -107,8 +256,9 @@ powerpc_dialect (struct disassemble_info *info) int print_insn_big_powerpc (bfd_vma memaddr, struct disassemble_info *info) { - int dialect = (char *) info->private_data - (char *) 0; - return print_insn_powerpc (memaddr, info, 1, dialect); + if (info->private_data == NULL && !powerpc_init_dialect (info)) + return -1; + return print_insn_powerpc (memaddr, info, 1, POWERPC_DIALECT(info)); } /* Print a little endian PowerPC instruction. */ @@ -116,8 +266,9 @@ print_insn_big_powerpc (bfd_vma memaddr, struct disassemble_info *info) int print_insn_little_powerpc (bfd_vma memaddr, struct disassemble_info *info) { - int dialect = (char *) info->private_data - (char *) 0; - return print_insn_powerpc (memaddr, info, 0, dialect); + if (info->private_data == NULL && !powerpc_init_dialect (info)) + return -1; + return print_insn_powerpc (memaddr, info, 0, POWERPC_DIALECT(info)); } /* Print a POWER (RS/6000) instruction. */ @@ -132,7 +283,7 @@ print_insn_rs6000 (bfd_vma memaddr, struct disassemble_info *info) static long operand_value_powerpc (const struct powerpc_operand *operand, - unsigned long insn, int dialect) + unsigned long insn, ppc_cpu_t dialect) { long value; int invalid; @@ -162,7 +313,7 @@ operand_value_powerpc (const struct powerpc_operand *operand, static int skip_optional_operands (const unsigned char *opindex, - unsigned long insn, int dialect) + unsigned long insn, ppc_cpu_t dialect) { const struct powerpc_operand *operand; @@ -184,7 +335,7 @@ static int print_insn_powerpc (bfd_vma memaddr, struct disassemble_info *info, int bigendian, - int dialect) + ppc_cpu_t dialect) { bfd_byte buffer[4]; int status; @@ -192,9 +343,7 @@ print_insn_powerpc (bfd_vma memaddr, const struct powerpc_opcode *opcode; const struct powerpc_opcode *opcode_end; unsigned long op; - - if (dialect == 0) - dialect = powerpc_dialect (info); + ppc_cpu_t dialect_orig = dialect; status = (*info->read_memory_func) (memaddr, buffer, 4, info); if (status != 0) @@ -232,7 +381,8 @@ print_insn_powerpc (bfd_vma memaddr, continue; if ((insn & opcode->mask) != opcode->opcode - || (opcode->flags & dialect) == 0) + || (opcode->flags & dialect) == 0 + || (opcode->deprecated & dialect_orig) != 0) continue; /* Make two passes over the operands. First see if any of them @@ -297,14 +447,20 @@ print_insn_powerpc (bfd_vma memaddr, (*info->fprintf_func) (info->stream, "f%ld", value); else if ((operand->flags & PPC_OPERAND_VR) != 0) (*info->fprintf_func) (info->stream, "v%ld", value); + else if ((operand->flags & PPC_OPERAND_VSR) != 0) + (*info->fprintf_func) (info->stream, "vs%ld", value); else if ((operand->flags & PPC_OPERAND_RELATIVE) != 0) (*info->print_address_func) (memaddr + value, info); else if ((operand->flags & PPC_OPERAND_ABSOLUTE) != 0) (*info->print_address_func) ((bfd_vma) value & 0xffffffff, info); - else if ((operand->flags & PPC_OPERAND_CR) == 0 - || (dialect & PPC_OPCODE_PPC) == 0) + else if ((operand->flags & PPC_OPERAND_FSL) != 0) + (*info->fprintf_func) (info->stream, "fsl%ld", value); + else if ((operand->flags & PPC_OPERAND_FCR) != 0) + (*info->fprintf_func) (info->stream, "fcr%ld", value); + else if ((operand->flags & PPC_OPERAND_UDI) != 0) (*info->fprintf_func) (info->stream, "%ld", value); - else + else if ((operand->flags & PPC_OPERAND_CR) != 0 + && (dialect & PPC_OPCODE_PPC) != 0) { if (operand->bitm == 7) (*info->fprintf_func) (info->stream, "cr%ld", value); @@ -321,6 +477,8 @@ print_insn_powerpc (bfd_vma memaddr, (*info->fprintf_func) (info->stream, "%s", cbnames[cc]); } } + else + (*info->fprintf_func) (info->stream, "%ld", value); if (need_paren) { @@ -356,18 +514,20 @@ print_insn_powerpc (bfd_vma memaddr, void print_ppc_disassembler_options (FILE *stream) { - fprintf (stream, "\n\ + unsigned int i, col; + + fprintf (stream, _("\n\ The following PPC specific disassembler options are supported for use with\n\ -the -M switch:\n"); - - fprintf (stream, " booke|booke32|booke64 Disassemble the BookE instructions\n"); - fprintf (stream, " e300 Disassemble the e300 instructions\n"); - fprintf (stream, " e500|e500x2 Disassemble the e500 instructions\n"); - fprintf (stream, " 440 Disassemble the 440 instructions\n"); - fprintf (stream, " efs Disassemble the EFS instructions\n"); - fprintf (stream, " power4 Disassemble the Power4 instructions\n"); - fprintf (stream, " power5 Disassemble the Power5 instructions\n"); - fprintf (stream, " power6 Disassemble the Power6 instructions\n"); - fprintf (stream, " 32 Do not disassemble 64-bit instructions\n"); - fprintf (stream, " 64 Allow disassembly of 64-bit instructions\n"); +the -M switch:\n")); + + for (col = 0, i = 0; i < sizeof (ppc_opts) / sizeof (ppc_opts[0]); i++) + { + col += fprintf (stream, " %s,", ppc_opts[i].opt); + if (col > 66) + { + fprintf (stream, "\n"); + col = 0; + } + } + fprintf (stream, " 32, 64\n"); }