160484Sobrien/* ppc-dis.c -- Disassemble PowerPC instructions 2218822Sdim Copyright 1994, 1995, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007 3130561Sobrien Free Software Foundation, Inc. 460484Sobrien Written by Ian Lance Taylor, Cygnus Support 560484Sobrien 660484SobrienThis file is part of GDB, GAS, and the GNU binutils. 760484Sobrien 860484SobrienGDB, GAS, and the GNU binutils are free software; you can redistribute 960484Sobrienthem and/or modify them under the terms of the GNU General Public 1060484SobrienLicense as published by the Free Software Foundation; either version 1160484Sobrien2, or (at your option) any later version. 1260484Sobrien 1360484SobrienGDB, GAS, and the GNU binutils are distributed in the hope that they 1460484Sobrienwill be useful, but WITHOUT ANY WARRANTY; without even the implied 1560484Sobrienwarranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See 1660484Sobrienthe GNU General Public License for more details. 1760484Sobrien 1860484SobrienYou should have received a copy of the GNU General Public License 1960484Sobrienalong with this file; see the file COPYING. If not, write to the Free 20218822SdimSoftware Foundation, 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA. */ 2160484Sobrien 2260484Sobrien#include <stdio.h> 2360484Sobrien#include "sysdep.h" 2460484Sobrien#include "dis-asm.h" 2560484Sobrien#include "opcode/ppc.h" 2660484Sobrien 2760484Sobrien/* This file provides several disassembler functions, all of which use 2860484Sobrien the disassembler interface defined in dis-asm.h. Several functions 2960484Sobrien are provided because this file handles disassembly for the PowerPC 3060484Sobrien in both big and little endian mode and also for the POWER (RS/6000) 3160484Sobrien chip. */ 3260484Sobrien 33130561Sobrienstatic int print_insn_powerpc (bfd_vma, struct disassemble_info *, int, int); 3460484Sobrien 3589857Sobrien/* Determine which set of machines to disassemble for. PPC403/601 or 3692828Sobrien BookE. For convenience, also disassemble instructions supported 3792828Sobrien by the AltiVec vector unit. */ 3889857Sobrien 39130561Sobrienstatic int 40130561Sobrienpowerpc_dialect (struct disassemble_info *info) 4189857Sobrien{ 42218822Sdim int dialect = PPC_OPCODE_PPC; 4389857Sobrien 4489857Sobrien if (BFD_DEFAULT_TARGET_SIZE == 64) 4589857Sobrien dialect |= PPC_OPCODE_64; 4689857Sobrien 4789857Sobrien if (info->disassembler_options 48130561Sobrien && strstr (info->disassembler_options, "booke") != NULL) 4989857Sobrien dialect |= PPC_OPCODE_BOOKE | PPC_OPCODE_BOOKE64; 50130561Sobrien else if ((info->mach == bfd_mach_ppc_e500) 51130561Sobrien || (info->disassembler_options 52130561Sobrien && strstr (info->disassembler_options, "e500") != NULL)) 53218822Sdim dialect |= (PPC_OPCODE_BOOKE 54218822Sdim | PPC_OPCODE_SPE | PPC_OPCODE_ISEL 55218822Sdim | PPC_OPCODE_EFS | PPC_OPCODE_BRLOCK 56218822Sdim | PPC_OPCODE_PMR | PPC_OPCODE_CACHELCK 57218822Sdim | PPC_OPCODE_RFMCI); 58130561Sobrien else if (info->disassembler_options 59130561Sobrien && strstr (info->disassembler_options, "efs") != NULL) 60218822Sdim dialect |= PPC_OPCODE_EFS; 61218822Sdim else if (info->disassembler_options 62218822Sdim && strstr (info->disassembler_options, "e300") != NULL) 63218822Sdim dialect |= PPC_OPCODE_E300 | PPC_OPCODE_CLASSIC | PPC_OPCODE_COMMON; 64218822Sdim else if (info->disassembler_options 65218822Sdim && strstr (info->disassembler_options, "440") != NULL) 66218822Sdim dialect |= PPC_OPCODE_BOOKE | PPC_OPCODE_32 67218822Sdim | PPC_OPCODE_440 | PPC_OPCODE_ISEL | PPC_OPCODE_RFMCI; 68130561Sobrien else 69130561Sobrien dialect |= (PPC_OPCODE_403 | PPC_OPCODE_601 | PPC_OPCODE_CLASSIC 70218822Sdim | PPC_OPCODE_COMMON | PPC_OPCODE_ALTIVEC); 7189857Sobrien 7292828Sobrien if (info->disassembler_options 73130561Sobrien && strstr (info->disassembler_options, "power4") != NULL) 7492828Sobrien dialect |= PPC_OPCODE_POWER4; 7592828Sobrien 76130561Sobrien if (info->disassembler_options 77218822Sdim && strstr (info->disassembler_options, "power5") != NULL) 78218822Sdim dialect |= PPC_OPCODE_POWER4 | PPC_OPCODE_POWER5; 79218822Sdim 80218822Sdim if (info->disassembler_options 81218822Sdim && strstr (info->disassembler_options, "cell") != NULL) 82218822Sdim dialect |= PPC_OPCODE_POWER4 | PPC_OPCODE_CELL | PPC_OPCODE_ALTIVEC; 83218822Sdim 84218822Sdim if (info->disassembler_options 85218822Sdim && strstr (info->disassembler_options, "power6") != NULL) 86218822Sdim dialect |= PPC_OPCODE_POWER4 | PPC_OPCODE_POWER5 | PPC_OPCODE_POWER6 | PPC_OPCODE_ALTIVEC; 87218822Sdim 88218822Sdim if (info->disassembler_options 89130561Sobrien && strstr (info->disassembler_options, "any") != NULL) 90130561Sobrien dialect |= PPC_OPCODE_ANY; 91130561Sobrien 9289857Sobrien if (info->disassembler_options) 9389857Sobrien { 9489857Sobrien if (strstr (info->disassembler_options, "32") != NULL) 9589857Sobrien dialect &= ~PPC_OPCODE_64; 9689857Sobrien else if (strstr (info->disassembler_options, "64") != NULL) 9789857Sobrien dialect |= PPC_OPCODE_64; 9889857Sobrien } 9989857Sobrien 100218822Sdim info->private_data = (char *) 0 + dialect; 10189857Sobrien return dialect; 10289857Sobrien} 10389857Sobrien 10489857Sobrien/* Print a big endian PowerPC instruction. */ 10589857Sobrien 10689857Sobrienint 107130561Sobrienprint_insn_big_powerpc (bfd_vma memaddr, struct disassemble_info *info) 10860484Sobrien{ 109218822Sdim int dialect = (char *) info->private_data - (char *) 0; 110130561Sobrien return print_insn_powerpc (memaddr, info, 1, dialect); 11160484Sobrien} 11260484Sobrien 11389857Sobrien/* Print a little endian PowerPC instruction. */ 11460484Sobrien 11560484Sobrienint 116130561Sobrienprint_insn_little_powerpc (bfd_vma memaddr, struct disassemble_info *info) 11760484Sobrien{ 118218822Sdim int dialect = (char *) info->private_data - (char *) 0; 119130561Sobrien return print_insn_powerpc (memaddr, info, 0, dialect); 12060484Sobrien} 12160484Sobrien 12260484Sobrien/* Print a POWER (RS/6000) instruction. */ 12360484Sobrien 12460484Sobrienint 125130561Sobrienprint_insn_rs6000 (bfd_vma memaddr, struct disassemble_info *info) 12660484Sobrien{ 12760484Sobrien return print_insn_powerpc (memaddr, info, 1, PPC_OPCODE_POWER); 12860484Sobrien} 12960484Sobrien 130218822Sdim/* Extract the operand value from the PowerPC or POWER instruction. */ 131218822Sdim 132218822Sdimstatic long 133218822Sdimoperand_value_powerpc (const struct powerpc_operand *operand, 134218822Sdim unsigned long insn, int dialect) 135218822Sdim{ 136218822Sdim long value; 137218822Sdim int invalid; 138218822Sdim /* Extract the value from the instruction. */ 139218822Sdim if (operand->extract) 140218822Sdim value = (*operand->extract) (insn, dialect, &invalid); 141218822Sdim else 142218822Sdim { 143218822Sdim value = (insn >> operand->shift) & operand->bitm; 144218822Sdim if ((operand->flags & PPC_OPERAND_SIGNED) != 0) 145218822Sdim { 146218822Sdim /* BITM is always some number of zeros followed by some 147218822Sdim number of ones, followed by some numer of zeros. */ 148218822Sdim unsigned long top = operand->bitm; 149218822Sdim /* top & -top gives the rightmost 1 bit, so this 150218822Sdim fills in any trailing zeros. */ 151218822Sdim top |= (top & -top) - 1; 152218822Sdim top &= ~(top >> 1); 153218822Sdim value = (value ^ top) - top; 154218822Sdim } 155218822Sdim } 156218822Sdim 157218822Sdim return value; 158218822Sdim} 159218822Sdim 160218822Sdim/* Determine whether the optional operand(s) should be printed. */ 161218822Sdim 162218822Sdimstatic int 163218822Sdimskip_optional_operands (const unsigned char *opindex, 164218822Sdim unsigned long insn, int dialect) 165218822Sdim{ 166218822Sdim const struct powerpc_operand *operand; 167218822Sdim 168218822Sdim for (; *opindex != 0; opindex++) 169218822Sdim { 170218822Sdim operand = &powerpc_operands[*opindex]; 171218822Sdim if ((operand->flags & PPC_OPERAND_NEXT) != 0 172218822Sdim || ((operand->flags & PPC_OPERAND_OPTIONAL) != 0 173218822Sdim && operand_value_powerpc (operand, insn, dialect) != 0)) 174218822Sdim return 0; 175218822Sdim } 176218822Sdim 177218822Sdim return 1; 178218822Sdim} 179218822Sdim 18060484Sobrien/* Print a PowerPC or POWER instruction. */ 18160484Sobrien 18260484Sobrienstatic int 183130561Sobrienprint_insn_powerpc (bfd_vma memaddr, 184130561Sobrien struct disassemble_info *info, 185130561Sobrien int bigendian, 186130561Sobrien int dialect) 18760484Sobrien{ 18860484Sobrien bfd_byte buffer[4]; 18960484Sobrien int status; 19060484Sobrien unsigned long insn; 19160484Sobrien const struct powerpc_opcode *opcode; 19260484Sobrien const struct powerpc_opcode *opcode_end; 19360484Sobrien unsigned long op; 19460484Sobrien 195130561Sobrien if (dialect == 0) 196130561Sobrien dialect = powerpc_dialect (info); 197130561Sobrien 19860484Sobrien status = (*info->read_memory_func) (memaddr, buffer, 4, info); 19960484Sobrien if (status != 0) 20060484Sobrien { 20160484Sobrien (*info->memory_error_func) (status, memaddr, info); 20260484Sobrien return -1; 20360484Sobrien } 20460484Sobrien 20560484Sobrien if (bigendian) 20660484Sobrien insn = bfd_getb32 (buffer); 20760484Sobrien else 20860484Sobrien insn = bfd_getl32 (buffer); 20960484Sobrien 21060484Sobrien /* Get the major opcode of the instruction. */ 21160484Sobrien op = PPC_OP (insn); 21260484Sobrien 21360484Sobrien /* Find the first match in the opcode table. We could speed this up 21460484Sobrien a bit by doing a binary search on the major opcode. */ 21560484Sobrien opcode_end = powerpc_opcodes + powerpc_num_opcodes; 216130561Sobrien again: 21760484Sobrien for (opcode = powerpc_opcodes; opcode < opcode_end; opcode++) 21860484Sobrien { 21960484Sobrien unsigned long table_op; 22060484Sobrien const unsigned char *opindex; 22160484Sobrien const struct powerpc_operand *operand; 22260484Sobrien int invalid; 22360484Sobrien int need_comma; 22460484Sobrien int need_paren; 225218822Sdim int skip_optional; 22660484Sobrien 22760484Sobrien table_op = PPC_OP (opcode->opcode); 22860484Sobrien if (op < table_op) 22960484Sobrien break; 23060484Sobrien if (op > table_op) 23160484Sobrien continue; 23260484Sobrien 23360484Sobrien if ((insn & opcode->mask) != opcode->opcode 23460484Sobrien || (opcode->flags & dialect) == 0) 23560484Sobrien continue; 23660484Sobrien 23760484Sobrien /* Make two passes over the operands. First see if any of them 23860484Sobrien have extraction functions, and, if they do, make sure the 23960484Sobrien instruction is valid. */ 24060484Sobrien invalid = 0; 24160484Sobrien for (opindex = opcode->operands; *opindex != 0; opindex++) 24260484Sobrien { 24360484Sobrien operand = powerpc_operands + *opindex; 24460484Sobrien if (operand->extract) 24589857Sobrien (*operand->extract) (insn, dialect, &invalid); 24660484Sobrien } 24760484Sobrien if (invalid) 24860484Sobrien continue; 24960484Sobrien 25060484Sobrien /* The instruction is valid. */ 25160484Sobrien if (opcode->operands[0] != 0) 252130561Sobrien (*info->fprintf_func) (info->stream, "%-7s ", opcode->name); 253130561Sobrien else 254130561Sobrien (*info->fprintf_func) (info->stream, "%s", opcode->name); 25560484Sobrien 25660484Sobrien /* Now extract and print the operands. */ 25760484Sobrien need_comma = 0; 25860484Sobrien need_paren = 0; 259218822Sdim skip_optional = -1; 26060484Sobrien for (opindex = opcode->operands; *opindex != 0; opindex++) 26160484Sobrien { 26260484Sobrien long value; 26360484Sobrien 26460484Sobrien operand = powerpc_operands + *opindex; 26560484Sobrien 26660484Sobrien /* Operands that are marked FAKE are simply ignored. We 26760484Sobrien already made sure that the extract function considered 26860484Sobrien the instruction to be valid. */ 26960484Sobrien if ((operand->flags & PPC_OPERAND_FAKE) != 0) 27060484Sobrien continue; 27160484Sobrien 272218822Sdim /* If all of the optional operands have the value zero, 273218822Sdim then don't print any of them. */ 274218822Sdim if ((operand->flags & PPC_OPERAND_OPTIONAL) != 0) 27560484Sobrien { 276218822Sdim if (skip_optional < 0) 277218822Sdim skip_optional = skip_optional_operands (opindex, insn, 278218822Sdim dialect); 279218822Sdim if (skip_optional) 280218822Sdim continue; 28160484Sobrien } 28260484Sobrien 283218822Sdim value = operand_value_powerpc (operand, insn, dialect); 28460484Sobrien 28560484Sobrien if (need_comma) 28660484Sobrien { 28760484Sobrien (*info->fprintf_func) (info->stream, ","); 28860484Sobrien need_comma = 0; 28960484Sobrien } 29060484Sobrien 29160484Sobrien /* Print the operand as directed by the flags. */ 292130561Sobrien if ((operand->flags & PPC_OPERAND_GPR) != 0 293130561Sobrien || ((operand->flags & PPC_OPERAND_GPR_0) != 0 && value != 0)) 29460484Sobrien (*info->fprintf_func) (info->stream, "r%ld", value); 29560484Sobrien else if ((operand->flags & PPC_OPERAND_FPR) != 0) 29660484Sobrien (*info->fprintf_func) (info->stream, "f%ld", value); 29777298Sobrien else if ((operand->flags & PPC_OPERAND_VR) != 0) 29877298Sobrien (*info->fprintf_func) (info->stream, "v%ld", value); 29960484Sobrien else if ((operand->flags & PPC_OPERAND_RELATIVE) != 0) 30060484Sobrien (*info->print_address_func) (memaddr + value, info); 30160484Sobrien else if ((operand->flags & PPC_OPERAND_ABSOLUTE) != 0) 30260484Sobrien (*info->print_address_func) ((bfd_vma) value & 0xffffffff, info); 30360484Sobrien else if ((operand->flags & PPC_OPERAND_CR) == 0 30460484Sobrien || (dialect & PPC_OPCODE_PPC) == 0) 30560484Sobrien (*info->fprintf_func) (info->stream, "%ld", value); 30660484Sobrien else 30760484Sobrien { 308218822Sdim if (operand->bitm == 7) 309218822Sdim (*info->fprintf_func) (info->stream, "cr%ld", value); 31060484Sobrien else 31160484Sobrien { 31260484Sobrien static const char *cbnames[4] = { "lt", "gt", "eq", "so" }; 31360484Sobrien int cr; 31460484Sobrien int cc; 31560484Sobrien 31660484Sobrien cr = value >> 2; 31760484Sobrien if (cr != 0) 318130561Sobrien (*info->fprintf_func) (info->stream, "4*cr%d+", cr); 31960484Sobrien cc = value & 3; 320130561Sobrien (*info->fprintf_func) (info->stream, "%s", cbnames[cc]); 32160484Sobrien } 32260484Sobrien } 32360484Sobrien 32460484Sobrien if (need_paren) 32560484Sobrien { 32660484Sobrien (*info->fprintf_func) (info->stream, ")"); 32760484Sobrien need_paren = 0; 32860484Sobrien } 32960484Sobrien 33060484Sobrien if ((operand->flags & PPC_OPERAND_PARENS) == 0) 33160484Sobrien need_comma = 1; 33260484Sobrien else 33360484Sobrien { 33460484Sobrien (*info->fprintf_func) (info->stream, "("); 33560484Sobrien need_paren = 1; 33660484Sobrien } 33760484Sobrien } 33860484Sobrien 33960484Sobrien /* We have found and printed an instruction; return. */ 34060484Sobrien return 4; 34160484Sobrien } 34260484Sobrien 343130561Sobrien if ((dialect & PPC_OPCODE_ANY) != 0) 344130561Sobrien { 345130561Sobrien dialect = ~PPC_OPCODE_ANY; 346130561Sobrien goto again; 347130561Sobrien } 348130561Sobrien 34960484Sobrien /* We could not find a match. */ 35060484Sobrien (*info->fprintf_func) (info->stream, ".long 0x%lx", insn); 35160484Sobrien 35260484Sobrien return 4; 35360484Sobrien} 354104834Sobrien 355104834Sobrienvoid 356130561Sobrienprint_ppc_disassembler_options (FILE *stream) 357104834Sobrien{ 358104834Sobrien fprintf (stream, "\n\ 359104834SobrienThe following PPC specific disassembler options are supported for use with\n\ 360104834Sobrienthe -M switch:\n"); 361130561Sobrien 362104834Sobrien fprintf (stream, " booke|booke32|booke64 Disassemble the BookE instructions\n"); 363218822Sdim fprintf (stream, " e300 Disassemble the e300 instructions\n"); 364130561Sobrien fprintf (stream, " e500|e500x2 Disassemble the e500 instructions\n"); 365218822Sdim fprintf (stream, " 440 Disassemble the 440 instructions\n"); 366130561Sobrien fprintf (stream, " efs Disassemble the EFS instructions\n"); 367104834Sobrien fprintf (stream, " power4 Disassemble the Power4 instructions\n"); 368218822Sdim fprintf (stream, " power5 Disassemble the Power5 instructions\n"); 369218822Sdim fprintf (stream, " power6 Disassemble the Power6 instructions\n"); 370104834Sobrien fprintf (stream, " 32 Do not disassemble 64-bit instructions\n"); 371104834Sobrien fprintf (stream, " 64 Allow disassembly of 64-bit instructions\n"); 372104834Sobrien} 373