ppc-dis.c revision 78828
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 3560484Sobrien/* Print a big endian PowerPC instruction. For convenience, also 3677298Sobrien disassemble instructions supported by the Motorola PowerPC 601 3777298Sobrien and the Altivec vector unit. */ 3860484Sobrien 3960484Sobrienint 4060484Sobrienprint_insn_big_powerpc (memaddr, info) 4160484Sobrien bfd_vma memaddr; 4260484Sobrien struct disassemble_info *info; 4360484Sobrien{ 4460484Sobrien return print_insn_powerpc (memaddr, info, 1, 4577298Sobrien PPC_OPCODE_PPC | PPC_OPCODE_601 | 4677298Sobrien PPC_OPCODE_ALTIVEC); 4760484Sobrien} 4860484Sobrien 4960484Sobrien/* Print a little endian PowerPC instruction. For convenience, also 5077298Sobrien disassemble instructions supported by the Motorola PowerPC 601 5177298Sobrien and the Altivec vector unit. */ 5260484Sobrien 5360484Sobrienint 5460484Sobrienprint_insn_little_powerpc (memaddr, info) 5560484Sobrien bfd_vma memaddr; 5660484Sobrien struct disassemble_info *info; 5760484Sobrien{ 5860484Sobrien return print_insn_powerpc (memaddr, info, 0, 5977298Sobrien PPC_OPCODE_PPC | PPC_OPCODE_601 | 6077298Sobrien PPC_OPCODE_ALTIVEC); 6160484Sobrien} 6260484Sobrien 6360484Sobrien/* Print a POWER (RS/6000) instruction. */ 6460484Sobrien 6560484Sobrienint 6660484Sobrienprint_insn_rs6000 (memaddr, info) 6760484Sobrien bfd_vma memaddr; 6860484Sobrien struct disassemble_info *info; 6960484Sobrien{ 7060484Sobrien return print_insn_powerpc (memaddr, info, 1, PPC_OPCODE_POWER); 7160484Sobrien} 7260484Sobrien 7360484Sobrien/* Print a PowerPC or POWER instruction. */ 7460484Sobrien 7560484Sobrienstatic int 7660484Sobrienprint_insn_powerpc (memaddr, info, bigendian, dialect) 7760484Sobrien bfd_vma memaddr; 7860484Sobrien struct disassemble_info *info; 7960484Sobrien int bigendian; 8060484Sobrien int dialect; 8160484Sobrien{ 8260484Sobrien bfd_byte buffer[4]; 8360484Sobrien int status; 8460484Sobrien unsigned long insn; 8560484Sobrien const struct powerpc_opcode *opcode; 8660484Sobrien const struct powerpc_opcode *opcode_end; 8760484Sobrien unsigned long op; 8860484Sobrien 8960484Sobrien status = (*info->read_memory_func) (memaddr, buffer, 4, info); 9060484Sobrien if (status != 0) 9160484Sobrien { 9260484Sobrien (*info->memory_error_func) (status, memaddr, info); 9360484Sobrien return -1; 9460484Sobrien } 9560484Sobrien 9660484Sobrien if (bigendian) 9760484Sobrien insn = bfd_getb32 (buffer); 9860484Sobrien else 9960484Sobrien insn = bfd_getl32 (buffer); 10060484Sobrien 10160484Sobrien /* Get the major opcode of the instruction. */ 10260484Sobrien op = PPC_OP (insn); 10360484Sobrien 10460484Sobrien /* Find the first match in the opcode table. We could speed this up 10560484Sobrien a bit by doing a binary search on the major opcode. */ 10660484Sobrien opcode_end = powerpc_opcodes + powerpc_num_opcodes; 10760484Sobrien for (opcode = powerpc_opcodes; opcode < opcode_end; opcode++) 10860484Sobrien { 10960484Sobrien unsigned long table_op; 11060484Sobrien const unsigned char *opindex; 11160484Sobrien const struct powerpc_operand *operand; 11260484Sobrien int invalid; 11360484Sobrien int need_comma; 11460484Sobrien int need_paren; 11560484Sobrien 11660484Sobrien table_op = PPC_OP (opcode->opcode); 11760484Sobrien if (op < table_op) 11860484Sobrien break; 11960484Sobrien if (op > table_op) 12060484Sobrien continue; 12160484Sobrien 12260484Sobrien if ((insn & opcode->mask) != opcode->opcode 12360484Sobrien || (opcode->flags & dialect) == 0) 12460484Sobrien continue; 12560484Sobrien 12660484Sobrien /* Make two passes over the operands. First see if any of them 12760484Sobrien have extraction functions, and, if they do, make sure the 12860484Sobrien instruction is valid. */ 12960484Sobrien invalid = 0; 13060484Sobrien for (opindex = opcode->operands; *opindex != 0; opindex++) 13160484Sobrien { 13260484Sobrien operand = powerpc_operands + *opindex; 13360484Sobrien if (operand->extract) 13460484Sobrien (*operand->extract) (insn, &invalid); 13560484Sobrien } 13660484Sobrien if (invalid) 13760484Sobrien continue; 13860484Sobrien 13960484Sobrien /* The instruction is valid. */ 14060484Sobrien (*info->fprintf_func) (info->stream, "%s", opcode->name); 14160484Sobrien if (opcode->operands[0] != 0) 14260484Sobrien (*info->fprintf_func) (info->stream, "\t"); 14360484Sobrien 14460484Sobrien /* Now extract and print the operands. */ 14560484Sobrien need_comma = 0; 14660484Sobrien need_paren = 0; 14760484Sobrien for (opindex = opcode->operands; *opindex != 0; opindex++) 14860484Sobrien { 14960484Sobrien long value; 15060484Sobrien 15160484Sobrien operand = powerpc_operands + *opindex; 15260484Sobrien 15360484Sobrien /* Operands that are marked FAKE are simply ignored. We 15460484Sobrien already made sure that the extract function considered 15560484Sobrien the instruction to be valid. */ 15660484Sobrien if ((operand->flags & PPC_OPERAND_FAKE) != 0) 15760484Sobrien continue; 15860484Sobrien 15960484Sobrien /* Extract the value from the instruction. */ 16060484Sobrien if (operand->extract) 16160484Sobrien value = (*operand->extract) (insn, (int *) NULL); 16260484Sobrien else 16360484Sobrien { 16460484Sobrien value = (insn >> operand->shift) & ((1 << operand->bits) - 1); 16560484Sobrien if ((operand->flags & PPC_OPERAND_SIGNED) != 0 16660484Sobrien && (value & (1 << (operand->bits - 1))) != 0) 16760484Sobrien value -= 1 << operand->bits; 16860484Sobrien } 16960484Sobrien 17060484Sobrien /* If the operand is optional, and the value is zero, don't 17160484Sobrien print anything. */ 17260484Sobrien if ((operand->flags & PPC_OPERAND_OPTIONAL) != 0 17360484Sobrien && (operand->flags & PPC_OPERAND_NEXT) == 0 17460484Sobrien && value == 0) 17560484Sobrien continue; 17660484Sobrien 17760484Sobrien if (need_comma) 17860484Sobrien { 17960484Sobrien (*info->fprintf_func) (info->stream, ","); 18060484Sobrien need_comma = 0; 18160484Sobrien } 18260484Sobrien 18360484Sobrien /* Print the operand as directed by the flags. */ 18460484Sobrien if ((operand->flags & PPC_OPERAND_GPR) != 0) 18560484Sobrien (*info->fprintf_func) (info->stream, "r%ld", value); 18660484Sobrien else if ((operand->flags & PPC_OPERAND_FPR) != 0) 18760484Sobrien (*info->fprintf_func) (info->stream, "f%ld", value); 18877298Sobrien else if ((operand->flags & PPC_OPERAND_VR) != 0) 18977298Sobrien (*info->fprintf_func) (info->stream, "v%ld", value); 19060484Sobrien else if ((operand->flags & PPC_OPERAND_RELATIVE) != 0) 19160484Sobrien (*info->print_address_func) (memaddr + value, info); 19260484Sobrien else if ((operand->flags & PPC_OPERAND_ABSOLUTE) != 0) 19360484Sobrien (*info->print_address_func) ((bfd_vma) value & 0xffffffff, info); 19460484Sobrien else if ((operand->flags & PPC_OPERAND_CR) == 0 19560484Sobrien || (dialect & PPC_OPCODE_PPC) == 0) 19660484Sobrien (*info->fprintf_func) (info->stream, "%ld", value); 19760484Sobrien else 19860484Sobrien { 19960484Sobrien if (operand->bits == 3) 20060484Sobrien (*info->fprintf_func) (info->stream, "cr%d", value); 20160484Sobrien else 20260484Sobrien { 20360484Sobrien static const char *cbnames[4] = { "lt", "gt", "eq", "so" }; 20460484Sobrien int cr; 20560484Sobrien int cc; 20660484Sobrien 20760484Sobrien cr = value >> 2; 20860484Sobrien if (cr != 0) 20960484Sobrien (*info->fprintf_func) (info->stream, "4*cr%d", cr); 21060484Sobrien cc = value & 3; 21160484Sobrien if (cc != 0) 21260484Sobrien { 21360484Sobrien if (cr != 0) 21460484Sobrien (*info->fprintf_func) (info->stream, "+"); 21560484Sobrien (*info->fprintf_func) (info->stream, "%s", cbnames[cc]); 21660484Sobrien } 21760484Sobrien } 21860484Sobrien } 21960484Sobrien 22060484Sobrien if (need_paren) 22160484Sobrien { 22260484Sobrien (*info->fprintf_func) (info->stream, ")"); 22360484Sobrien need_paren = 0; 22460484Sobrien } 22560484Sobrien 22660484Sobrien if ((operand->flags & PPC_OPERAND_PARENS) == 0) 22760484Sobrien need_comma = 1; 22860484Sobrien else 22960484Sobrien { 23060484Sobrien (*info->fprintf_func) (info->stream, "("); 23160484Sobrien need_paren = 1; 23260484Sobrien } 23360484Sobrien } 23460484Sobrien 23560484Sobrien /* We have found and printed an instruction; return. */ 23660484Sobrien return 4; 23760484Sobrien } 23860484Sobrien 23960484Sobrien /* We could not find a match. */ 24060484Sobrien (*info->fprintf_func) (info->stream, ".long 0x%lx", insn); 24160484Sobrien 24260484Sobrien return 4; 24360484Sobrien} 244