Home | History | Annotate | Line # | Download | only in opcodes
ppc-dis.c revision 1.3.2.1
      1      1.1  christos /* ppc-dis.c -- Disassemble PowerPC instructions
      2      1.3  christos    Copyright (C) 1994-2015 Free Software Foundation, Inc.
      3      1.1  christos    Written by Ian Lance Taylor, Cygnus Support
      4      1.1  christos 
      5      1.1  christos    This file is part of the GNU opcodes library.
      6      1.1  christos 
      7      1.1  christos    This library is free software; you can redistribute it and/or modify
      8      1.1  christos    it under the terms of the GNU General Public License as published by
      9      1.1  christos    the Free Software Foundation; either version 3, or (at your option)
     10      1.1  christos    any later version.
     11      1.1  christos 
     12      1.1  christos    It is distributed in the hope that it will be useful, but WITHOUT
     13      1.1  christos    ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
     14      1.1  christos    or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public
     15      1.1  christos    License for more details.
     16      1.1  christos 
     17      1.1  christos    You should have received a copy of the GNU General Public License
     18      1.1  christos    along with this file; see the file COPYING.  If not, write to the
     19      1.1  christos    Free Software Foundation, 51 Franklin Street - Fifth Floor, Boston,
     20      1.1  christos    MA 02110-1301, USA.  */
     21      1.1  christos 
     22      1.1  christos #include "sysdep.h"
     23      1.1  christos #include <stdio.h>
     24      1.1  christos #include "dis-asm.h"
     25      1.1  christos #include "elf-bfd.h"
     26      1.1  christos #include "elf/ppc.h"
     27      1.1  christos #include "opintl.h"
     28      1.1  christos #include "opcode/ppc.h"
     29      1.1  christos 
     30      1.1  christos /* This file provides several disassembler functions, all of which use
     31      1.1  christos    the disassembler interface defined in dis-asm.h.  Several functions
     32      1.1  christos    are provided because this file handles disassembly for the PowerPC
     33      1.1  christos    in both big and little endian mode and also for the POWER (RS/6000)
     34      1.1  christos    chip.  */
     35      1.1  christos static int print_insn_powerpc (bfd_vma, struct disassemble_info *, int,
     36      1.1  christos 			       ppc_cpu_t);
     37      1.1  christos 
     38      1.1  christos struct dis_private
     39      1.1  christos {
     40      1.1  christos   /* Stash the result of parsing disassembler_options here.  */
     41      1.1  christos   ppc_cpu_t dialect;
     42      1.1  christos } private;
     43      1.1  christos 
     44      1.1  christos #define POWERPC_DIALECT(INFO) \
     45      1.1  christos   (((struct dis_private *) ((INFO)->private_data))->dialect)
     46      1.1  christos 
     47      1.1  christos struct ppc_mopt {
     48      1.1  christos   const char *opt;
     49      1.1  christos   ppc_cpu_t cpu;
     50      1.1  christos   ppc_cpu_t sticky;
     51      1.1  christos };
     52      1.1  christos 
     53      1.1  christos struct ppc_mopt ppc_opts[] = {
     54      1.1  christos   { "403",     (PPC_OPCODE_PPC | PPC_OPCODE_403),
     55      1.1  christos     0 },
     56      1.1  christos   { "405",     (PPC_OPCODE_PPC | PPC_OPCODE_403 | PPC_OPCODE_405),
     57      1.1  christos     0 },
     58      1.1  christos   { "440",     (PPC_OPCODE_PPC | PPC_OPCODE_BOOKE | PPC_OPCODE_440
     59      1.1  christos 		| PPC_OPCODE_ISEL | PPC_OPCODE_RFMCI),
     60      1.1  christos     0 },
     61      1.1  christos   { "464",     (PPC_OPCODE_PPC | PPC_OPCODE_BOOKE | PPC_OPCODE_440
     62      1.1  christos 		| PPC_OPCODE_ISEL | PPC_OPCODE_RFMCI),
     63      1.1  christos     0 },
     64      1.1  christos   { "476",     (PPC_OPCODE_PPC | PPC_OPCODE_ISEL | PPC_OPCODE_440
     65      1.1  christos 		| PPC_OPCODE_476 | PPC_OPCODE_POWER4 | PPC_OPCODE_POWER5),
     66      1.1  christos     0 },
     67      1.1  christos   { "601",     (PPC_OPCODE_PPC | PPC_OPCODE_601),
     68      1.1  christos     0 },
     69      1.1  christos   { "603",     (PPC_OPCODE_PPC),
     70      1.1  christos     0 },
     71      1.1  christos   { "604",     (PPC_OPCODE_PPC),
     72      1.1  christos     0 },
     73      1.1  christos   { "620",     (PPC_OPCODE_PPC | PPC_OPCODE_64),
     74      1.1  christos     0 },
     75      1.1  christos   { "7400",    (PPC_OPCODE_PPC | PPC_OPCODE_ALTIVEC),
     76      1.1  christos     0 },
     77      1.1  christos   { "7410",    (PPC_OPCODE_PPC | PPC_OPCODE_ALTIVEC),
     78      1.1  christos     0 },
     79  1.3.2.1  pgoyette   { "7450",    (PPC_OPCODE_PPC | PPC_OPCODE_7450 | PPC_OPCODE_ALTIVEC),
     80      1.1  christos     0 },
     81      1.1  christos   { "7455",    (PPC_OPCODE_PPC | PPC_OPCODE_ALTIVEC),
     82      1.1  christos     0 },
     83  1.3.2.1  pgoyette   { "750cl",   (PPC_OPCODE_PPC | PPC_OPCODE_750 | PPC_OPCODE_PPCPS)
     84      1.1  christos     , 0 },
     85  1.3.2.1  pgoyette   { "821",     (PPC_OPCODE_PPC | PPC_OPCODE_860),
     86  1.3.2.1  pgoyette     0 },
     87  1.3.2.1  pgoyette   { "850",     (PPC_OPCODE_PPC | PPC_OPCODE_860),
     88  1.3.2.1  pgoyette     0 },
     89  1.3.2.1  pgoyette   { "860",     (PPC_OPCODE_PPC | PPC_OPCODE_860),
     90  1.3.2.1  pgoyette     0 },
     91      1.1  christos   { "a2",      (PPC_OPCODE_PPC | PPC_OPCODE_ISEL | PPC_OPCODE_POWER4
     92      1.1  christos 		| PPC_OPCODE_POWER5 | PPC_OPCODE_CACHELCK | PPC_OPCODE_64
     93      1.1  christos 		| PPC_OPCODE_A2),
     94      1.1  christos     0 },
     95      1.1  christos   { "altivec", (PPC_OPCODE_PPC),
     96      1.1  christos     PPC_OPCODE_ALTIVEC | PPC_OPCODE_ALTIVEC2 },
     97      1.1  christos   { "any",     0,
     98      1.1  christos     PPC_OPCODE_ANY },
     99      1.1  christos   { "booke",   (PPC_OPCODE_PPC | PPC_OPCODE_BOOKE),
    100      1.1  christos     0 },
    101      1.1  christos   { "booke32", (PPC_OPCODE_PPC | PPC_OPCODE_BOOKE),
    102      1.1  christos     0 },
    103      1.1  christos   { "cell",    (PPC_OPCODE_PPC | PPC_OPCODE_64 | PPC_OPCODE_POWER4
    104      1.1  christos 		| PPC_OPCODE_CELL | PPC_OPCODE_ALTIVEC),
    105      1.1  christos     0 },
    106      1.1  christos   { "com",     (PPC_OPCODE_COMMON),
    107      1.1  christos     0 },
    108      1.1  christos   { "e300",    (PPC_OPCODE_PPC | PPC_OPCODE_E300),
    109      1.1  christos     0 },
    110      1.1  christos   { "e500",    (PPC_OPCODE_PPC | PPC_OPCODE_BOOKE | PPC_OPCODE_SPE
    111      1.1  christos 		| PPC_OPCODE_ISEL | PPC_OPCODE_EFS | PPC_OPCODE_BRLOCK
    112      1.1  christos 		| PPC_OPCODE_PMR | PPC_OPCODE_CACHELCK | PPC_OPCODE_RFMCI
    113      1.1  christos 		| PPC_OPCODE_E500),
    114      1.1  christos     0 },
    115      1.1  christos   { "e500mc",  (PPC_OPCODE_PPC | PPC_OPCODE_BOOKE | PPC_OPCODE_ISEL
    116      1.1  christos 		| PPC_OPCODE_PMR | PPC_OPCODE_CACHELCK | PPC_OPCODE_RFMCI
    117      1.1  christos 		| PPC_OPCODE_E500MC),
    118      1.1  christos     0 },
    119      1.1  christos   { "e500mc64",  (PPC_OPCODE_PPC | PPC_OPCODE_BOOKE | PPC_OPCODE_ISEL
    120      1.1  christos 		| PPC_OPCODE_PMR | PPC_OPCODE_CACHELCK | PPC_OPCODE_RFMCI
    121      1.1  christos 		| PPC_OPCODE_E500MC | PPC_OPCODE_64 | PPC_OPCODE_POWER5
    122      1.1  christos 		| PPC_OPCODE_POWER6 | PPC_OPCODE_POWER7),
    123      1.1  christos     0 },
    124      1.1  christos   { "e5500",    (PPC_OPCODE_PPC | PPC_OPCODE_BOOKE | PPC_OPCODE_ISEL
    125      1.1  christos 		| PPC_OPCODE_PMR | PPC_OPCODE_CACHELCK | PPC_OPCODE_RFMCI
    126      1.1  christos 		| PPC_OPCODE_E500MC | PPC_OPCODE_64 | PPC_OPCODE_POWER4
    127      1.1  christos 		| PPC_OPCODE_POWER5 | PPC_OPCODE_POWER6
    128      1.1  christos 		| PPC_OPCODE_POWER7),
    129      1.1  christos     0 },
    130      1.1  christos   { "e6500",   (PPC_OPCODE_PPC | PPC_OPCODE_BOOKE | PPC_OPCODE_ISEL
    131      1.1  christos 		| PPC_OPCODE_PMR | PPC_OPCODE_CACHELCK | PPC_OPCODE_RFMCI
    132      1.1  christos 		| PPC_OPCODE_E500MC | PPC_OPCODE_64 | PPC_OPCODE_ALTIVEC
    133      1.1  christos 		| PPC_OPCODE_ALTIVEC2 | PPC_OPCODE_E6500 | PPC_OPCODE_POWER4
    134      1.1  christos 		| PPC_OPCODE_POWER5 | PPC_OPCODE_POWER6 | PPC_OPCODE_POWER7),
    135      1.1  christos     0 },
    136      1.1  christos   { "e500x2",  (PPC_OPCODE_PPC | PPC_OPCODE_BOOKE | PPC_OPCODE_SPE
    137      1.1  christos 		| PPC_OPCODE_ISEL | PPC_OPCODE_EFS | PPC_OPCODE_BRLOCK
    138      1.1  christos 		| PPC_OPCODE_PMR | PPC_OPCODE_CACHELCK | PPC_OPCODE_RFMCI
    139      1.1  christos 		| PPC_OPCODE_E500),
    140      1.1  christos     0 },
    141      1.1  christos   { "efs",     (PPC_OPCODE_PPC | PPC_OPCODE_EFS),
    142      1.1  christos     0 },
    143      1.1  christos   { "power4",  (PPC_OPCODE_PPC | PPC_OPCODE_64 | PPC_OPCODE_POWER4),
    144      1.1  christos     0 },
    145      1.1  christos   { "power5",  (PPC_OPCODE_PPC | PPC_OPCODE_64 | PPC_OPCODE_POWER4
    146      1.1  christos 		| PPC_OPCODE_POWER5),
    147      1.1  christos     0 },
    148      1.1  christos   { "power6",  (PPC_OPCODE_PPC | PPC_OPCODE_64 | PPC_OPCODE_POWER4
    149      1.1  christos 		| PPC_OPCODE_POWER5 | PPC_OPCODE_POWER6 | PPC_OPCODE_ALTIVEC),
    150      1.1  christos     0 },
    151      1.1  christos   { "power7",  (PPC_OPCODE_PPC | PPC_OPCODE_ISEL | PPC_OPCODE_64
    152      1.1  christos 		| PPC_OPCODE_POWER4 | PPC_OPCODE_POWER5 | PPC_OPCODE_POWER6
    153      1.1  christos 		| PPC_OPCODE_POWER7 | PPC_OPCODE_ALTIVEC | PPC_OPCODE_VSX),
    154      1.1  christos     0 },
    155      1.1  christos   { "power8",  (PPC_OPCODE_PPC | PPC_OPCODE_ISEL | PPC_OPCODE_64
    156      1.1  christos 		| PPC_OPCODE_POWER4 | PPC_OPCODE_POWER5 | PPC_OPCODE_POWER6
    157      1.1  christos 		| PPC_OPCODE_POWER7 | PPC_OPCODE_POWER8 | PPC_OPCODE_HTM
    158      1.1  christos 		| PPC_OPCODE_ALTIVEC | PPC_OPCODE_ALTIVEC2 | PPC_OPCODE_VSX),
    159      1.1  christos     0 },
    160      1.1  christos   { "ppc",     (PPC_OPCODE_PPC),
    161      1.1  christos     0 },
    162      1.1  christos   { "ppc32",   (PPC_OPCODE_PPC),
    163      1.1  christos     0 },
    164      1.1  christos   { "ppc64",   (PPC_OPCODE_PPC | PPC_OPCODE_64),
    165      1.1  christos     0 },
    166      1.1  christos   { "ppc64bridge", (PPC_OPCODE_PPC | PPC_OPCODE_64_BRIDGE),
    167      1.1  christos     0 },
    168      1.1  christos   { "ppcps",   (PPC_OPCODE_PPC | PPC_OPCODE_PPCPS),
    169      1.1  christos     0 },
    170      1.1  christos   { "pwr",     (PPC_OPCODE_POWER),
    171      1.1  christos     0 },
    172      1.1  christos   { "pwr2",    (PPC_OPCODE_POWER | PPC_OPCODE_POWER2),
    173      1.1  christos     0 },
    174      1.1  christos   { "pwr4",    (PPC_OPCODE_PPC | PPC_OPCODE_64 | PPC_OPCODE_POWER4),
    175      1.1  christos     0 },
    176      1.1  christos   { "pwr5",    (PPC_OPCODE_PPC | PPC_OPCODE_64 | PPC_OPCODE_POWER4
    177      1.1  christos 		| PPC_OPCODE_POWER5),
    178      1.1  christos     0 },
    179      1.1  christos   { "pwr5x",   (PPC_OPCODE_PPC | PPC_OPCODE_64 | PPC_OPCODE_POWER4
    180      1.1  christos 		| PPC_OPCODE_POWER5),
    181      1.1  christos     0 },
    182      1.1  christos   { "pwr6",    (PPC_OPCODE_PPC | PPC_OPCODE_64 | PPC_OPCODE_POWER4
    183      1.1  christos 		| PPC_OPCODE_POWER5 | PPC_OPCODE_POWER6 | PPC_OPCODE_ALTIVEC),
    184      1.1  christos     0 },
    185      1.1  christos   { "pwr7",    (PPC_OPCODE_PPC | PPC_OPCODE_ISEL | PPC_OPCODE_64
    186      1.1  christos 		| PPC_OPCODE_POWER4 | PPC_OPCODE_POWER5 | PPC_OPCODE_POWER6
    187      1.1  christos 		| PPC_OPCODE_POWER7 | PPC_OPCODE_ALTIVEC | PPC_OPCODE_VSX),
    188      1.1  christos     0 },
    189      1.1  christos   { "pwr8",    (PPC_OPCODE_PPC | PPC_OPCODE_ISEL | PPC_OPCODE_64
    190      1.1  christos 		| PPC_OPCODE_POWER4 | PPC_OPCODE_POWER5 | PPC_OPCODE_POWER6
    191      1.1  christos 		| PPC_OPCODE_POWER7 | PPC_OPCODE_POWER8 | PPC_OPCODE_HTM
    192      1.1  christos 		| PPC_OPCODE_ALTIVEC | PPC_OPCODE_ALTIVEC2 | PPC_OPCODE_VSX),
    193      1.1  christos     0 },
    194      1.1  christos   { "pwrx",    (PPC_OPCODE_POWER | PPC_OPCODE_POWER2),
    195      1.1  christos     0 },
    196      1.1  christos   { "spe",     (PPC_OPCODE_PPC | PPC_OPCODE_EFS),
    197      1.1  christos     PPC_OPCODE_SPE },
    198      1.1  christos   { "titan",   (PPC_OPCODE_PPC | PPC_OPCODE_BOOKE | PPC_OPCODE_PMR
    199      1.1  christos 		| PPC_OPCODE_RFMCI | PPC_OPCODE_TITAN),
    200      1.1  christos     0 },
    201      1.1  christos   { "vle",     (PPC_OPCODE_PPC | PPC_OPCODE_ISEL | PPC_OPCODE_VLE),
    202      1.1  christos     PPC_OPCODE_VLE },
    203      1.1  christos   { "vsx",     (PPC_OPCODE_PPC),
    204      1.1  christos     PPC_OPCODE_VSX },
    205      1.1  christos   { "htm",     (PPC_OPCODE_PPC),
    206      1.1  christos     PPC_OPCODE_HTM },
    207      1.1  christos };
    208      1.1  christos 
    209      1.1  christos /* Switch between Booke and VLE dialects for interlinked dumps.  */
    210      1.1  christos static ppc_cpu_t
    211      1.1  christos get_powerpc_dialect (struct disassemble_info *info)
    212      1.1  christos {
    213      1.1  christos   ppc_cpu_t dialect = 0;
    214      1.1  christos 
    215      1.1  christos   dialect = POWERPC_DIALECT (info);
    216      1.1  christos 
    217      1.1  christos   /* Disassemble according to the section headers flags for VLE-mode.  */
    218      1.1  christos   if (dialect & PPC_OPCODE_VLE
    219      1.1  christos       && info->section->owner != NULL
    220      1.1  christos       && bfd_get_flavour (info->section->owner) == bfd_target_elf_flavour
    221      1.1  christos       && elf_object_id (info->section->owner) == PPC32_ELF_DATA
    222      1.1  christos       && (elf_section_flags (info->section) & SHF_PPC_VLE) != 0)
    223      1.1  christos     return dialect;
    224      1.1  christos   else
    225      1.1  christos     return dialect & ~ PPC_OPCODE_VLE;
    226      1.1  christos }
    227      1.1  christos 
    228      1.1  christos /* Handle -m and -M options that set cpu type, and .machine arg.  */
    229      1.1  christos 
    230      1.1  christos ppc_cpu_t
    231      1.1  christos ppc_parse_cpu (ppc_cpu_t ppc_cpu, ppc_cpu_t *sticky, const char *arg)
    232      1.1  christos {
    233      1.1  christos   unsigned int i;
    234      1.1  christos 
    235      1.1  christos   for (i = 0; i < sizeof (ppc_opts) / sizeof (ppc_opts[0]); i++)
    236      1.1  christos     if (strcmp (ppc_opts[i].opt, arg) == 0)
    237      1.1  christos       {
    238      1.1  christos 	if (ppc_opts[i].sticky)
    239      1.1  christos 	  {
    240      1.1  christos 	    *sticky |= ppc_opts[i].sticky;
    241      1.1  christos 	    if ((ppc_cpu & ~*sticky) != 0)
    242      1.1  christos 	      break;
    243      1.1  christos 	  }
    244      1.1  christos 	ppc_cpu = ppc_opts[i].cpu;
    245      1.1  christos 	break;
    246      1.1  christos       }
    247      1.1  christos   if (i >= sizeof (ppc_opts) / sizeof (ppc_opts[0]))
    248      1.1  christos     return 0;
    249      1.1  christos 
    250      1.1  christos   ppc_cpu |= *sticky;
    251      1.1  christos   return ppc_cpu;
    252      1.1  christos }
    253      1.1  christos 
    254      1.1  christos /* Determine which set of machines to disassemble for.  */
    255      1.1  christos 
    256      1.1  christos static void
    257      1.1  christos powerpc_init_dialect (struct disassemble_info *info)
    258      1.1  christos {
    259      1.1  christos   ppc_cpu_t dialect = 0;
    260      1.1  christos   ppc_cpu_t sticky = 0;
    261      1.1  christos   char *arg;
    262      1.1  christos   struct dis_private *priv = calloc (sizeof (*priv), 1);
    263      1.1  christos 
    264      1.1  christos   if (priv == NULL)
    265      1.1  christos     priv = &private;
    266      1.1  christos 
    267      1.1  christos   switch (info->mach)
    268      1.1  christos     {
    269      1.1  christos     case bfd_mach_ppc_403:
    270      1.1  christos     case bfd_mach_ppc_403gc:
    271      1.1  christos       dialect = ppc_parse_cpu (dialect, &sticky, "403");
    272      1.1  christos       break;
    273      1.1  christos     case bfd_mach_ppc_405:
    274      1.1  christos       dialect = ppc_parse_cpu (dialect, &sticky, "405");
    275      1.1  christos       break;
    276      1.1  christos     case bfd_mach_ppc_601:
    277      1.1  christos       dialect = ppc_parse_cpu (dialect, &sticky, "601");
    278      1.1  christos       break;
    279      1.1  christos     case bfd_mach_ppc_a35:
    280      1.1  christos     case bfd_mach_ppc_rs64ii:
    281      1.1  christos     case bfd_mach_ppc_rs64iii:
    282      1.1  christos       dialect = ppc_parse_cpu (dialect, &sticky, "pwr2") | PPC_OPCODE_64;
    283      1.1  christos       break;
    284      1.1  christos     case bfd_mach_ppc_e500:
    285      1.1  christos       dialect = ppc_parse_cpu (dialect, &sticky, "e500");
    286      1.1  christos       break;
    287      1.1  christos     case bfd_mach_ppc_e500mc:
    288      1.1  christos       dialect = ppc_parse_cpu (dialect, &sticky, "e500mc");
    289      1.1  christos       break;
    290      1.1  christos     case bfd_mach_ppc_e500mc64:
    291      1.1  christos       dialect = ppc_parse_cpu (dialect, &sticky, "e500mc64");
    292      1.1  christos       break;
    293      1.1  christos     case bfd_mach_ppc_e5500:
    294      1.1  christos       dialect = ppc_parse_cpu (dialect, &sticky, "e5500");
    295      1.1  christos       break;
    296      1.1  christos     case bfd_mach_ppc_e6500:
    297      1.1  christos       dialect = ppc_parse_cpu (dialect, &sticky, "e6500");
    298      1.1  christos       break;
    299      1.1  christos     case bfd_mach_ppc_titan:
    300      1.1  christos       dialect = ppc_parse_cpu (dialect, &sticky, "titan");
    301      1.1  christos       break;
    302      1.1  christos     case bfd_mach_ppc_vle:
    303      1.1  christos       dialect = ppc_parse_cpu (dialect, &sticky, "vle");
    304      1.1  christos       break;
    305      1.1  christos     default:
    306      1.1  christos       dialect = ppc_parse_cpu (dialect, &sticky, "power8") | PPC_OPCODE_ANY;
    307      1.1  christos     }
    308      1.1  christos 
    309      1.1  christos   arg = info->disassembler_options;
    310      1.1  christos   while (arg != NULL)
    311      1.1  christos     {
    312      1.1  christos       ppc_cpu_t new_cpu = 0;
    313      1.1  christos       char *end = strchr (arg, ',');
    314      1.1  christos 
    315      1.1  christos       if (end != NULL)
    316      1.1  christos 	*end = 0;
    317      1.1  christos 
    318      1.1  christos       if ((new_cpu = ppc_parse_cpu (dialect, &sticky, arg)) != 0)
    319      1.1  christos 	dialect = new_cpu;
    320      1.1  christos       else if (strcmp (arg, "32") == 0)
    321      1.1  christos 	dialect &= ~(ppc_cpu_t) PPC_OPCODE_64;
    322      1.1  christos       else if (strcmp (arg, "64") == 0)
    323      1.1  christos 	dialect |= PPC_OPCODE_64;
    324      1.1  christos       else
    325      1.1  christos 	fprintf (stderr, _("warning: ignoring unknown -M%s option\n"), arg);
    326      1.1  christos 
    327      1.1  christos       if (end != NULL)
    328      1.1  christos 	*end++ = ',';
    329      1.1  christos       arg = end;
    330      1.1  christos     }
    331      1.1  christos 
    332      1.1  christos   info->private_data = priv;
    333      1.1  christos   POWERPC_DIALECT(info) = dialect;
    334      1.1  christos }
    335      1.1  christos 
    336      1.1  christos #define PPC_OPCD_SEGS 64
    337      1.1  christos static unsigned short powerpc_opcd_indices[PPC_OPCD_SEGS+1];
    338      1.1  christos #define VLE_OPCD_SEGS 32
    339      1.1  christos static unsigned short vle_opcd_indices[VLE_OPCD_SEGS+1];
    340      1.1  christos 
    341      1.1  christos /* Calculate opcode table indices to speed up disassembly,
    342      1.1  christos    and init dialect.  */
    343      1.1  christos 
    344      1.1  christos void
    345      1.1  christos disassemble_init_powerpc (struct disassemble_info *info)
    346      1.1  christos {
    347      1.1  christos   int i;
    348      1.1  christos   unsigned short last;
    349      1.1  christos 
    350  1.3.2.1  pgoyette   if (powerpc_opcd_indices[PPC_OPCD_SEGS] == 0)
    351      1.1  christos     {
    352      1.1  christos 
    353  1.3.2.1  pgoyette       i = powerpc_num_opcodes;
    354  1.3.2.1  pgoyette       while (--i >= 0)
    355  1.3.2.1  pgoyette         {
    356  1.3.2.1  pgoyette           unsigned op = PPC_OP (powerpc_opcodes[i].opcode);
    357      1.1  christos 
    358  1.3.2.1  pgoyette           powerpc_opcd_indices[op] = i;
    359  1.3.2.1  pgoyette         }
    360      1.1  christos 
    361  1.3.2.1  pgoyette       last = powerpc_num_opcodes;
    362  1.3.2.1  pgoyette       for (i = PPC_OPCD_SEGS; i > 0; --i)
    363  1.3.2.1  pgoyette         {
    364  1.3.2.1  pgoyette           if (powerpc_opcd_indices[i] == 0)
    365  1.3.2.1  pgoyette 	    powerpc_opcd_indices[i] = last;
    366  1.3.2.1  pgoyette           last = powerpc_opcd_indices[i];
    367  1.3.2.1  pgoyette         }
    368      1.1  christos 
    369  1.3.2.1  pgoyette       i = vle_num_opcodes;
    370  1.3.2.1  pgoyette       while (--i >= 0)
    371  1.3.2.1  pgoyette         {
    372  1.3.2.1  pgoyette           unsigned op = VLE_OP (vle_opcodes[i].opcode, vle_opcodes[i].mask);
    373  1.3.2.1  pgoyette           unsigned seg = VLE_OP_TO_SEG (op);
    374      1.1  christos 
    375  1.3.2.1  pgoyette           vle_opcd_indices[seg] = i;
    376  1.3.2.1  pgoyette         }
    377  1.3.2.1  pgoyette 
    378  1.3.2.1  pgoyette       last = vle_num_opcodes;
    379  1.3.2.1  pgoyette       for (i = VLE_OPCD_SEGS; i > 0; --i)
    380  1.3.2.1  pgoyette         {
    381  1.3.2.1  pgoyette           if (vle_opcd_indices[i] == 0)
    382  1.3.2.1  pgoyette 	    vle_opcd_indices[i] = last;
    383  1.3.2.1  pgoyette           last = vle_opcd_indices[i];
    384  1.3.2.1  pgoyette         }
    385      1.1  christos     }
    386      1.1  christos 
    387      1.1  christos   if (info->arch == bfd_arch_powerpc)
    388      1.1  christos     powerpc_init_dialect (info);
    389      1.1  christos }
    390      1.1  christos 
    391      1.1  christos /* Print a big endian PowerPC instruction.  */
    392      1.1  christos 
    393      1.1  christos int
    394      1.1  christos print_insn_big_powerpc (bfd_vma memaddr, struct disassemble_info *info)
    395      1.1  christos {
    396      1.1  christos   return print_insn_powerpc (memaddr, info, 1, get_powerpc_dialect (info));
    397      1.1  christos }
    398      1.1  christos 
    399      1.1  christos /* Print a little endian PowerPC instruction.  */
    400      1.1  christos 
    401      1.1  christos int
    402      1.1  christos print_insn_little_powerpc (bfd_vma memaddr, struct disassemble_info *info)
    403      1.1  christos {
    404      1.1  christos   return print_insn_powerpc (memaddr, info, 0, get_powerpc_dialect (info));
    405      1.1  christos }
    406      1.1  christos 
    407      1.1  christos /* Print a POWER (RS/6000) instruction.  */
    408      1.1  christos 
    409      1.1  christos int
    410      1.1  christos print_insn_rs6000 (bfd_vma memaddr, struct disassemble_info *info)
    411      1.1  christos {
    412      1.1  christos   return print_insn_powerpc (memaddr, info, 1, PPC_OPCODE_POWER);
    413      1.1  christos }
    414      1.1  christos 
    415      1.1  christos /* Extract the operand value from the PowerPC or POWER instruction.  */
    416      1.1  christos 
    417      1.1  christos static long
    418      1.1  christos operand_value_powerpc (const struct powerpc_operand *operand,
    419      1.1  christos 		       unsigned long insn, ppc_cpu_t dialect)
    420      1.1  christos {
    421      1.1  christos   long value;
    422      1.1  christos   int invalid;
    423      1.1  christos   /* Extract the value from the instruction.  */
    424      1.1  christos   if (operand->extract)
    425      1.1  christos     value = (*operand->extract) (insn, dialect, &invalid);
    426      1.1  christos   else
    427      1.1  christos     {
    428      1.1  christos       if (operand->shift >= 0)
    429      1.1  christos 	value = (insn >> operand->shift) & operand->bitm;
    430      1.1  christos       else
    431      1.1  christos 	value = (insn << -operand->shift) & operand->bitm;
    432      1.1  christos       if ((operand->flags & PPC_OPERAND_SIGNED) != 0)
    433      1.1  christos 	{
    434      1.1  christos 	  /* BITM is always some number of zeros followed by some
    435      1.1  christos 	     number of ones, followed by some number of zeros.  */
    436      1.1  christos 	  unsigned long top = operand->bitm;
    437      1.1  christos 	  /* top & -top gives the rightmost 1 bit, so this
    438      1.1  christos 	     fills in any trailing zeros.  */
    439      1.1  christos 	  top |= (top & -top) - 1;
    440      1.1  christos 	  top &= ~(top >> 1);
    441      1.1  christos 	  value = (value ^ top) - top;
    442      1.1  christos 	}
    443      1.1  christos     }
    444      1.1  christos 
    445      1.1  christos   return value;
    446      1.1  christos }
    447      1.1  christos 
    448      1.1  christos /* Determine whether the optional operand(s) should be printed.  */
    449      1.1  christos 
    450      1.1  christos static int
    451      1.1  christos skip_optional_operands (const unsigned char *opindex,
    452      1.1  christos 			unsigned long insn, ppc_cpu_t dialect)
    453      1.1  christos {
    454      1.1  christos   const struct powerpc_operand *operand;
    455      1.1  christos 
    456      1.1  christos   for (; *opindex != 0; opindex++)
    457      1.1  christos     {
    458      1.1  christos       operand = &powerpc_operands[*opindex];
    459      1.1  christos       if ((operand->flags & PPC_OPERAND_NEXT) != 0
    460      1.1  christos 	  || ((operand->flags & PPC_OPERAND_OPTIONAL) != 0
    461  1.3.2.1  pgoyette 	      && operand_value_powerpc (operand, insn, dialect) !=
    462  1.3.2.1  pgoyette 		 ppc_optional_operand_value (operand)))
    463      1.1  christos 	return 0;
    464      1.1  christos     }
    465      1.1  christos 
    466      1.1  christos   return 1;
    467      1.1  christos }
    468      1.1  christos 
    469      1.1  christos /* Find a match for INSN in the opcode table, given machine DIALECT.
    470      1.1  christos    A DIALECT of -1 is special, matching all machine opcode variations.  */
    471      1.1  christos 
    472      1.1  christos static const struct powerpc_opcode *
    473      1.1  christos lookup_powerpc (unsigned long insn, ppc_cpu_t dialect)
    474      1.1  christos {
    475      1.1  christos   const struct powerpc_opcode *opcode;
    476      1.1  christos   const struct powerpc_opcode *opcode_end;
    477      1.1  christos   unsigned long op;
    478      1.1  christos 
    479      1.1  christos   /* Get the major opcode of the instruction.  */
    480      1.1  christos   op = PPC_OP (insn);
    481      1.1  christos 
    482      1.1  christos   /* Find the first match in the opcode table for this major opcode.  */
    483      1.1  christos   opcode_end = powerpc_opcodes + powerpc_opcd_indices[op + 1];
    484      1.1  christos   for (opcode = powerpc_opcodes + powerpc_opcd_indices[op];
    485      1.1  christos        opcode < opcode_end;
    486      1.1  christos        ++opcode)
    487      1.1  christos     {
    488      1.1  christos       const unsigned char *opindex;
    489      1.1  christos       const struct powerpc_operand *operand;
    490      1.1  christos       int invalid;
    491      1.1  christos 
    492      1.1  christos       if ((insn & opcode->mask) != opcode->opcode
    493      1.1  christos 	  || (dialect != (ppc_cpu_t) -1
    494      1.1  christos 	      && ((opcode->flags & dialect) == 0
    495      1.1  christos 		  || (opcode->deprecated & dialect) != 0)))
    496      1.1  christos 	continue;
    497      1.1  christos 
    498      1.1  christos       /* Check validity of operands.  */
    499      1.1  christos       invalid = 0;
    500      1.1  christos       for (opindex = opcode->operands; *opindex != 0; opindex++)
    501      1.1  christos 	{
    502      1.1  christos 	  operand = powerpc_operands + *opindex;
    503      1.1  christos 	  if (operand->extract)
    504      1.1  christos 	    (*operand->extract) (insn, dialect, &invalid);
    505      1.1  christos 	}
    506      1.1  christos       if (invalid)
    507      1.1  christos 	continue;
    508      1.1  christos 
    509      1.1  christos       return opcode;
    510      1.1  christos     }
    511      1.1  christos 
    512      1.1  christos   return NULL;
    513      1.1  christos }
    514      1.1  christos 
    515      1.1  christos /* Find a match for INSN in the VLE opcode table.  */
    516      1.1  christos 
    517      1.1  christos static const struct powerpc_opcode *
    518      1.1  christos lookup_vle (unsigned long insn)
    519      1.1  christos {
    520      1.1  christos   const struct powerpc_opcode *opcode;
    521      1.1  christos   const struct powerpc_opcode *opcode_end;
    522      1.1  christos   unsigned op, seg;
    523      1.1  christos 
    524      1.1  christos   op = PPC_OP (insn);
    525      1.1  christos   if (op >= 0x20 && op <= 0x37)
    526      1.1  christos     {
    527      1.1  christos       /* This insn has a 4-bit opcode.  */
    528      1.1  christos       op &= 0x3c;
    529      1.1  christos     }
    530      1.1  christos   seg = VLE_OP_TO_SEG (op);
    531      1.1  christos 
    532      1.1  christos   /* Find the first match in the opcode table for this major opcode.  */
    533      1.1  christos   opcode_end = vle_opcodes + vle_opcd_indices[seg + 1];
    534      1.1  christos   for (opcode = vle_opcodes + vle_opcd_indices[seg];
    535      1.1  christos        opcode < opcode_end;
    536      1.1  christos        ++opcode)
    537      1.1  christos     {
    538      1.1  christos       unsigned long table_opcd = opcode->opcode;
    539      1.1  christos       unsigned long table_mask = opcode->mask;
    540      1.1  christos       bfd_boolean table_op_is_short = PPC_OP_SE_VLE(table_mask);
    541      1.1  christos       unsigned long insn2;
    542      1.1  christos       const unsigned char *opindex;
    543      1.1  christos       const struct powerpc_operand *operand;
    544      1.1  christos       int invalid;
    545      1.1  christos 
    546      1.1  christos       insn2 = insn;
    547      1.1  christos       if (table_op_is_short)
    548      1.1  christos 	insn2 >>= 16;
    549      1.1  christos       if ((insn2 & table_mask) != table_opcd)
    550      1.1  christos 	continue;
    551      1.1  christos 
    552      1.1  christos       /* Check validity of operands.  */
    553      1.1  christos       invalid = 0;
    554      1.1  christos       for (opindex = opcode->operands; *opindex != 0; ++opindex)
    555      1.1  christos 	{
    556      1.1  christos 	  operand = powerpc_operands + *opindex;
    557      1.1  christos 	  if (operand->extract)
    558      1.1  christos 	    (*operand->extract) (insn, (ppc_cpu_t)0, &invalid);
    559      1.1  christos 	}
    560      1.1  christos       if (invalid)
    561      1.1  christos 	continue;
    562      1.1  christos 
    563      1.1  christos       return opcode;
    564      1.1  christos     }
    565      1.1  christos 
    566      1.1  christos   return NULL;
    567      1.1  christos }
    568      1.1  christos 
    569      1.1  christos /* Print a PowerPC or POWER instruction.  */
    570      1.1  christos 
    571      1.1  christos static int
    572      1.1  christos print_insn_powerpc (bfd_vma memaddr,
    573      1.1  christos 		    struct disassemble_info *info,
    574      1.1  christos 		    int bigendian,
    575      1.1  christos 		    ppc_cpu_t dialect)
    576      1.1  christos {
    577      1.1  christos   bfd_byte buffer[4];
    578      1.1  christos   int status;
    579      1.1  christos   unsigned long insn;
    580      1.1  christos   const struct powerpc_opcode *opcode;
    581      1.1  christos   bfd_boolean insn_is_short;
    582      1.1  christos 
    583      1.1  christos   status = (*info->read_memory_func) (memaddr, buffer, 4, info);
    584      1.1  christos   if (status != 0)
    585      1.1  christos     {
    586      1.1  christos       /* The final instruction may be a 2-byte VLE insn.  */
    587      1.1  christos       if ((dialect & PPC_OPCODE_VLE) != 0)
    588      1.1  christos         {
    589      1.1  christos           /* Clear buffer so unused bytes will not have garbage in them.  */
    590      1.1  christos           buffer[0] = buffer[1] = buffer[2] = buffer[3] = 0;
    591      1.1  christos           status = (*info->read_memory_func) (memaddr, buffer, 2, info);
    592      1.1  christos           if (status != 0)
    593      1.1  christos             {
    594      1.1  christos               (*info->memory_error_func) (status, memaddr, info);
    595      1.1  christos               return -1;
    596      1.1  christos             }
    597      1.1  christos         }
    598      1.1  christos       else
    599      1.1  christos         {
    600      1.1  christos           (*info->memory_error_func) (status, memaddr, info);
    601      1.1  christos           return -1;
    602      1.1  christos         }
    603      1.1  christos     }
    604      1.1  christos 
    605      1.1  christos   if (bigendian)
    606      1.1  christos     insn = bfd_getb32 (buffer);
    607      1.1  christos   else
    608      1.1  christos     insn = bfd_getl32 (buffer);
    609      1.1  christos 
    610      1.1  christos   /* Get the major opcode of the insn.  */
    611      1.1  christos   opcode = NULL;
    612      1.1  christos   insn_is_short = FALSE;
    613      1.1  christos   if ((dialect & PPC_OPCODE_VLE) != 0)
    614      1.1  christos     {
    615      1.1  christos       opcode = lookup_vle (insn);
    616      1.1  christos       if (opcode != NULL)
    617      1.1  christos 	insn_is_short = PPC_OP_SE_VLE(opcode->mask);
    618      1.1  christos     }
    619      1.1  christos   if (opcode == NULL)
    620      1.1  christos     opcode = lookup_powerpc (insn, dialect);
    621      1.1  christos   if (opcode == NULL && (dialect & PPC_OPCODE_ANY) != 0)
    622      1.1  christos     opcode = lookup_powerpc (insn, (ppc_cpu_t) -1);
    623      1.1  christos 
    624      1.1  christos   if (opcode != NULL)
    625      1.1  christos     {
    626      1.1  christos       const unsigned char *opindex;
    627      1.1  christos       const struct powerpc_operand *operand;
    628      1.1  christos       int need_comma;
    629      1.1  christos       int need_paren;
    630      1.1  christos       int skip_optional;
    631      1.1  christos 
    632      1.1  christos       if (opcode->operands[0] != 0)
    633      1.1  christos 	(*info->fprintf_func) (info->stream, "%-7s ", opcode->name);
    634      1.1  christos       else
    635      1.1  christos 	(*info->fprintf_func) (info->stream, "%s", opcode->name);
    636      1.1  christos 
    637      1.1  christos       if (insn_is_short)
    638      1.1  christos         /* The operands will be fetched out of the 16-bit instruction.  */
    639      1.1  christos         insn >>= 16;
    640      1.1  christos 
    641      1.1  christos       /* Now extract and print the operands.  */
    642      1.1  christos       need_comma = 0;
    643      1.1  christos       need_paren = 0;
    644      1.1  christos       skip_optional = -1;
    645      1.1  christos       for (opindex = opcode->operands; *opindex != 0; opindex++)
    646      1.1  christos 	{
    647      1.1  christos 	  long value;
    648      1.1  christos 
    649      1.1  christos 	  operand = powerpc_operands + *opindex;
    650      1.1  christos 
    651      1.1  christos 	  /* Operands that are marked FAKE are simply ignored.  We
    652      1.1  christos 	     already made sure that the extract function considered
    653      1.1  christos 	     the instruction to be valid.  */
    654      1.1  christos 	  if ((operand->flags & PPC_OPERAND_FAKE) != 0)
    655      1.1  christos 	    continue;
    656      1.1  christos 
    657      1.1  christos 	  /* If all of the optional operands have the value zero,
    658      1.1  christos 	     then don't print any of them.  */
    659      1.1  christos 	  if ((operand->flags & PPC_OPERAND_OPTIONAL) != 0)
    660      1.1  christos 	    {
    661      1.1  christos 	      if (skip_optional < 0)
    662      1.1  christos 		skip_optional = skip_optional_operands (opindex, insn,
    663      1.1  christos 							dialect);
    664      1.1  christos 	      if (skip_optional)
    665      1.1  christos 		continue;
    666      1.1  christos 	    }
    667      1.1  christos 
    668      1.1  christos 	  value = operand_value_powerpc (operand, insn, dialect);
    669      1.1  christos 
    670      1.1  christos 	  if (need_comma)
    671      1.1  christos 	    {
    672      1.1  christos 	      (*info->fprintf_func) (info->stream, ",");
    673      1.1  christos 	      need_comma = 0;
    674      1.1  christos 	    }
    675      1.1  christos 
    676      1.1  christos 	  /* Print the operand as directed by the flags.  */
    677      1.1  christos 	  if ((operand->flags & PPC_OPERAND_GPR) != 0
    678      1.1  christos 	      || ((operand->flags & PPC_OPERAND_GPR_0) != 0 && value != 0))
    679      1.1  christos 	    (*info->fprintf_func) (info->stream, "r%ld", value);
    680      1.1  christos 	  else if ((operand->flags & PPC_OPERAND_FPR) != 0)
    681      1.1  christos 	    (*info->fprintf_func) (info->stream, "f%ld", value);
    682      1.1  christos 	  else if ((operand->flags & PPC_OPERAND_VR) != 0)
    683      1.1  christos 	    (*info->fprintf_func) (info->stream, "v%ld", value);
    684      1.1  christos 	  else if ((operand->flags & PPC_OPERAND_VSR) != 0)
    685      1.1  christos 	    (*info->fprintf_func) (info->stream, "vs%ld", value);
    686      1.1  christos 	  else if ((operand->flags & PPC_OPERAND_RELATIVE) != 0)
    687      1.1  christos 	    (*info->print_address_func) (memaddr + value, info);
    688      1.1  christos 	  else if ((operand->flags & PPC_OPERAND_ABSOLUTE) != 0)
    689      1.1  christos 	    (*info->print_address_func) ((bfd_vma) value & 0xffffffff, info);
    690      1.1  christos 	  else if ((operand->flags & PPC_OPERAND_FSL) != 0)
    691      1.1  christos 	    (*info->fprintf_func) (info->stream, "fsl%ld", value);
    692      1.1  christos 	  else if ((operand->flags & PPC_OPERAND_FCR) != 0)
    693      1.1  christos 	    (*info->fprintf_func) (info->stream, "fcr%ld", value);
    694      1.1  christos 	  else if ((operand->flags & PPC_OPERAND_UDI) != 0)
    695      1.1  christos 	    (*info->fprintf_func) (info->stream, "%ld", value);
    696      1.1  christos 	  else if ((operand->flags & PPC_OPERAND_CR_REG) != 0
    697      1.1  christos 		   && (((dialect & PPC_OPCODE_PPC) != 0)
    698      1.1  christos 		       || ((dialect & PPC_OPCODE_VLE) != 0)))
    699      1.1  christos 	    (*info->fprintf_func) (info->stream, "cr%ld", value);
    700      1.1  christos 	  else if (((operand->flags & PPC_OPERAND_CR_BIT) != 0)
    701      1.1  christos 		   && (((dialect & PPC_OPCODE_PPC) != 0)
    702      1.1  christos 		       || ((dialect & PPC_OPCODE_VLE) != 0)))
    703      1.1  christos 	    {
    704      1.1  christos 	      static const char *cbnames[4] = { "lt", "gt", "eq", "so" };
    705      1.1  christos 	      int cr;
    706      1.1  christos 	      int cc;
    707      1.1  christos 
    708      1.1  christos 	      cr = value >> 2;
    709      1.1  christos 	      if (cr != 0)
    710      1.1  christos 		(*info->fprintf_func) (info->stream, "4*cr%d+", cr);
    711      1.1  christos 	      cc = value & 3;
    712      1.1  christos 	      (*info->fprintf_func) (info->stream, "%s", cbnames[cc]);
    713      1.1  christos 	    }
    714      1.1  christos 	  else
    715      1.1  christos 	    (*info->fprintf_func) (info->stream, "%d", (int) value);
    716      1.1  christos 
    717      1.1  christos 	  if (need_paren)
    718      1.1  christos 	    {
    719      1.1  christos 	      (*info->fprintf_func) (info->stream, ")");
    720      1.1  christos 	      need_paren = 0;
    721      1.1  christos 	    }
    722      1.1  christos 
    723      1.1  christos 	  if ((operand->flags & PPC_OPERAND_PARENS) == 0)
    724      1.1  christos 	    need_comma = 1;
    725      1.1  christos 	  else
    726      1.1  christos 	    {
    727      1.1  christos 	      (*info->fprintf_func) (info->stream, "(");
    728      1.1  christos 	      need_paren = 1;
    729      1.1  christos 	    }
    730      1.1  christos 	}
    731      1.1  christos 
    732      1.1  christos       /* We have found and printed an instruction.
    733      1.1  christos          If it was a short VLE instruction we have more to do.  */
    734      1.1  christos       if (insn_is_short)
    735      1.1  christos         {
    736      1.1  christos           memaddr += 2;
    737      1.1  christos           return 2;
    738      1.1  christos         }
    739      1.1  christos       else
    740      1.1  christos         /* Otherwise, return.  */
    741      1.1  christos         return 4;
    742      1.1  christos     }
    743      1.1  christos 
    744      1.1  christos   /* We could not find a match.  */
    745      1.1  christos   (*info->fprintf_func) (info->stream, ".long 0x%lx", insn);
    746      1.1  christos 
    747      1.1  christos   return 4;
    748      1.1  christos }
    749      1.1  christos 
    750      1.1  christos void
    751      1.1  christos print_ppc_disassembler_options (FILE *stream)
    752      1.1  christos {
    753      1.1  christos   unsigned int i, col;
    754      1.1  christos 
    755      1.1  christos   fprintf (stream, _("\n\
    756      1.1  christos The following PPC specific disassembler options are supported for use with\n\
    757      1.1  christos the -M switch:\n"));
    758      1.1  christos 
    759      1.1  christos   for (col = 0, i = 0; i < sizeof (ppc_opts) / sizeof (ppc_opts[0]); i++)
    760      1.1  christos     {
    761      1.1  christos       col += fprintf (stream, " %s,", ppc_opts[i].opt);
    762      1.1  christos       if (col > 66)
    763      1.1  christos 	{
    764      1.1  christos 	  fprintf (stream, "\n");
    765      1.1  christos 	  col = 0;
    766      1.1  christos 	}
    767      1.1  christos     }
    768      1.1  christos   fprintf (stream, " 32, 64\n");
    769      1.1  christos }
    770