Home | History | Annotate | Line # | Download | only in opcodes
vax-dis.c revision 1.1
      1  1.1  christos /* Print VAX instructions.
      2  1.1  christos    Copyright 1995, 1998, 2000, 2001, 2002, 2005, 2007, 2009, 2012
      3  1.1  christos    Free Software Foundation, Inc.
      4  1.1  christos    Contributed by Pauline Middelink <middelin (at) polyware.iaf.nl>
      5  1.1  christos 
      6  1.1  christos    This file is part of the GNU opcodes library.
      7  1.1  christos 
      8  1.1  christos    This library is free software; you can redistribute it and/or modify
      9  1.1  christos    it under the terms of the GNU General Public License as published by
     10  1.1  christos    the Free Software Foundation; either version 3, or (at your option)
     11  1.1  christos    any later version.
     12  1.1  christos 
     13  1.1  christos    It is distributed in the hope that it will be useful, but WITHOUT
     14  1.1  christos    ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
     15  1.1  christos    or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public
     16  1.1  christos    License for more details.
     17  1.1  christos 
     18  1.1  christos    You should have received a copy of the GNU General Public License
     19  1.1  christos    along with this program; if not, write to the Free Software
     20  1.1  christos    Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
     21  1.1  christos    MA 02110-1301, USA.  */
     22  1.1  christos 
     23  1.1  christos #include "sysdep.h"
     24  1.1  christos #include <setjmp.h>
     25  1.1  christos #include <string.h>
     26  1.1  christos #include "opcode/vax.h"
     27  1.1  christos #include "dis-asm.h"
     28  1.1  christos 
     29  1.1  christos static char *reg_names[] =
     30  1.1  christos {
     31  1.1  christos   "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7",
     32  1.1  christos   "r8", "r9", "r10", "r11", "ap", "fp", "sp", "pc"
     33  1.1  christos };
     34  1.1  christos 
     35  1.1  christos /* Definitions for the function entry mask bits.  */
     36  1.1  christos static char *entry_mask_bit[] =
     37  1.1  christos {
     38  1.1  christos   /* Registers 0 and 1 shall not be saved, since they're used to pass back
     39  1.1  christos      a function's result to its caller...  */
     40  1.1  christos   "~r0~", "~r1~",
     41  1.1  christos   /* Registers 2 .. 11 are normal registers.  */
     42  1.1  christos   "r2", "r3", "r4", "r5", "r6", "r7", "r8", "r9", "r10", "r11",
     43  1.1  christos   /* Registers 12 and 13 are argument and frame pointer and must not
     44  1.1  christos      be saved by using the entry mask.  */
     45  1.1  christos   "~ap~", "~fp~",
     46  1.1  christos   /* Bits 14 and 15 control integer and decimal overflow.  */
     47  1.1  christos   "IntOvfl", "DecOvfl",
     48  1.1  christos };
     49  1.1  christos 
     50  1.1  christos /* Sign-extend an (unsigned char). */
     51  1.1  christos #define COERCE_SIGNED_CHAR(ch) ((signed char)(ch))
     52  1.1  christos 
     53  1.1  christos /* Get a 1 byte signed integer.  */
     54  1.1  christos #define NEXTBYTE(p)  \
     55  1.1  christos   (p += 1, FETCH_DATA (info, p), \
     56  1.1  christos   COERCE_SIGNED_CHAR(p[-1]))
     57  1.1  christos 
     58  1.1  christos /* Get a 2 byte signed integer.  */
     59  1.1  christos #define COERCE16(x) ((int) (((x) ^ 0x8000) - 0x8000))
     60  1.1  christos #define NEXTWORD(p)  \
     61  1.1  christos   (p += 2, FETCH_DATA (info, p), \
     62  1.1  christos    COERCE16 ((p[-1] << 8) + p[-2]))
     63  1.1  christos 
     64  1.1  christos /* Get a 4 byte signed integer.  */
     65  1.1  christos #define COERCE32(x) ((int) (((x) ^ 0x80000000) - 0x80000000))
     66  1.1  christos #define NEXTLONG(p)  \
     67  1.1  christos   (p += 4, FETCH_DATA (info, p), \
     68  1.1  christos    (COERCE32 ((((((p[-1] << 8) + p[-2]) << 8) + p[-3]) << 8) + p[-4])))
     69  1.1  christos 
     70  1.1  christos /* Maximum length of an instruction.  */
     71  1.1  christos #define MAXLEN 25
     72  1.1  christos 
     73  1.1  christos struct private
     74  1.1  christos {
     75  1.1  christos   /* Points to first byte not fetched.  */
     76  1.1  christos   bfd_byte * max_fetched;
     77  1.1  christos   bfd_byte   the_buffer[MAXLEN];
     78  1.1  christos   bfd_vma    insn_start;
     79  1.1  christos   jmp_buf    bailout;
     80  1.1  christos };
     81  1.1  christos 
     82  1.1  christos /* Make sure that bytes from INFO->PRIVATE_DATA->BUFFER (inclusive)
     83  1.1  christos    to ADDR (exclusive) are valid.  Returns 1 for success, longjmps
     84  1.1  christos    on error.  */
     85  1.1  christos #define FETCH_DATA(info, addr) \
     86  1.1  christos   ((addr) <= ((struct private *)(info->private_data))->max_fetched \
     87  1.1  christos    ? 1 : fetch_data ((info), (addr)))
     88  1.1  christos 
     89  1.1  christos static int
     90  1.1  christos fetch_data (struct disassemble_info *info, bfd_byte *addr)
     91  1.1  christos {
     92  1.1  christos   int status;
     93  1.1  christos   struct private *priv = (struct private *) info->private_data;
     94  1.1  christos   bfd_vma start = priv->insn_start + (priv->max_fetched - priv->the_buffer);
     95  1.1  christos 
     96  1.1  christos   status = (*info->read_memory_func) (start,
     97  1.1  christos 				      priv->max_fetched,
     98  1.1  christos 				      addr - priv->max_fetched,
     99  1.1  christos 				      info);
    100  1.1  christos   if (status != 0)
    101  1.1  christos     {
    102  1.1  christos       (*info->memory_error_func) (status, start, info);
    103  1.1  christos       longjmp (priv->bailout, 1);
    104  1.1  christos     }
    105  1.1  christos   else
    106  1.1  christos     priv->max_fetched = addr;
    107  1.1  christos 
    108  1.1  christos   return 1;
    109  1.1  christos }
    110  1.1  christos 
    111  1.1  christos /* Entry mask handling.  */
    112  1.1  christos static unsigned int  entry_addr_occupied_slots = 0;
    113  1.1  christos static unsigned int  entry_addr_total_slots = 0;
    114  1.1  christos static bfd_vma *     entry_addr = NULL;
    115  1.1  christos 
    116  1.1  christos /* Parse the VAX specific disassembler options.  These contain function
    117  1.1  christos    entry addresses, which can be useful to disassemble ROM images, since
    118  1.1  christos    there's no symbol table.  Returns TRUE upon success, FALSE otherwise.  */
    119  1.1  christos 
    120  1.1  christos static bfd_boolean
    121  1.1  christos parse_disassembler_options (char * options)
    122  1.1  christos {
    123  1.1  christos   const char * entry_switch = "entry:";
    124  1.1  christos 
    125  1.1  christos   while ((options = strstr (options, entry_switch)))
    126  1.1  christos     {
    127  1.1  christos       options += strlen (entry_switch);
    128  1.1  christos 
    129  1.1  christos       /* The greater-than part of the test below is paranoia.  */
    130  1.1  christos       if (entry_addr_occupied_slots >= entry_addr_total_slots)
    131  1.1  christos 	{
    132  1.1  christos 	  /* A guesstimate of the number of entries we will have to create.  */
    133  1.1  christos 	  entry_addr_total_slots +=
    134  1.1  christos 	    strlen (options) / (strlen (entry_switch) + 5);
    135  1.1  christos 
    136  1.1  christos 	  entry_addr = realloc (entry_addr, sizeof (bfd_vma)
    137  1.1  christos 				* entry_addr_total_slots);
    138  1.1  christos 	}
    139  1.1  christos 
    140  1.1  christos       if (entry_addr == NULL)
    141  1.1  christos 	return FALSE;
    142  1.1  christos 
    143  1.1  christos       entry_addr[entry_addr_occupied_slots] = bfd_scan_vma (options, NULL, 0);
    144  1.1  christos       entry_addr_occupied_slots ++;
    145  1.1  christos     }
    146  1.1  christos 
    147  1.1  christos   return TRUE;
    148  1.1  christos }
    149  1.1  christos 
    150  1.1  christos #if 0 /* FIXME:  Ideally the disassembler should have target specific
    151  1.1  christos 	 initialisation and termination function pointers.  Then
    152  1.1  christos 	 parse_disassembler_options could be the init function and
    153  1.1  christos 	 free_entry_array (below) could be the termination routine.
    154  1.1  christos 	 Until then there is no way for the disassembler to tell us
    155  1.1  christos 	 that it has finished and that we no longer need the entry
    156  1.1  christos 	 array, so this routine is suppressed for now.  It does mean
    157  1.1  christos 	 that we leak memory, but only to the extent that we do not
    158  1.1  christos 	 free it just before the disassembler is about to terminate
    159  1.1  christos 	 anyway.  */
    160  1.1  christos 
    161  1.1  christos /* Free memory allocated to our entry array.  */
    162  1.1  christos 
    163  1.1  christos static void
    164  1.1  christos free_entry_array (void)
    165  1.1  christos {
    166  1.1  christos   if (entry_addr)
    167  1.1  christos     {
    168  1.1  christos       free (entry_addr);
    169  1.1  christos       entry_addr = NULL;
    170  1.1  christos       entry_addr_occupied_slots = entry_addr_total_slots = 0;
    171  1.1  christos     }
    172  1.1  christos }
    173  1.1  christos #endif
    174  1.1  christos /* Check if the given address is a known function entry point.  This is
    175  1.1  christos    the case if there is a symbol of the function type at this address.
    176  1.1  christos    We also check for synthetic symbols as these are used for PLT entries
    177  1.1  christos    (weak undefined symbols may not have the function type set).  Finally
    178  1.1  christos    the address may have been forced to be treated as an entry point.  The
    179  1.1  christos    latter helps in disassembling ROM images, because there's no symbol
    180  1.1  christos    table at all.  Forced entry points can be given by supplying several
    181  1.1  christos    -M options to objdump: -M entry:0xffbb7730.  */
    182  1.1  christos 
    183  1.1  christos static bfd_boolean
    184  1.1  christos is_function_entry (struct disassemble_info *info, bfd_vma addr)
    185  1.1  christos {
    186  1.1  christos   unsigned int i;
    187  1.1  christos 
    188  1.1  christos   /* Check if there's a function or PLT symbol at our address.  */
    189  1.1  christos   if (info->symbols
    190  1.1  christos       && info->symbols[0]
    191  1.1  christos       && (info->symbols[0]->flags & (BSF_FUNCTION | BSF_SYNTHETIC))
    192  1.1  christos       && addr == bfd_asymbol_value (info->symbols[0]))
    193  1.1  christos     return TRUE;
    194  1.1  christos 
    195  1.1  christos   /* Check for forced function entry address.  */
    196  1.1  christos   for (i = entry_addr_occupied_slots; i--;)
    197  1.1  christos     if (entry_addr[i] == addr)
    198  1.1  christos       return TRUE;
    199  1.1  christos 
    200  1.1  christos   return FALSE;
    201  1.1  christos }
    202  1.1  christos 
    203  1.1  christos /* Check if the given address is the last longword of a PLT entry.
    204  1.1  christos    This longword is data and depending on the value it may interfere
    205  1.1  christos    with disassembly of further PLT entries.  We make use of the fact
    206  1.1  christos    PLT symbols are marked BSF_SYNTHETIC.  */
    207  1.1  christos static bfd_boolean
    208  1.1  christos is_plt_tail (struct disassemble_info *info, bfd_vma addr)
    209  1.1  christos {
    210  1.1  christos   if (info->symbols
    211  1.1  christos       && info->symbols[0]
    212  1.1  christos       && (info->symbols[0]->flags & BSF_SYNTHETIC)
    213  1.1  christos       && addr == bfd_asymbol_value (info->symbols[0]) + 8)
    214  1.1  christos     return TRUE;
    215  1.1  christos 
    216  1.1  christos   return FALSE;
    217  1.1  christos }
    218  1.1  christos 
    219  1.1  christos static int
    220  1.1  christos print_insn_mode (const char *d,
    221  1.1  christos 		 int size,
    222  1.1  christos 		 unsigned char *p0,
    223  1.1  christos 		 bfd_vma addr,	/* PC for this arg to be relative to.  */
    224  1.1  christos 		 disassemble_info *info)
    225  1.1  christos {
    226  1.1  christos   unsigned char *p = p0;
    227  1.1  christos   unsigned char mode, reg;
    228  1.1  christos 
    229  1.1  christos   /* Fetch and interpret mode byte.  */
    230  1.1  christos   mode = (unsigned char) NEXTBYTE (p);
    231  1.1  christos   reg = mode & 0xF;
    232  1.1  christos   switch (mode & 0xF0)
    233  1.1  christos     {
    234  1.1  christos     case 0x00:
    235  1.1  christos     case 0x10:
    236  1.1  christos     case 0x20:
    237  1.1  christos     case 0x30: /* Literal mode			$number.  */
    238  1.1  christos       if (d[1] == 'd' || d[1] == 'f' || d[1] == 'g' || d[1] == 'h')
    239  1.1  christos 	(*info->fprintf_func) (info->stream, "$0x%x [%c-float]", mode, d[1]);
    240  1.1  christos       else
    241  1.1  christos         (*info->fprintf_func) (info->stream, "$0x%x", mode);
    242  1.1  christos       break;
    243  1.1  christos     case 0x40: /* Index:			base-addr[Rn] */
    244  1.1  christos       p += print_insn_mode (d, size, p0 + 1, addr + 1, info);
    245  1.1  christos       (*info->fprintf_func) (info->stream, "[%s]", reg_names[reg]);
    246  1.1  christos       break;
    247  1.1  christos     case 0x50: /* Register:			Rn */
    248  1.1  christos       (*info->fprintf_func) (info->stream, "%s", reg_names[reg]);
    249  1.1  christos       break;
    250  1.1  christos     case 0x60: /* Register deferred:		(Rn) */
    251  1.1  christos       (*info->fprintf_func) (info->stream, "(%s)", reg_names[reg]);
    252  1.1  christos       break;
    253  1.1  christos     case 0x70: /* Autodecrement:		-(Rn) */
    254  1.1  christos       (*info->fprintf_func) (info->stream, "-(%s)", reg_names[reg]);
    255  1.1  christos       break;
    256  1.1  christos     case 0x80: /* Autoincrement:		(Rn)+ */
    257  1.1  christos       if (reg == 0xF)
    258  1.1  christos 	{	/* Immediate?  */
    259  1.1  christos 	  int i;
    260  1.1  christos 
    261  1.1  christos 	  FETCH_DATA (info, p + size);
    262  1.1  christos 	  (*info->fprintf_func) (info->stream, "$0x");
    263  1.1  christos 	  if (d[1] == 'd' || d[1] == 'f' || d[1] == 'g' || d[1] == 'h')
    264  1.1  christos 	    {
    265  1.1  christos 	      int float_word;
    266  1.1  christos 
    267  1.1  christos 	      float_word = p[0] | (p[1] << 8);
    268  1.1  christos 	      if ((d[1] == 'd' || d[1] == 'f')
    269  1.1  christos 		  && (float_word & 0xff80) == 0x8000)
    270  1.1  christos 		{
    271  1.1  christos 		  (*info->fprintf_func) (info->stream, "[invalid %c-float]",
    272  1.1  christos 					 d[1]);
    273  1.1  christos 		}
    274  1.1  christos 	      else
    275  1.1  christos 		{
    276  1.1  christos 	          for (i = 0; i < size; i++)
    277  1.1  christos 		    (*info->fprintf_func) (info->stream, "%02x",
    278  1.1  christos 		                           p[size - i - 1]);
    279  1.1  christos 	          (*info->fprintf_func) (info->stream, " [%c-float]", d[1]);
    280  1.1  christos 		}
    281  1.1  christos 	    }
    282  1.1  christos 	  else
    283  1.1  christos 	    {
    284  1.1  christos 	      for (i = 0; i < size; i++)
    285  1.1  christos 	        (*info->fprintf_func) (info->stream, "%02x", p[size - i - 1]);
    286  1.1  christos 	    }
    287  1.1  christos 	  p += size;
    288  1.1  christos 	}
    289  1.1  christos       else
    290  1.1  christos 	(*info->fprintf_func) (info->stream, "(%s)+", reg_names[reg]);
    291  1.1  christos       break;
    292  1.1  christos     case 0x90: /* Autoincrement deferred:	@(Rn)+ */
    293  1.1  christos       if (reg == 0xF)
    294  1.1  christos 	(*info->fprintf_func) (info->stream, "*0x%x", NEXTLONG (p));
    295  1.1  christos       else
    296  1.1  christos 	(*info->fprintf_func) (info->stream, "@(%s)+", reg_names[reg]);
    297  1.1  christos       break;
    298  1.1  christos     case 0xB0: /* Displacement byte deferred:	*displ(Rn).  */
    299  1.1  christos       (*info->fprintf_func) (info->stream, "*");
    300  1.1  christos     case 0xA0: /* Displacement byte:		displ(Rn).  */
    301  1.1  christos       if (reg == 0xF)
    302  1.1  christos 	(*info->print_address_func) (addr + 2 + NEXTBYTE (p), info);
    303  1.1  christos       else
    304  1.1  christos 	(*info->fprintf_func) (info->stream, "0x%x(%s)", NEXTBYTE (p),
    305  1.1  christos 			       reg_names[reg]);
    306  1.1  christos       break;
    307  1.1  christos     case 0xD0: /* Displacement word deferred:	*displ(Rn).  */
    308  1.1  christos       (*info->fprintf_func) (info->stream, "*");
    309  1.1  christos     case 0xC0: /* Displacement word:		displ(Rn).  */
    310  1.1  christos       if (reg == 0xF)
    311  1.1  christos 	(*info->print_address_func) (addr + 3 + NEXTWORD (p), info);
    312  1.1  christos       else
    313  1.1  christos 	(*info->fprintf_func) (info->stream, "0x%x(%s)", NEXTWORD (p),
    314  1.1  christos 			       reg_names[reg]);
    315  1.1  christos       break;
    316  1.1  christos     case 0xF0: /* Displacement long deferred:	*displ(Rn).  */
    317  1.1  christos       (*info->fprintf_func) (info->stream, "*");
    318  1.1  christos     case 0xE0: /* Displacement long:		displ(Rn).  */
    319  1.1  christos       if (reg == 0xF)
    320  1.1  christos 	(*info->print_address_func) (addr + 5 + NEXTLONG (p), info);
    321  1.1  christos       else
    322  1.1  christos 	(*info->fprintf_func) (info->stream, "0x%x(%s)", NEXTLONG (p),
    323  1.1  christos 			       reg_names[reg]);
    324  1.1  christos       break;
    325  1.1  christos     }
    326  1.1  christos 
    327  1.1  christos   return p - p0;
    328  1.1  christos }
    329  1.1  christos 
    330  1.1  christos /* Returns number of bytes "eaten" by the operand, or return -1 if an
    331  1.1  christos    invalid operand was found, or -2 if an opcode tabel error was
    332  1.1  christos    found. */
    333  1.1  christos 
    334  1.1  christos static int
    335  1.1  christos print_insn_arg (const char *d,
    336  1.1  christos 		unsigned char *p0,
    337  1.1  christos 		bfd_vma addr,	/* PC for this arg to be relative to.  */
    338  1.1  christos 		disassemble_info *info)
    339  1.1  christos {
    340  1.1  christos   int arg_len;
    341  1.1  christos 
    342  1.1  christos   /* Check validity of addressing length.  */
    343  1.1  christos   switch (d[1])
    344  1.1  christos     {
    345  1.1  christos     case 'b' : arg_len = 1;	break;
    346  1.1  christos     case 'd' : arg_len = 8;	break;
    347  1.1  christos     case 'f' : arg_len = 4;	break;
    348  1.1  christos     case 'g' : arg_len = 8;	break;
    349  1.1  christos     case 'h' : arg_len = 16;	break;
    350  1.1  christos     case 'l' : arg_len = 4;	break;
    351  1.1  christos     case 'o' : arg_len = 16;	break;
    352  1.1  christos     case 'w' : arg_len = 2;	break;
    353  1.1  christos     case 'q' : arg_len = 8;	break;
    354  1.1  christos     default  : abort ();
    355  1.1  christos     }
    356  1.1  christos 
    357  1.1  christos   /* Branches have no mode byte.  */
    358  1.1  christos   if (d[0] == 'b')
    359  1.1  christos     {
    360  1.1  christos       unsigned char *p = p0;
    361  1.1  christos 
    362  1.1  christos       if (arg_len == 1)
    363  1.1  christos 	(*info->print_address_func) (addr + 1 + NEXTBYTE (p), info);
    364  1.1  christos       else
    365  1.1  christos 	(*info->print_address_func) (addr + 2 + NEXTWORD (p), info);
    366  1.1  christos 
    367  1.1  christos       return p - p0;
    368  1.1  christos     }
    369  1.1  christos 
    370  1.1  christos   return print_insn_mode (d, arg_len, p0, addr, info);
    371  1.1  christos }
    372  1.1  christos 
    373  1.1  christos /* Print the vax instruction at address MEMADDR in debugged memory,
    374  1.1  christos    on INFO->STREAM.  Returns length of the instruction, in bytes.  */
    375  1.1  christos 
    376  1.1  christos int
    377  1.1  christos print_insn_vax (bfd_vma memaddr, disassemble_info *info)
    378  1.1  christos {
    379  1.1  christos   static bfd_boolean parsed_disassembler_options = FALSE;
    380  1.1  christos   const struct vot *votp;
    381  1.1  christos   const char *argp;
    382  1.1  christos   unsigned char *arg;
    383  1.1  christos   struct private priv;
    384  1.1  christos   bfd_byte *buffer = priv.the_buffer;
    385  1.1  christos 
    386  1.1  christos   info->private_data = & priv;
    387  1.1  christos   priv.max_fetched = priv.the_buffer;
    388  1.1  christos   priv.insn_start = memaddr;
    389  1.1  christos 
    390  1.1  christos   if (! parsed_disassembler_options
    391  1.1  christos       && info->disassembler_options != NULL)
    392  1.1  christos     {
    393  1.1  christos       parse_disassembler_options (info->disassembler_options);
    394  1.1  christos 
    395  1.1  christos       /* To avoid repeated parsing of these options.  */
    396  1.1  christos       parsed_disassembler_options = TRUE;
    397  1.1  christos     }
    398  1.1  christos 
    399  1.1  christos   if (setjmp (priv.bailout) != 0)
    400  1.1  christos     /* Error return.  */
    401  1.1  christos     return -1;
    402  1.1  christos 
    403  1.1  christos   argp = NULL;
    404  1.1  christos   /* Check if the info buffer has more than one byte left since
    405  1.1  christos      the last opcode might be a single byte with no argument data.  */
    406  1.1  christos   if (info->buffer_length - (memaddr - info->buffer_vma) > 1)
    407  1.1  christos     {
    408  1.1  christos       FETCH_DATA (info, buffer + 2);
    409  1.1  christos     }
    410  1.1  christos   else
    411  1.1  christos     {
    412  1.1  christos       FETCH_DATA (info, buffer + 1);
    413  1.1  christos       buffer[1] = 0;
    414  1.1  christos     }
    415  1.1  christos 
    416  1.1  christos   /* Decode function entry mask.  */
    417  1.1  christos   if (is_function_entry (info, memaddr))
    418  1.1  christos     {
    419  1.1  christos       int i = 0;
    420  1.1  christos       int register_mask = buffer[1] << 8 | buffer[0];
    421  1.1  christos 
    422  1.1  christos       (*info->fprintf_func) (info->stream, ".word 0x%04x # Entry mask: <",
    423  1.1  christos 			     register_mask);
    424  1.1  christos 
    425  1.1  christos       for (i = 15; i >= 0; i--)
    426  1.1  christos 	if (register_mask & (1 << i))
    427  1.1  christos           (*info->fprintf_func) (info->stream, " %s", entry_mask_bit[i]);
    428  1.1  christos 
    429  1.1  christos       (*info->fprintf_func) (info->stream, " >");
    430  1.1  christos 
    431  1.1  christos       return 2;
    432  1.1  christos     }
    433  1.1  christos 
    434  1.1  christos   /* Decode PLT entry offset longword.  */
    435  1.1  christos   if (is_plt_tail (info, memaddr))
    436  1.1  christos     {
    437  1.1  christos       int offset;
    438  1.1  christos 
    439  1.1  christos       FETCH_DATA (info, buffer + 4);
    440  1.1  christos       offset = buffer[3] << 24 | buffer[2] << 16 | buffer[1] << 8 | buffer[0];
    441  1.1  christos       (*info->fprintf_func) (info->stream, ".long 0x%08x", offset);
    442  1.1  christos 
    443  1.1  christos       return 4;
    444  1.1  christos     }
    445  1.1  christos 
    446  1.1  christos   for (votp = &votstrs[0]; votp->name[0]; votp++)
    447  1.1  christos     {
    448  1.1  christos       vax_opcodeT opcode = votp->detail.code;
    449  1.1  christos 
    450  1.1  christos       /* 2 byte codes match 2 buffer pos. */
    451  1.1  christos       if ((bfd_byte) opcode == buffer[0]
    452  1.1  christos 	  && (opcode >> 8 == 0 || opcode >> 8 == buffer[1]))
    453  1.1  christos 	{
    454  1.1  christos 	  argp = votp->detail.args;
    455  1.1  christos 	  break;
    456  1.1  christos 	}
    457  1.1  christos     }
    458  1.1  christos   if (argp == NULL)
    459  1.1  christos     {
    460  1.1  christos       /* Handle undefined instructions. */
    461  1.1  christos       (*info->fprintf_func) (info->stream, ".word 0x%x",
    462  1.1  christos 			     (buffer[0] << 8) + buffer[1]);
    463  1.1  christos       return 2;
    464  1.1  christos     }
    465  1.1  christos 
    466  1.1  christos   /* Point at first byte of argument data, and at descriptor for first
    467  1.1  christos      argument.  */
    468  1.1  christos   arg = buffer + ((votp->detail.code >> 8) ? 2 : 1);
    469  1.1  christos 
    470  1.1  christos   /* Make sure we have it in mem */
    471  1.1  christos   FETCH_DATA (info, arg);
    472  1.1  christos 
    473  1.1  christos   (*info->fprintf_func) (info->stream, "%s", votp->name);
    474  1.1  christos   if (*argp)
    475  1.1  christos     (*info->fprintf_func) (info->stream, " ");
    476  1.1  christos 
    477  1.1  christos   while (*argp)
    478  1.1  christos     {
    479  1.1  christos       arg += print_insn_arg (argp, arg, memaddr + arg - buffer, info);
    480  1.1  christos       argp += 2;
    481  1.1  christos       if (*argp)
    482  1.1  christos 	(*info->fprintf_func) (info->stream, ",");
    483  1.1  christos     }
    484  1.1  christos 
    485  1.1  christos   return arg - buffer;
    486  1.1  christos }
    487  1.1  christos 
    488