xref: /openbsd-src/gnu/usr.bin/binutils/opcodes/ppc-dis.c (revision 007c2a4539b8b8aaa95c5e73e77620090abe113b)
12159047fSniklas /* ppc-dis.c -- Disassemble PowerPC instructions
2*007c2a45Smiod    Copyright 1994, 1995, 2000, 2001, 2002, 2003, 2004
3*007c2a45Smiod    Free Software Foundation, Inc.
42159047fSniklas    Written by Ian Lance Taylor, Cygnus Support
52159047fSniklas 
62159047fSniklas This file is part of GDB, GAS, and the GNU binutils.
72159047fSniklas 
82159047fSniklas GDB, GAS, and the GNU binutils are free software; you can redistribute
92159047fSniklas them and/or modify them under the terms of the GNU General Public
102159047fSniklas License as published by the Free Software Foundation; either version
112159047fSniklas 2, or (at your option) any later version.
122159047fSniklas 
132159047fSniklas GDB, GAS, and the GNU binutils are distributed in the hope that they
142159047fSniklas will be useful, but WITHOUT ANY WARRANTY; without even the implied
152159047fSniklas warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See
162159047fSniklas the GNU General Public License for more details.
172159047fSniklas 
182159047fSniklas You should have received a copy of the GNU General Public License
192159047fSniklas along with this file; see the file COPYING.  If not, write to the Free
202159047fSniklas Software Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
212159047fSniklas 
222159047fSniklas #include <stdio.h>
232159047fSniklas #include "sysdep.h"
242159047fSniklas #include "dis-asm.h"
252159047fSniklas #include "opcode/ppc.h"
262159047fSniklas 
272159047fSniklas /* This file provides several disassembler functions, all of which use
282159047fSniklas    the disassembler interface defined in dis-asm.h.  Several functions
292159047fSniklas    are provided because this file handles disassembly for the PowerPC
302159047fSniklas    in both big and little endian mode and also for the POWER (RS/6000)
312159047fSniklas    chip.  */
322159047fSniklas 
33*007c2a45Smiod static int print_insn_powerpc (bfd_vma, struct disassemble_info *, int, int);
342159047fSniklas 
35*007c2a45Smiod struct dis_private {
36*007c2a45Smiod   /* Stash the result of parsing disassembler_options here.  */
37*007c2a45Smiod   int dialect;
38*007c2a45Smiod };
39c074d1c9Sdrahn 
40c074d1c9Sdrahn /* Determine which set of machines to disassemble for.  PPC403/601 or
41c074d1c9Sdrahn    BookE.  For convenience, also disassemble instructions supported
42c074d1c9Sdrahn    by the AltiVec vector unit.  */
43c074d1c9Sdrahn 
44*007c2a45Smiod static int
powerpc_dialect(struct disassemble_info * info)45*007c2a45Smiod powerpc_dialect (struct disassemble_info *info)
46c074d1c9Sdrahn {
47c074d1c9Sdrahn   int dialect = PPC_OPCODE_PPC | PPC_OPCODE_ALTIVEC;
48c074d1c9Sdrahn 
49c074d1c9Sdrahn   if (BFD_DEFAULT_TARGET_SIZE == 64)
50c074d1c9Sdrahn     dialect |= PPC_OPCODE_64;
51c074d1c9Sdrahn 
52c074d1c9Sdrahn   if (info->disassembler_options
53*007c2a45Smiod       && strstr (info->disassembler_options, "booke") != NULL)
54c074d1c9Sdrahn     dialect |= PPC_OPCODE_BOOKE | PPC_OPCODE_BOOKE64;
55*007c2a45Smiod   else if ((info->mach == bfd_mach_ppc_e500)
56c074d1c9Sdrahn 	   || (info->disassembler_options
57*007c2a45Smiod 	       && strstr (info->disassembler_options, "e500") != NULL))
58c074d1c9Sdrahn     {
59c074d1c9Sdrahn       dialect |= PPC_OPCODE_BOOKE
60c074d1c9Sdrahn 	| PPC_OPCODE_SPE | PPC_OPCODE_ISEL
61c074d1c9Sdrahn 	| PPC_OPCODE_EFS | PPC_OPCODE_BRLOCK
62c074d1c9Sdrahn 	| PPC_OPCODE_PMR | PPC_OPCODE_CACHELCK
63c074d1c9Sdrahn 	| PPC_OPCODE_RFMCI;
64c074d1c9Sdrahn       /* efs* and AltiVec conflict.  */
65c074d1c9Sdrahn       dialect &= ~PPC_OPCODE_ALTIVEC;
66c074d1c9Sdrahn     }
67*007c2a45Smiod   else if (info->disassembler_options
68*007c2a45Smiod 	   && strstr (info->disassembler_options, "efs") != NULL)
69c074d1c9Sdrahn     {
70c074d1c9Sdrahn       dialect |= PPC_OPCODE_EFS;
71c074d1c9Sdrahn       /* efs* and AltiVec conflict.  */
72c074d1c9Sdrahn       dialect &= ~PPC_OPCODE_ALTIVEC;
73c074d1c9Sdrahn     }
74c074d1c9Sdrahn   else
75c074d1c9Sdrahn     dialect |= (PPC_OPCODE_403 | PPC_OPCODE_601 | PPC_OPCODE_CLASSIC
76c074d1c9Sdrahn 		| PPC_OPCODE_COMMON);
77c074d1c9Sdrahn 
78c074d1c9Sdrahn   if (info->disassembler_options
79*007c2a45Smiod       && strstr (info->disassembler_options, "power4") != NULL)
80c074d1c9Sdrahn     dialect |= PPC_OPCODE_POWER4;
81c074d1c9Sdrahn 
82*007c2a45Smiod   if (info->disassembler_options
83*007c2a45Smiod       && strstr (info->disassembler_options, "any") != NULL)
84*007c2a45Smiod     dialect |= PPC_OPCODE_ANY;
85*007c2a45Smiod 
86c074d1c9Sdrahn   if (info->disassembler_options)
87c074d1c9Sdrahn     {
88c074d1c9Sdrahn       if (strstr (info->disassembler_options, "32") != NULL)
89c074d1c9Sdrahn 	dialect &= ~PPC_OPCODE_64;
90c074d1c9Sdrahn       else if (strstr (info->disassembler_options, "64") != NULL)
91c074d1c9Sdrahn 	dialect |= PPC_OPCODE_64;
92c074d1c9Sdrahn     }
93c074d1c9Sdrahn 
94*007c2a45Smiod   ((struct dis_private *) &info->private_data)->dialect = dialect;
95c074d1c9Sdrahn   return dialect;
96c074d1c9Sdrahn }
97c074d1c9Sdrahn 
98c074d1c9Sdrahn /* Print a big endian PowerPC instruction.  */
992159047fSniklas 
1002159047fSniklas int
print_insn_big_powerpc(bfd_vma memaddr,struct disassemble_info * info)101*007c2a45Smiod print_insn_big_powerpc (bfd_vma memaddr, struct disassemble_info *info)
1022159047fSniklas {
103*007c2a45Smiod   int dialect = ((struct dis_private *) &info->private_data)->dialect;
104*007c2a45Smiod   return print_insn_powerpc (memaddr, info, 1, dialect);
1052159047fSniklas }
1062159047fSniklas 
107c074d1c9Sdrahn /* Print a little endian PowerPC instruction.  */
1082159047fSniklas 
1092159047fSniklas int
print_insn_little_powerpc(bfd_vma memaddr,struct disassemble_info * info)110*007c2a45Smiod print_insn_little_powerpc (bfd_vma memaddr, struct disassemble_info *info)
1112159047fSniklas {
112*007c2a45Smiod   int dialect = ((struct dis_private *) &info->private_data)->dialect;
113*007c2a45Smiod   return print_insn_powerpc (memaddr, info, 0, dialect);
1142159047fSniklas }
1152159047fSniklas 
1162159047fSniklas /* Print a POWER (RS/6000) instruction.  */
1172159047fSniklas 
1182159047fSniklas int
print_insn_rs6000(bfd_vma memaddr,struct disassemble_info * info)119*007c2a45Smiod print_insn_rs6000 (bfd_vma memaddr, struct disassemble_info *info)
1202159047fSniklas {
1212159047fSniklas   return print_insn_powerpc (memaddr, info, 1, PPC_OPCODE_POWER);
1222159047fSniklas }
1232159047fSniklas 
1242159047fSniklas /* Print a PowerPC or POWER instruction.  */
1252159047fSniklas 
1262159047fSniklas static int
print_insn_powerpc(bfd_vma memaddr,struct disassemble_info * info,int bigendian,int dialect)127*007c2a45Smiod print_insn_powerpc (bfd_vma memaddr,
128*007c2a45Smiod 		    struct disassemble_info *info,
129*007c2a45Smiod 		    int bigendian,
130*007c2a45Smiod 		    int dialect)
1312159047fSniklas {
1322159047fSniklas   bfd_byte buffer[4];
1332159047fSniklas   int status;
1342159047fSniklas   unsigned long insn;
1352159047fSniklas   const struct powerpc_opcode *opcode;
1362159047fSniklas   const struct powerpc_opcode *opcode_end;
1372159047fSniklas   unsigned long op;
1382159047fSniklas 
139*007c2a45Smiod   if (dialect == 0)
140*007c2a45Smiod     dialect = powerpc_dialect (info);
141*007c2a45Smiod 
1422159047fSniklas   status = (*info->read_memory_func) (memaddr, buffer, 4, info);
1432159047fSniklas   if (status != 0)
1442159047fSniklas     {
1452159047fSniklas       (*info->memory_error_func) (status, memaddr, info);
1462159047fSniklas       return -1;
1472159047fSniklas     }
1482159047fSniklas 
1492159047fSniklas   if (bigendian)
1502159047fSniklas     insn = bfd_getb32 (buffer);
1512159047fSniklas   else
1522159047fSniklas     insn = bfd_getl32 (buffer);
1532159047fSniklas 
1542159047fSniklas   /* Get the major opcode of the instruction.  */
1552159047fSniklas   op = PPC_OP (insn);
1562159047fSniklas 
1572159047fSniklas   /* Find the first match in the opcode table.  We could speed this up
1582159047fSniklas      a bit by doing a binary search on the major opcode.  */
1592159047fSniklas   opcode_end = powerpc_opcodes + powerpc_num_opcodes;
160*007c2a45Smiod  again:
1612159047fSniklas   for (opcode = powerpc_opcodes; opcode < opcode_end; opcode++)
1622159047fSniklas     {
1632159047fSniklas       unsigned long table_op;
1642159047fSniklas       const unsigned char *opindex;
1652159047fSniklas       const struct powerpc_operand *operand;
1662159047fSniklas       int invalid;
1672159047fSniklas       int need_comma;
1682159047fSniklas       int need_paren;
1692159047fSniklas 
1702159047fSniklas       table_op = PPC_OP (opcode->opcode);
1712159047fSniklas       if (op < table_op)
1722159047fSniklas 	break;
1732159047fSniklas       if (op > table_op)
1742159047fSniklas 	continue;
1752159047fSniklas 
1762159047fSniklas       if ((insn & opcode->mask) != opcode->opcode
1772159047fSniklas 	  || (opcode->flags & dialect) == 0)
1782159047fSniklas 	continue;
1792159047fSniklas 
1802159047fSniklas       /* Make two passes over the operands.  First see if any of them
1812159047fSniklas 	 have extraction functions, and, if they do, make sure the
1822159047fSniklas 	 instruction is valid.  */
1832159047fSniklas       invalid = 0;
1842159047fSniklas       for (opindex = opcode->operands; *opindex != 0; opindex++)
1852159047fSniklas 	{
1862159047fSniklas 	  operand = powerpc_operands + *opindex;
1872159047fSniklas 	  if (operand->extract)
188c074d1c9Sdrahn 	    (*operand->extract) (insn, dialect, &invalid);
1892159047fSniklas 	}
1902159047fSniklas       if (invalid)
1912159047fSniklas 	continue;
1922159047fSniklas 
1932159047fSniklas       /* The instruction is valid.  */
1942159047fSniklas       if (opcode->operands[0] != 0)
195*007c2a45Smiod 	(*info->fprintf_func) (info->stream, "%-7s ", opcode->name);
196*007c2a45Smiod       else
197*007c2a45Smiod 	(*info->fprintf_func) (info->stream, "%s", opcode->name);
1982159047fSniklas 
1992159047fSniklas       /* Now extract and print the operands.  */
2002159047fSniklas       need_comma = 0;
2012159047fSniklas       need_paren = 0;
2022159047fSniklas       for (opindex = opcode->operands; *opindex != 0; opindex++)
2032159047fSniklas 	{
2042159047fSniklas 	  long value;
2052159047fSniklas 
2062159047fSniklas 	  operand = powerpc_operands + *opindex;
2072159047fSniklas 
2082159047fSniklas 	  /* Operands that are marked FAKE are simply ignored.  We
2092159047fSniklas 	     already made sure that the extract function considered
2102159047fSniklas 	     the instruction to be valid.  */
2112159047fSniklas 	  if ((operand->flags & PPC_OPERAND_FAKE) != 0)
2122159047fSniklas 	    continue;
2132159047fSniklas 
2142159047fSniklas 	  /* Extract the value from the instruction.  */
2152159047fSniklas 	  if (operand->extract)
216*007c2a45Smiod 	    value = (*operand->extract) (insn, dialect, &invalid);
2172159047fSniklas 	  else
2182159047fSniklas 	    {
2192159047fSniklas 	      value = (insn >> operand->shift) & ((1 << operand->bits) - 1);
2202159047fSniklas 	      if ((operand->flags & PPC_OPERAND_SIGNED) != 0
2212159047fSniklas 		  && (value & (1 << (operand->bits - 1))) != 0)
2222159047fSniklas 		value -= 1 << operand->bits;
2232159047fSniklas 	    }
2242159047fSniklas 
2252159047fSniklas 	  /* If the operand is optional, and the value is zero, don't
2262159047fSniklas 	     print anything.  */
2272159047fSniklas 	  if ((operand->flags & PPC_OPERAND_OPTIONAL) != 0
2282159047fSniklas 	      && (operand->flags & PPC_OPERAND_NEXT) == 0
2292159047fSniklas 	      && value == 0)
2302159047fSniklas 	    continue;
2312159047fSniklas 
2322159047fSniklas 	  if (need_comma)
2332159047fSniklas 	    {
2342159047fSniklas 	      (*info->fprintf_func) (info->stream, ",");
2352159047fSniklas 	      need_comma = 0;
2362159047fSniklas 	    }
2372159047fSniklas 
2382159047fSniklas 	  /* Print the operand as directed by the flags.  */
239*007c2a45Smiod 	  if ((operand->flags & PPC_OPERAND_GPR) != 0
240*007c2a45Smiod 	      || ((operand->flags & PPC_OPERAND_GPR_0) != 0 && value != 0))
2412159047fSniklas 	    (*info->fprintf_func) (info->stream, "r%ld", value);
2422159047fSniklas 	  else if ((operand->flags & PPC_OPERAND_FPR) != 0)
2432159047fSniklas 	    (*info->fprintf_func) (info->stream, "f%ld", value);
244b55d4692Sfgsch 	  else if ((operand->flags & PPC_OPERAND_VR) != 0)
245b55d4692Sfgsch 	    (*info->fprintf_func) (info->stream, "v%ld", value);
2462159047fSniklas 	  else if ((operand->flags & PPC_OPERAND_RELATIVE) != 0)
2472159047fSniklas 	    (*info->print_address_func) (memaddr + value, info);
2482159047fSniklas 	  else if ((operand->flags & PPC_OPERAND_ABSOLUTE) != 0)
2492159047fSniklas 	    (*info->print_address_func) ((bfd_vma) value & 0xffffffff, info);
2502159047fSniklas 	  else if ((operand->flags & PPC_OPERAND_CR) == 0
2512159047fSniklas 		   || (dialect & PPC_OPCODE_PPC) == 0)
2522159047fSniklas 	    (*info->fprintf_func) (info->stream, "%ld", value);
2532159047fSniklas 	  else
2542159047fSniklas 	    {
2552159047fSniklas 	      if (operand->bits == 3)
2562159047fSniklas 		(*info->fprintf_func) (info->stream, "cr%d", value);
2572159047fSniklas 	      else
2582159047fSniklas 		{
2592159047fSniklas 		  static const char *cbnames[4] = { "lt", "gt", "eq", "so" };
2602159047fSniklas 		  int cr;
2612159047fSniklas 		  int cc;
2622159047fSniklas 
2632159047fSniklas 		  cr = value >> 2;
2642159047fSniklas 		  if (cr != 0)
265c074d1c9Sdrahn 		    (*info->fprintf_func) (info->stream, "4*cr%d+", cr);
2662159047fSniklas 		  cc = value & 3;
2672159047fSniklas 		  (*info->fprintf_func) (info->stream, "%s", cbnames[cc]);
2682159047fSniklas 		}
2692159047fSniklas 	    }
2702159047fSniklas 
2712159047fSniklas 	  if (need_paren)
2722159047fSniklas 	    {
2732159047fSniklas 	      (*info->fprintf_func) (info->stream, ")");
2742159047fSniklas 	      need_paren = 0;
2752159047fSniklas 	    }
2762159047fSniklas 
2772159047fSniklas 	  if ((operand->flags & PPC_OPERAND_PARENS) == 0)
2782159047fSniklas 	    need_comma = 1;
2792159047fSniklas 	  else
2802159047fSniklas 	    {
2812159047fSniklas 	      (*info->fprintf_func) (info->stream, "(");
2822159047fSniklas 	      need_paren = 1;
2832159047fSniklas 	    }
2842159047fSniklas 	}
2852159047fSniklas 
2862159047fSniklas       /* We have found and printed an instruction; return.  */
2872159047fSniklas       return 4;
2882159047fSniklas     }
2892159047fSniklas 
290*007c2a45Smiod   if ((dialect & PPC_OPCODE_ANY) != 0)
291*007c2a45Smiod     {
292*007c2a45Smiod       dialect = ~PPC_OPCODE_ANY;
293*007c2a45Smiod       goto again;
294*007c2a45Smiod     }
295*007c2a45Smiod 
2962159047fSniklas   /* We could not find a match.  */
2972159047fSniklas   (*info->fprintf_func) (info->stream, ".long 0x%lx", insn);
2982159047fSniklas 
2992159047fSniklas   return 4;
3002159047fSniklas }
301c074d1c9Sdrahn 
302c074d1c9Sdrahn void
print_ppc_disassembler_options(FILE * stream)303c074d1c9Sdrahn print_ppc_disassembler_options (FILE *stream)
304c074d1c9Sdrahn {
305c074d1c9Sdrahn   fprintf (stream, "\n\
306c074d1c9Sdrahn The following PPC specific disassembler options are supported for use with\n\
307c074d1c9Sdrahn the -M switch:\n");
308c074d1c9Sdrahn 
309c074d1c9Sdrahn   fprintf (stream, "  booke|booke32|booke64    Disassemble the BookE instructions\n");
310c074d1c9Sdrahn   fprintf (stream, "  e500|e500x2              Disassemble the e500 instructions\n");
311c074d1c9Sdrahn   fprintf (stream, "  efs                      Disassemble the EFS instructions\n");
312c074d1c9Sdrahn   fprintf (stream, "  power4                   Disassemble the Power4 instructions\n");
313c074d1c9Sdrahn   fprintf (stream, "  32                       Do not disassemble 64-bit instructions\n");
314c074d1c9Sdrahn   fprintf (stream, "  64                       Allow disassembly of 64-bit instructions\n");
315c074d1c9Sdrahn }
316