ppc-dis.c revision 104834
160484Sobrien/* ppc-dis.c -- Disassemble PowerPC instructions 292828Sobrien Copyright 1994, 1995, 2000, 2001, 2002 Free Software Foundation, Inc. 360484Sobrien Written by Ian Lance Taylor, Cygnus Support 460484Sobrien 560484SobrienThis file is part of GDB, GAS, and the GNU binutils. 660484Sobrien 760484SobrienGDB, GAS, and the GNU binutils are free software; you can redistribute 860484Sobrienthem and/or modify them under the terms of the GNU General Public 960484SobrienLicense as published by the Free Software Foundation; either version 1060484Sobrien2, or (at your option) any later version. 1160484Sobrien 1260484SobrienGDB, GAS, and the GNU binutils are distributed in the hope that they 1360484Sobrienwill be useful, but WITHOUT ANY WARRANTY; without even the implied 1460484Sobrienwarranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See 1560484Sobrienthe GNU General Public License for more details. 1660484Sobrien 1760484SobrienYou should have received a copy of the GNU General Public License 1860484Sobrienalong with this file; see the file COPYING. If not, write to the Free 1960484SobrienSoftware Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ 2060484Sobrien 2160484Sobrien#include <stdio.h> 2260484Sobrien#include "sysdep.h" 2360484Sobrien#include "dis-asm.h" 2460484Sobrien#include "opcode/ppc.h" 2560484Sobrien 2660484Sobrien/* This file provides several disassembler functions, all of which use 2760484Sobrien the disassembler interface defined in dis-asm.h. Several functions 2860484Sobrien are provided because this file handles disassembly for the PowerPC 2960484Sobrien in both big and little endian mode and also for the POWER (RS/6000) 3060484Sobrien chip. */ 3160484Sobrien 3260484Sobrienstatic int print_insn_powerpc PARAMS ((bfd_vma, struct disassemble_info *, 3360484Sobrien int bigendian, int dialect)); 3460484Sobrien 3589857Sobrienstatic int powerpc_dialect PARAMS ((struct disassemble_info *)); 3660484Sobrien 3789857Sobrien/* Determine which set of machines to disassemble for. PPC403/601 or 3892828Sobrien BookE. For convenience, also disassemble instructions supported 3992828Sobrien by the AltiVec vector unit. */ 4089857Sobrien 4160484Sobrienint 4289857Sobrienpowerpc_dialect(info) 4389857Sobrien struct disassemble_info *info; 4489857Sobrien{ 4589857Sobrien int dialect = PPC_OPCODE_PPC | PPC_OPCODE_ALTIVEC; 4689857Sobrien 4789857Sobrien if (BFD_DEFAULT_TARGET_SIZE == 64) 4889857Sobrien dialect |= PPC_OPCODE_64; 4989857Sobrien 5089857Sobrien if (info->disassembler_options 5189857Sobrien && (strcmp (info->disassembler_options, "booke") == 0 5289857Sobrien || strcmp (info->disassembler_options, "booke32") == 0 5389857Sobrien || strcmp (info->disassembler_options, "booke64") == 0)) 5489857Sobrien dialect |= PPC_OPCODE_BOOKE | PPC_OPCODE_BOOKE64; 5589857Sobrien else 5689857Sobrien dialect |= PPC_OPCODE_403 | PPC_OPCODE_601; 5789857Sobrien 5892828Sobrien if (info->disassembler_options 5992828Sobrien && strcmp (info->disassembler_options, "power4") == 0) 6092828Sobrien dialect |= PPC_OPCODE_POWER4; 6192828Sobrien 6289857Sobrien if (info->disassembler_options) 6389857Sobrien { 6489857Sobrien if (strstr (info->disassembler_options, "32") != NULL) 6589857Sobrien dialect &= ~PPC_OPCODE_64; 6689857Sobrien else if (strstr (info->disassembler_options, "64") != NULL) 6789857Sobrien dialect |= PPC_OPCODE_64; 6889857Sobrien } 6989857Sobrien 7089857Sobrien return dialect; 7189857Sobrien} 7289857Sobrien 7389857Sobrien/* Print a big endian PowerPC instruction. */ 7489857Sobrien 7589857Sobrienint 7660484Sobrienprint_insn_big_powerpc (memaddr, info) 7760484Sobrien bfd_vma memaddr; 7860484Sobrien struct disassemble_info *info; 7960484Sobrien{ 8089857Sobrien return print_insn_powerpc (memaddr, info, 1, powerpc_dialect(info)); 8160484Sobrien} 8260484Sobrien 8389857Sobrien/* Print a little endian PowerPC instruction. */ 8460484Sobrien 8560484Sobrienint 8660484Sobrienprint_insn_little_powerpc (memaddr, info) 8760484Sobrien bfd_vma memaddr; 8860484Sobrien struct disassemble_info *info; 8960484Sobrien{ 9089857Sobrien return print_insn_powerpc (memaddr, info, 0, powerpc_dialect(info)); 9160484Sobrien} 9260484Sobrien 9360484Sobrien/* Print a POWER (RS/6000) instruction. */ 9460484Sobrien 9560484Sobrienint 9660484Sobrienprint_insn_rs6000 (memaddr, info) 9760484Sobrien bfd_vma memaddr; 9860484Sobrien struct disassemble_info *info; 9960484Sobrien{ 10060484Sobrien return print_insn_powerpc (memaddr, info, 1, PPC_OPCODE_POWER); 10160484Sobrien} 10260484Sobrien 10360484Sobrien/* Print a PowerPC or POWER instruction. */ 10460484Sobrien 10560484Sobrienstatic int 10660484Sobrienprint_insn_powerpc (memaddr, info, bigendian, dialect) 10760484Sobrien bfd_vma memaddr; 10860484Sobrien struct disassemble_info *info; 10960484Sobrien int bigendian; 11060484Sobrien int dialect; 11160484Sobrien{ 11260484Sobrien bfd_byte buffer[4]; 11360484Sobrien int status; 11460484Sobrien unsigned long insn; 11560484Sobrien const struct powerpc_opcode *opcode; 11660484Sobrien const struct powerpc_opcode *opcode_end; 11760484Sobrien unsigned long op; 11860484Sobrien 11960484Sobrien status = (*info->read_memory_func) (memaddr, buffer, 4, info); 12060484Sobrien if (status != 0) 12160484Sobrien { 12260484Sobrien (*info->memory_error_func) (status, memaddr, info); 12360484Sobrien return -1; 12460484Sobrien } 12560484Sobrien 12660484Sobrien if (bigendian) 12760484Sobrien insn = bfd_getb32 (buffer); 12860484Sobrien else 12960484Sobrien insn = bfd_getl32 (buffer); 13060484Sobrien 13160484Sobrien /* Get the major opcode of the instruction. */ 13260484Sobrien op = PPC_OP (insn); 13360484Sobrien 13460484Sobrien /* Find the first match in the opcode table. We could speed this up 13560484Sobrien a bit by doing a binary search on the major opcode. */ 13660484Sobrien opcode_end = powerpc_opcodes + powerpc_num_opcodes; 13760484Sobrien for (opcode = powerpc_opcodes; opcode < opcode_end; opcode++) 13860484Sobrien { 13960484Sobrien unsigned long table_op; 14060484Sobrien const unsigned char *opindex; 14160484Sobrien const struct powerpc_operand *operand; 14260484Sobrien int invalid; 14360484Sobrien int need_comma; 14460484Sobrien int need_paren; 14560484Sobrien 14660484Sobrien table_op = PPC_OP (opcode->opcode); 14760484Sobrien if (op < table_op) 14860484Sobrien break; 14960484Sobrien if (op > table_op) 15060484Sobrien continue; 15160484Sobrien 15260484Sobrien if ((insn & opcode->mask) != opcode->opcode 15360484Sobrien || (opcode->flags & dialect) == 0) 15460484Sobrien continue; 15560484Sobrien 15660484Sobrien /* Make two passes over the operands. First see if any of them 15760484Sobrien have extraction functions, and, if they do, make sure the 15860484Sobrien instruction is valid. */ 15960484Sobrien invalid = 0; 16060484Sobrien for (opindex = opcode->operands; *opindex != 0; opindex++) 16160484Sobrien { 16260484Sobrien operand = powerpc_operands + *opindex; 16360484Sobrien if (operand->extract) 16489857Sobrien (*operand->extract) (insn, dialect, &invalid); 16560484Sobrien } 16660484Sobrien if (invalid) 16760484Sobrien continue; 16860484Sobrien 16960484Sobrien /* The instruction is valid. */ 17060484Sobrien (*info->fprintf_func) (info->stream, "%s", opcode->name); 17160484Sobrien if (opcode->operands[0] != 0) 17260484Sobrien (*info->fprintf_func) (info->stream, "\t"); 17360484Sobrien 17460484Sobrien /* Now extract and print the operands. */ 17560484Sobrien need_comma = 0; 17660484Sobrien need_paren = 0; 17760484Sobrien for (opindex = opcode->operands; *opindex != 0; opindex++) 17860484Sobrien { 17960484Sobrien long value; 18060484Sobrien 18160484Sobrien operand = powerpc_operands + *opindex; 18260484Sobrien 18360484Sobrien /* Operands that are marked FAKE are simply ignored. We 18460484Sobrien already made sure that the extract function considered 18560484Sobrien the instruction to be valid. */ 18660484Sobrien if ((operand->flags & PPC_OPERAND_FAKE) != 0) 18760484Sobrien continue; 18860484Sobrien 18960484Sobrien /* Extract the value from the instruction. */ 19060484Sobrien if (operand->extract) 19189857Sobrien value = (*operand->extract) (insn, dialect, (int *) NULL); 19260484Sobrien else 19360484Sobrien { 19460484Sobrien value = (insn >> operand->shift) & ((1 << operand->bits) - 1); 19560484Sobrien if ((operand->flags & PPC_OPERAND_SIGNED) != 0 19660484Sobrien && (value & (1 << (operand->bits - 1))) != 0) 19760484Sobrien value -= 1 << operand->bits; 19860484Sobrien } 19960484Sobrien 20060484Sobrien /* If the operand is optional, and the value is zero, don't 20160484Sobrien print anything. */ 20260484Sobrien if ((operand->flags & PPC_OPERAND_OPTIONAL) != 0 20360484Sobrien && (operand->flags & PPC_OPERAND_NEXT) == 0 20460484Sobrien && value == 0) 20560484Sobrien continue; 20660484Sobrien 20760484Sobrien if (need_comma) 20860484Sobrien { 20960484Sobrien (*info->fprintf_func) (info->stream, ","); 21060484Sobrien need_comma = 0; 21160484Sobrien } 21260484Sobrien 21360484Sobrien /* Print the operand as directed by the flags. */ 21460484Sobrien if ((operand->flags & PPC_OPERAND_GPR) != 0) 21560484Sobrien (*info->fprintf_func) (info->stream, "r%ld", value); 21660484Sobrien else if ((operand->flags & PPC_OPERAND_FPR) != 0) 21760484Sobrien (*info->fprintf_func) (info->stream, "f%ld", value); 21877298Sobrien else if ((operand->flags & PPC_OPERAND_VR) != 0) 21977298Sobrien (*info->fprintf_func) (info->stream, "v%ld", value); 22060484Sobrien else if ((operand->flags & PPC_OPERAND_RELATIVE) != 0) 22160484Sobrien (*info->print_address_func) (memaddr + value, info); 22260484Sobrien else if ((operand->flags & PPC_OPERAND_ABSOLUTE) != 0) 22360484Sobrien (*info->print_address_func) ((bfd_vma) value & 0xffffffff, info); 22460484Sobrien else if ((operand->flags & PPC_OPERAND_CR) == 0 22560484Sobrien || (dialect & PPC_OPCODE_PPC) == 0) 22660484Sobrien (*info->fprintf_func) (info->stream, "%ld", value); 22760484Sobrien else 22860484Sobrien { 22960484Sobrien if (operand->bits == 3) 23060484Sobrien (*info->fprintf_func) (info->stream, "cr%d", value); 23160484Sobrien else 23260484Sobrien { 23360484Sobrien static const char *cbnames[4] = { "lt", "gt", "eq", "so" }; 23460484Sobrien int cr; 23560484Sobrien int cc; 23660484Sobrien 23760484Sobrien cr = value >> 2; 23860484Sobrien if (cr != 0) 23960484Sobrien (*info->fprintf_func) (info->stream, "4*cr%d", cr); 24060484Sobrien cc = value & 3; 24160484Sobrien if (cc != 0) 24260484Sobrien { 24360484Sobrien if (cr != 0) 24460484Sobrien (*info->fprintf_func) (info->stream, "+"); 24560484Sobrien (*info->fprintf_func) (info->stream, "%s", cbnames[cc]); 24660484Sobrien } 24760484Sobrien } 24860484Sobrien } 24960484Sobrien 25060484Sobrien if (need_paren) 25160484Sobrien { 25260484Sobrien (*info->fprintf_func) (info->stream, ")"); 25360484Sobrien need_paren = 0; 25460484Sobrien } 25560484Sobrien 25660484Sobrien if ((operand->flags & PPC_OPERAND_PARENS) == 0) 25760484Sobrien need_comma = 1; 25860484Sobrien else 25960484Sobrien { 26060484Sobrien (*info->fprintf_func) (info->stream, "("); 26160484Sobrien need_paren = 1; 26260484Sobrien } 26360484Sobrien } 26460484Sobrien 26560484Sobrien /* We have found and printed an instruction; return. */ 26660484Sobrien return 4; 26760484Sobrien } 26860484Sobrien 26960484Sobrien /* We could not find a match. */ 27060484Sobrien (*info->fprintf_func) (info->stream, ".long 0x%lx", insn); 27160484Sobrien 27260484Sobrien return 4; 27360484Sobrien} 274104834Sobrien 275104834Sobrienvoid 276104834Sobrienprint_ppc_disassembler_options (FILE * stream) 277104834Sobrien{ 278104834Sobrien fprintf (stream, "\n\ 279104834SobrienThe following PPC specific disassembler options are supported for use with\n\ 280104834Sobrienthe -M switch:\n"); 281104834Sobrien 282104834Sobrien fprintf (stream, " booke|booke32|booke64 Disassemble the BookE instructions\n"); 283104834Sobrien fprintf (stream, " power4 Disassemble the Power4 instructions\n"); 284104834Sobrien fprintf (stream, " 32 Do not disassemble 64-bit instructions\n"); 285104834Sobrien fprintf (stream, " 64 Allow disassembly of 64-bit instructions\n"); 286104834Sobrien} 287