ppc-dis.c revision 89857
160484Sobrien/* ppc-dis.c -- Disassemble PowerPC instructions 278828Sobrien Copyright 1994, 1995, 2000 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 3889857Sobrien Motorola BookE. For convenience, also disassemble instructions 3989857Sobrien supported 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 5889857Sobrien if (info->disassembler_options) 5989857Sobrien { 6089857Sobrien if (strstr (info->disassembler_options, "32") != NULL) 6189857Sobrien dialect &= ~PPC_OPCODE_64; 6289857Sobrien else if (strstr (info->disassembler_options, "64") != NULL) 6389857Sobrien dialect |= PPC_OPCODE_64; 6489857Sobrien } 6589857Sobrien 6689857Sobrien return dialect; 6789857Sobrien} 6889857Sobrien 6989857Sobrien/* Print a big endian PowerPC instruction. */ 7089857Sobrien 7189857Sobrienint 7260484Sobrienprint_insn_big_powerpc (memaddr, info) 7360484Sobrien bfd_vma memaddr; 7460484Sobrien struct disassemble_info *info; 7560484Sobrien{ 7689857Sobrien return print_insn_powerpc (memaddr, info, 1, powerpc_dialect(info)); 7760484Sobrien} 7860484Sobrien 7989857Sobrien/* Print a little endian PowerPC instruction. */ 8060484Sobrien 8160484Sobrienint 8260484Sobrienprint_insn_little_powerpc (memaddr, info) 8360484Sobrien bfd_vma memaddr; 8460484Sobrien struct disassemble_info *info; 8560484Sobrien{ 8689857Sobrien return print_insn_powerpc (memaddr, info, 0, powerpc_dialect(info)); 8760484Sobrien} 8860484Sobrien 8960484Sobrien/* Print a POWER (RS/6000) instruction. */ 9060484Sobrien 9160484Sobrienint 9260484Sobrienprint_insn_rs6000 (memaddr, info) 9360484Sobrien bfd_vma memaddr; 9460484Sobrien struct disassemble_info *info; 9560484Sobrien{ 9660484Sobrien return print_insn_powerpc (memaddr, info, 1, PPC_OPCODE_POWER); 9760484Sobrien} 9860484Sobrien 9960484Sobrien/* Print a PowerPC or POWER instruction. */ 10060484Sobrien 10160484Sobrienstatic int 10260484Sobrienprint_insn_powerpc (memaddr, info, bigendian, dialect) 10360484Sobrien bfd_vma memaddr; 10460484Sobrien struct disassemble_info *info; 10560484Sobrien int bigendian; 10660484Sobrien int dialect; 10760484Sobrien{ 10860484Sobrien bfd_byte buffer[4]; 10960484Sobrien int status; 11060484Sobrien unsigned long insn; 11160484Sobrien const struct powerpc_opcode *opcode; 11260484Sobrien const struct powerpc_opcode *opcode_end; 11360484Sobrien unsigned long op; 11460484Sobrien 11560484Sobrien status = (*info->read_memory_func) (memaddr, buffer, 4, info); 11660484Sobrien if (status != 0) 11760484Sobrien { 11860484Sobrien (*info->memory_error_func) (status, memaddr, info); 11960484Sobrien return -1; 12060484Sobrien } 12160484Sobrien 12260484Sobrien if (bigendian) 12360484Sobrien insn = bfd_getb32 (buffer); 12460484Sobrien else 12560484Sobrien insn = bfd_getl32 (buffer); 12660484Sobrien 12760484Sobrien /* Get the major opcode of the instruction. */ 12860484Sobrien op = PPC_OP (insn); 12960484Sobrien 13060484Sobrien /* Find the first match in the opcode table. We could speed this up 13160484Sobrien a bit by doing a binary search on the major opcode. */ 13260484Sobrien opcode_end = powerpc_opcodes + powerpc_num_opcodes; 13360484Sobrien for (opcode = powerpc_opcodes; opcode < opcode_end; opcode++) 13460484Sobrien { 13560484Sobrien unsigned long table_op; 13660484Sobrien const unsigned char *opindex; 13760484Sobrien const struct powerpc_operand *operand; 13860484Sobrien int invalid; 13960484Sobrien int need_comma; 14060484Sobrien int need_paren; 14160484Sobrien 14260484Sobrien table_op = PPC_OP (opcode->opcode); 14360484Sobrien if (op < table_op) 14460484Sobrien break; 14560484Sobrien if (op > table_op) 14660484Sobrien continue; 14760484Sobrien 14860484Sobrien if ((insn & opcode->mask) != opcode->opcode 14960484Sobrien || (opcode->flags & dialect) == 0) 15060484Sobrien continue; 15160484Sobrien 15260484Sobrien /* Make two passes over the operands. First see if any of them 15360484Sobrien have extraction functions, and, if they do, make sure the 15460484Sobrien instruction is valid. */ 15560484Sobrien invalid = 0; 15660484Sobrien for (opindex = opcode->operands; *opindex != 0; opindex++) 15760484Sobrien { 15860484Sobrien operand = powerpc_operands + *opindex; 15960484Sobrien if (operand->extract) 16089857Sobrien (*operand->extract) (insn, dialect, &invalid); 16160484Sobrien } 16260484Sobrien if (invalid) 16360484Sobrien continue; 16460484Sobrien 16560484Sobrien /* The instruction is valid. */ 16660484Sobrien (*info->fprintf_func) (info->stream, "%s", opcode->name); 16760484Sobrien if (opcode->operands[0] != 0) 16860484Sobrien (*info->fprintf_func) (info->stream, "\t"); 16960484Sobrien 17060484Sobrien /* Now extract and print the operands. */ 17160484Sobrien need_comma = 0; 17260484Sobrien need_paren = 0; 17360484Sobrien for (opindex = opcode->operands; *opindex != 0; opindex++) 17460484Sobrien { 17560484Sobrien long value; 17660484Sobrien 17760484Sobrien operand = powerpc_operands + *opindex; 17860484Sobrien 17960484Sobrien /* Operands that are marked FAKE are simply ignored. We 18060484Sobrien already made sure that the extract function considered 18160484Sobrien the instruction to be valid. */ 18260484Sobrien if ((operand->flags & PPC_OPERAND_FAKE) != 0) 18360484Sobrien continue; 18460484Sobrien 18560484Sobrien /* Extract the value from the instruction. */ 18660484Sobrien if (operand->extract) 18789857Sobrien value = (*operand->extract) (insn, dialect, (int *) NULL); 18860484Sobrien else 18960484Sobrien { 19060484Sobrien value = (insn >> operand->shift) & ((1 << operand->bits) - 1); 19160484Sobrien if ((operand->flags & PPC_OPERAND_SIGNED) != 0 19260484Sobrien && (value & (1 << (operand->bits - 1))) != 0) 19360484Sobrien value -= 1 << operand->bits; 19460484Sobrien } 19560484Sobrien 19660484Sobrien /* If the operand is optional, and the value is zero, don't 19760484Sobrien print anything. */ 19860484Sobrien if ((operand->flags & PPC_OPERAND_OPTIONAL) != 0 19960484Sobrien && (operand->flags & PPC_OPERAND_NEXT) == 0 20060484Sobrien && value == 0) 20160484Sobrien continue; 20260484Sobrien 20360484Sobrien if (need_comma) 20460484Sobrien { 20560484Sobrien (*info->fprintf_func) (info->stream, ","); 20660484Sobrien need_comma = 0; 20760484Sobrien } 20860484Sobrien 20960484Sobrien /* Print the operand as directed by the flags. */ 21060484Sobrien if ((operand->flags & PPC_OPERAND_GPR) != 0) 21160484Sobrien (*info->fprintf_func) (info->stream, "r%ld", value); 21260484Sobrien else if ((operand->flags & PPC_OPERAND_FPR) != 0) 21360484Sobrien (*info->fprintf_func) (info->stream, "f%ld", value); 21477298Sobrien else if ((operand->flags & PPC_OPERAND_VR) != 0) 21577298Sobrien (*info->fprintf_func) (info->stream, "v%ld", value); 21660484Sobrien else if ((operand->flags & PPC_OPERAND_RELATIVE) != 0) 21760484Sobrien (*info->print_address_func) (memaddr + value, info); 21860484Sobrien else if ((operand->flags & PPC_OPERAND_ABSOLUTE) != 0) 21960484Sobrien (*info->print_address_func) ((bfd_vma) value & 0xffffffff, info); 22060484Sobrien else if ((operand->flags & PPC_OPERAND_CR) == 0 22160484Sobrien || (dialect & PPC_OPCODE_PPC) == 0) 22260484Sobrien (*info->fprintf_func) (info->stream, "%ld", value); 22360484Sobrien else 22460484Sobrien { 22560484Sobrien if (operand->bits == 3) 22660484Sobrien (*info->fprintf_func) (info->stream, "cr%d", value); 22760484Sobrien else 22860484Sobrien { 22960484Sobrien static const char *cbnames[4] = { "lt", "gt", "eq", "so" }; 23060484Sobrien int cr; 23160484Sobrien int cc; 23260484Sobrien 23360484Sobrien cr = value >> 2; 23460484Sobrien if (cr != 0) 23560484Sobrien (*info->fprintf_func) (info->stream, "4*cr%d", cr); 23660484Sobrien cc = value & 3; 23760484Sobrien if (cc != 0) 23860484Sobrien { 23960484Sobrien if (cr != 0) 24060484Sobrien (*info->fprintf_func) (info->stream, "+"); 24160484Sobrien (*info->fprintf_func) (info->stream, "%s", cbnames[cc]); 24260484Sobrien } 24360484Sobrien } 24460484Sobrien } 24560484Sobrien 24660484Sobrien if (need_paren) 24760484Sobrien { 24860484Sobrien (*info->fprintf_func) (info->stream, ")"); 24960484Sobrien need_paren = 0; 25060484Sobrien } 25160484Sobrien 25260484Sobrien if ((operand->flags & PPC_OPERAND_PARENS) == 0) 25360484Sobrien need_comma = 1; 25460484Sobrien else 25560484Sobrien { 25660484Sobrien (*info->fprintf_func) (info->stream, "("); 25760484Sobrien need_paren = 1; 25860484Sobrien } 25960484Sobrien } 26060484Sobrien 26160484Sobrien /* We have found and printed an instruction; return. */ 26260484Sobrien return 4; 26360484Sobrien } 26460484Sobrien 26560484Sobrien /* We could not find a match. */ 26660484Sobrien (*info->fprintf_func) (info->stream, ".long 0x%lx", insn); 26760484Sobrien 26860484Sobrien return 4; 26960484Sobrien} 270