(root)/
binutils-2.41/
opcodes/
ia64-dis.c
       1  /* ia64-dis.c -- Disassemble ia64 instructions
       2     Copyright (C) 1998-2023 Free Software Foundation, Inc.
       3     Contributed by David Mosberger-Tang <davidm@hpl.hp.com>
       4  
       5     This file is part of the GNU opcodes library.
       6  
       7     This library is free software; you can redistribute it and/or modify
       8     it under the terms of the GNU General Public License as published by
       9     the Free Software Foundation; either version 3, or (at your option)
      10     any later version.
      11  
      12     It is distributed in the hope that it will be useful, but WITHOUT
      13     ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
      14     or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public
      15     License for more details.
      16  
      17     You should have received a copy of the GNU General Public License
      18     along with this file; see the file COPYING.  If not, write to the
      19     Free Software Foundation, 51 Franklin Street - Fifth Floor, Boston, MA
      20     02110-1301, USA.  */
      21  
      22  #include "sysdep.h"
      23  #include <assert.h>
      24  
      25  #include "disassemble.h"
      26  #include "opcode/ia64.h"
      27  
      28  #define NELEMS(a)	((int) (sizeof (a) / sizeof (a[0])))
      29  
      30  /* Disassemble ia64 instruction.  */
      31  
      32  /* Return the instruction type for OPCODE found in unit UNIT. */
      33  
      34  static enum ia64_insn_type
      35  unit_to_type (ia64_insn opcode, enum ia64_unit unit)
      36  {
      37    enum ia64_insn_type type;
      38    int op;
      39  
      40    op = IA64_OP (opcode);
      41  
      42    if (op >= 8 && (unit == IA64_UNIT_I || unit == IA64_UNIT_M))
      43      {
      44        type = IA64_TYPE_A;
      45      }
      46    else
      47      {
      48        switch (unit)
      49  	{
      50  	case IA64_UNIT_I:
      51  	  type = IA64_TYPE_I; break;
      52  	case IA64_UNIT_M:
      53  	  type = IA64_TYPE_M; break;
      54  	case IA64_UNIT_B:
      55  	  type = IA64_TYPE_B; break;
      56  	case IA64_UNIT_F:
      57  	  type = IA64_TYPE_F; break;
      58          case IA64_UNIT_L:
      59  	case IA64_UNIT_X:
      60  	  type = IA64_TYPE_X; break;
      61  	default:
      62  	  type = -1;
      63  	}
      64      }
      65    return type;
      66  }
      67  
      68  int
      69  print_insn_ia64 (bfd_vma memaddr, struct disassemble_info *info)
      70  {
      71    ia64_insn t0, t1, slot[3], template_val, s_bit, insn;
      72    int slotnum, j, status, need_comma, retval, slot_multiplier;
      73    const struct ia64_operand *odesc;
      74    const struct ia64_opcode *idesc;
      75    const char *err, *str, *tname;
      76    uint64_t value;
      77    bfd_byte bundle[16];
      78    enum ia64_unit unit;
      79    char regname[16];
      80  
      81    if (info->bytes_per_line == 0)
      82      info->bytes_per_line = 6;
      83    info->display_endian = info->endian;
      84  
      85    slot_multiplier = info->bytes_per_line;
      86    retval = slot_multiplier;
      87  
      88    slotnum = (((long) memaddr) & 0xf) / slot_multiplier;
      89    if (slotnum > 2)
      90      return -1;
      91  
      92    memaddr -= (memaddr & 0xf);
      93    status = (*info->read_memory_func) (memaddr, bundle, sizeof (bundle), info);
      94    if (status != 0)
      95      {
      96        (*info->memory_error_func) (status, memaddr, info);
      97        return -1;
      98      }
      99    /* bundles are always in little-endian byte order */
     100    t0 = bfd_getl64 (bundle);
     101    t1 = bfd_getl64 (bundle + 8);
     102    s_bit = t0 & 1;
     103    template_val = (t0 >> 1) & 0xf;
     104    slot[0] = (t0 >>  5) & 0x1ffffffffffLL;
     105    slot[1] = ((t0 >> 46) & 0x3ffff) | ((t1 & 0x7fffff) << 18);
     106    slot[2] = (t1 >> 23) & 0x1ffffffffffLL;
     107  
     108    tname = ia64_templ_desc[template_val].name;
     109    if (slotnum == 0)
     110      (*info->fprintf_func) (info->stream, "[%s] ", tname);
     111    else
     112      (*info->fprintf_func) (info->stream, "      ");
     113  
     114    unit = ia64_templ_desc[template_val].exec_unit[slotnum];
     115  
     116    if (template_val == 2 && slotnum == 1)
     117      {
     118        /* skip L slot in MLI template: */
     119        slotnum = 2;
     120        retval += slot_multiplier;
     121      }
     122  
     123    insn = slot[slotnum];
     124  
     125    if (unit == IA64_UNIT_NIL)
     126      goto decoding_failed;
     127  
     128    idesc = ia64_dis_opcode (insn, unit_to_type (insn, unit));
     129    if (idesc == NULL)
     130      goto decoding_failed;
     131  
     132    /* print predicate, if any: */
     133  
     134    if ((idesc->flags & IA64_OPCODE_NO_PRED)
     135        || (insn & 0x3f) == 0)
     136      (*info->fprintf_func) (info->stream, "      ");
     137    else
     138      (*info->fprintf_func) (info->stream, "(p%02d) ", (int)(insn & 0x3f));
     139  
     140    /* now the actual instruction: */
     141  
     142    (*info->fprintf_func) (info->stream, "%s", idesc->name);
     143    if (idesc->operands[0])
     144      (*info->fprintf_func) (info->stream, " ");
     145  
     146    need_comma = 0;
     147    for (j = 0; j < NELEMS (idesc->operands) && idesc->operands[j]; ++j)
     148      {
     149        odesc = elf64_ia64_operands + idesc->operands[j];
     150  
     151        if (need_comma)
     152  	(*info->fprintf_func) (info->stream, ",");
     153  
     154        if (odesc - elf64_ia64_operands == IA64_OPND_IMMU64)
     155  	{
     156  	  /* special case of 64 bit immediate load: */
     157  	  value = ((insn >> 13) & 0x7f) | (((insn >> 27) & 0x1ff) << 7)
     158  	    | (((insn >> 22) & 0x1f) << 16) | (((insn >> 21) & 0x1) << 21)
     159  	    | (slot[1] << 22) | (((insn >> 36) & 0x1) << 63);
     160  	}
     161        else if (odesc - elf64_ia64_operands == IA64_OPND_IMMU62)
     162          {
     163            /* 62-bit immediate for nop.x/break.x */
     164            value = ((slot[1] & 0x1ffffffffffLL) << 21)
     165              | (((insn >> 36) & 0x1) << 20)
     166              | ((insn >> 6) & 0xfffff);
     167          }
     168        else if (odesc - elf64_ia64_operands == IA64_OPND_TGT64)
     169  	{
     170  	  /* 60-bit immediate for long branches. */
     171  	  value = (((insn >> 13) & 0xfffff)
     172  		   | (((insn >> 36) & 1) << 59)
     173  		   | (((slot[1] >> 2) & 0x7fffffffffLL) << 20)) << 4;
     174  	}
     175        else
     176  	{
     177  	  err = (*odesc->extract) (odesc, insn, &value);
     178  	  if (err)
     179  	    {
     180  	      (*info->fprintf_func) (info->stream, "%s", err);
     181  	      goto done;
     182  	    }
     183  	}
     184  
     185  	switch (odesc->op_class)
     186  	  {
     187  	  case IA64_OPND_CLASS_CST:
     188  	    (*info->fprintf_func) (info->stream, "%s", odesc->str);
     189  	    break;
     190  
     191  	  case IA64_OPND_CLASS_REG:
     192  	    if (odesc->str[0] == 'a' && odesc->str[1] == 'r')
     193  	      {
     194  		switch (value)
     195  		  {
     196  		  case 0: case 1: case 2: case 3:
     197  		  case 4: case 5: case 6: case 7:
     198  		    sprintf (regname, "ar.k%u", (unsigned int) value);
     199  		    break;
     200  		  case 16:	strcpy (regname, "ar.rsc"); break;
     201  		  case 17:	strcpy (regname, "ar.bsp"); break;
     202  		  case 18:	strcpy (regname, "ar.bspstore"); break;
     203  		  case 19:	strcpy (regname, "ar.rnat"); break;
     204  		  case 21:	strcpy (regname, "ar.fcr"); break;
     205  		  case 24:	strcpy (regname, "ar.eflag"); break;
     206  		  case 25:	strcpy (regname, "ar.csd"); break;
     207  		  case 26:	strcpy (regname, "ar.ssd"); break;
     208  		  case 27:	strcpy (regname, "ar.cflg"); break;
     209  		  case 28:	strcpy (regname, "ar.fsr"); break;
     210  		  case 29:	strcpy (regname, "ar.fir"); break;
     211  		  case 30:	strcpy (regname, "ar.fdr"); break;
     212  		  case 32:	strcpy (regname, "ar.ccv"); break;
     213  		  case 36:	strcpy (regname, "ar.unat"); break;
     214  		  case 40:	strcpy (regname, "ar.fpsr"); break;
     215  		  case 44:	strcpy (regname, "ar.itc"); break;
     216  		  case 45:	strcpy (regname, "ar.ruc"); break;
     217  		  case 64:	strcpy (regname, "ar.pfs"); break;
     218  		  case 65:	strcpy (regname, "ar.lc"); break;
     219  		  case 66:	strcpy (regname, "ar.ec"); break;
     220  		  default:
     221  		    sprintf (regname, "ar%u", (unsigned int) value);
     222  		    break;
     223  		  }
     224  		(*info->fprintf_func) (info->stream, "%s", regname);
     225  	      }
     226  	    else if (odesc->str[0] == 'c' && odesc->str[1] == 'r')
     227  	      {
     228  		switch (value)
     229  		  {
     230  		  case 0:       strcpy (regname, "cr.dcr"); break;
     231  		  case 1:       strcpy (regname, "cr.itm"); break;
     232  		  case 2:       strcpy (regname, "cr.iva"); break;
     233  		  case 8:       strcpy (regname, "cr.pta"); break;
     234  		  case 16:      strcpy (regname, "cr.ipsr"); break;
     235  		  case 17:      strcpy (regname, "cr.isr"); break;
     236  		  case 19:      strcpy (regname, "cr.iip"); break;
     237  		  case 20:      strcpy (regname, "cr.ifa"); break;
     238  		  case 21:      strcpy (regname, "cr.itir"); break;
     239  		  case 22:      strcpy (regname, "cr.iipa"); break;
     240  		  case 23:      strcpy (regname, "cr.ifs"); break;
     241  		  case 24:      strcpy (regname, "cr.iim"); break;
     242  		  case 25:      strcpy (regname, "cr.iha"); break;
     243  		  case 26:      strcpy (regname, "cr.iib0"); break;
     244  		  case 27:      strcpy (regname, "cr.iib1"); break;
     245  		  case 64:      strcpy (regname, "cr.lid"); break;
     246  		  case 65:      strcpy (regname, "cr.ivr"); break;
     247  		  case 66:      strcpy (regname, "cr.tpr"); break;
     248  		  case 67:      strcpy (regname, "cr.eoi"); break;
     249  		  case 68:      strcpy (regname, "cr.irr0"); break;
     250  		  case 69:      strcpy (regname, "cr.irr1"); break;
     251  		  case 70:      strcpy (regname, "cr.irr2"); break;
     252  		  case 71:      strcpy (regname, "cr.irr3"); break;
     253  		  case 72:      strcpy (regname, "cr.itv"); break;
     254  		  case 73:      strcpy (regname, "cr.pmv"); break;
     255  		  case 74:      strcpy (regname, "cr.cmcv"); break;
     256  		  case 80:      strcpy (regname, "cr.lrr0"); break;
     257  		  case 81:      strcpy (regname, "cr.lrr1"); break;
     258  		  default:
     259  		    sprintf (regname, "cr%u", (unsigned int) value);
     260  		    break;
     261  		  }
     262  		(*info->fprintf_func) (info->stream, "%s", regname);
     263  	      }
     264  	    else
     265  	      (*info->fprintf_func) (info->stream, "%s%d", odesc->str, (int)value);
     266  	    break;
     267  
     268  	  case IA64_OPND_CLASS_IND:
     269  	    (*info->fprintf_func) (info->stream, "%s[r%d]", odesc->str, (int)value);
     270  	    break;
     271  
     272  	  case IA64_OPND_CLASS_ABS:
     273  	    str = 0;
     274  	    if (odesc - elf64_ia64_operands == IA64_OPND_MBTYPE4)
     275  	      switch (value)
     276  		{
     277  		case 0x0: str = "@brcst"; break;
     278  		case 0x8: str = "@mix"; break;
     279  		case 0x9: str = "@shuf"; break;
     280  		case 0xa: str = "@alt"; break;
     281  		case 0xb: str = "@rev"; break;
     282  		}
     283  
     284  	    if (str)
     285  	      (*info->fprintf_func) (info->stream, "%s", str);
     286  	    else if (odesc->flags & IA64_OPND_FLAG_DECIMAL_SIGNED)
     287  	      (*info->fprintf_func) (info->stream, "%lld", (long long) value);
     288  	    else if (odesc->flags & IA64_OPND_FLAG_DECIMAL_UNSIGNED)
     289  	      (*info->fprintf_func) (info->stream, "%llu", (long long) value);
     290  	    else
     291  	      (*info->fprintf_func) (info->stream, "0x%llx", (long long) value);
     292  	    break;
     293  
     294  	  case IA64_OPND_CLASS_REL:
     295  	    (*info->print_address_func) (memaddr + value, info);
     296  	    break;
     297  	  }
     298  
     299        need_comma = 1;
     300        if (j + 1 == idesc->num_outputs)
     301  	{
     302  	  (*info->fprintf_func) (info->stream, "=");
     303  	  need_comma = 0;
     304  	}
     305      }
     306    if (slotnum + 1 == ia64_templ_desc[template_val].group_boundary
     307        || ((slotnum == 2) && s_bit))
     308      (*info->fprintf_func) (info->stream, ";;");
     309  
     310   done:
     311    ia64_free_opcode ((struct ia64_opcode *)idesc);
     312   failed:
     313    if (slotnum == 2)
     314      retval += 16 - 3*slot_multiplier;
     315    return retval;
     316  
     317   decoding_failed:
     318    (*info->fprintf_func) (info->stream, "      data8 %#011llx", (long long) insn);
     319    goto failed;
     320  }