xref: /openbsd-src/gnu/usr.bin/binutils/opcodes/vax-dis.c (revision d2201f2f89f0be1a0be6f7568000ed297414a06d)
1f7cc78ecSespie /* Print VAX instructions.
2*d2201f2fSdrahn    Copyright 1995, 1998, 2000, 2001, 2002 Free Software Foundation, Inc.
3f7cc78ecSespie    Contributed by Pauline Middelink <middelin@polyware.iaf.nl>
4f7cc78ecSespie 
5f7cc78ecSespie This program is free software; you can redistribute it and/or modify
6f7cc78ecSespie it under the terms of the GNU General Public License as published by
7f7cc78ecSespie the Free Software Foundation; either version 2 of the License, or
8f7cc78ecSespie (at your option) any later version.
9f7cc78ecSespie 
10f7cc78ecSespie This program is distributed in the hope that it will be useful,
11f7cc78ecSespie but WITHOUT ANY WARRANTY; without even the implied warranty of
12f7cc78ecSespie MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13f7cc78ecSespie GNU General Public License for more details.
14f7cc78ecSespie 
15f7cc78ecSespie You should have received a copy of the GNU General Public License
16f7cc78ecSespie along with this program; if not, write to the Free Software
17f7cc78ecSespie Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
18f7cc78ecSespie 
19f7cc78ecSespie #include "sysdep.h"
20f7cc78ecSespie #include "opcode/vax.h"
21f7cc78ecSespie #include "dis-asm.h"
22f7cc78ecSespie 
23f7cc78ecSespie /* Local function prototypes */
24*d2201f2fSdrahn static int fetch_data PARAMS ((struct disassemble_info *, bfd_byte *));
25*d2201f2fSdrahn static int print_insn_arg
26*d2201f2fSdrahn   PARAMS ((const char *, unsigned char *, bfd_vma, disassemble_info *));
27*d2201f2fSdrahn static int print_insn_mode
28*d2201f2fSdrahn   PARAMS ((const char *, int, unsigned char *, bfd_vma, disassemble_info *));
29f7cc78ecSespie 
30f7cc78ecSespie 
31f7cc78ecSespie static char *reg_names[] =
32f7cc78ecSespie {
33f7cc78ecSespie   "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7",
34f7cc78ecSespie   "r8", "r9", "r10", "r11", "ap", "fp", "sp", "pc"
35f7cc78ecSespie };
36f7cc78ecSespie 
37f7cc78ecSespie /* Sign-extend an (unsigned char). */
38f7cc78ecSespie #if __STDC__ == 1
39f7cc78ecSespie #define COERCE_SIGNED_CHAR(ch) ((signed char)(ch))
40f7cc78ecSespie #else
41f7cc78ecSespie #define COERCE_SIGNED_CHAR(ch) ((int)(((ch) ^ 0x80) & 0xFF) - 128)
42f7cc78ecSespie #endif
43f7cc78ecSespie 
44f7cc78ecSespie /* Get a 1 byte signed integer.  */
45f7cc78ecSespie #define NEXTBYTE(p)  \
46f7cc78ecSespie   (p += 1, FETCH_DATA (info, p), \
47f7cc78ecSespie   COERCE_SIGNED_CHAR(p[-1]))
48f7cc78ecSespie 
49f7cc78ecSespie /* Get a 2 byte signed integer.  */
50f7cc78ecSespie #define COERCE16(x) ((int) (((x) ^ 0x8000) - 0x8000))
51f7cc78ecSespie #define NEXTWORD(p)  \
52f7cc78ecSespie   (p += 2, FETCH_DATA (info, p), \
53f7cc78ecSespie    COERCE16 ((p[-1] << 8) + p[-2]))
54f7cc78ecSespie 
55f7cc78ecSespie /* Get a 4 byte signed integer.  */
56f7cc78ecSespie #define COERCE32(x) ((int) (((x) ^ 0x80000000) - 0x80000000))
57f7cc78ecSespie #define NEXTLONG(p)  \
58f7cc78ecSespie   (p += 4, FETCH_DATA (info, p), \
59f7cc78ecSespie    (COERCE32 ((((((p[-1] << 8) + p[-2]) << 8) + p[-3]) << 8) + p[-4])))
60f7cc78ecSespie 
61f7cc78ecSespie /* Maximum length of an instruction.  */
62f7cc78ecSespie #define MAXLEN 25
63f7cc78ecSespie 
64f7cc78ecSespie #include <setjmp.h>
65f7cc78ecSespie 
66f7cc78ecSespie struct private
67f7cc78ecSespie {
68f7cc78ecSespie   /* Points to first byte not fetched.  */
69f7cc78ecSespie   bfd_byte *max_fetched;
70f7cc78ecSespie   bfd_byte the_buffer[MAXLEN];
71f7cc78ecSespie   bfd_vma insn_start;
72f7cc78ecSespie   jmp_buf bailout;
73f7cc78ecSespie };
74f7cc78ecSespie 
75f7cc78ecSespie /* Make sure that bytes from INFO->PRIVATE_DATA->BUFFER (inclusive)
76f7cc78ecSespie    to ADDR (exclusive) are valid.  Returns 1 for success, longjmps
77f7cc78ecSespie    on error.  */
78f7cc78ecSespie #define FETCH_DATA(info, addr) \
79f7cc78ecSespie   ((addr) <= ((struct private *)(info->private_data))->max_fetched \
80f7cc78ecSespie    ? 1 : fetch_data ((info), (addr)))
81f7cc78ecSespie 
82f7cc78ecSespie static int
fetch_data(info,addr)83f7cc78ecSespie fetch_data (info, addr)
84f7cc78ecSespie      struct disassemble_info *info;
85f7cc78ecSespie      bfd_byte *addr;
86f7cc78ecSespie {
87f7cc78ecSespie   int status;
88f7cc78ecSespie   struct private *priv = (struct private *) info->private_data;
89f7cc78ecSespie   bfd_vma start = priv->insn_start + (priv->max_fetched - priv->the_buffer);
90f7cc78ecSespie 
91f7cc78ecSespie   status = (*info->read_memory_func) (start,
92f7cc78ecSespie 				      priv->max_fetched,
93f7cc78ecSespie 				      addr - priv->max_fetched,
94f7cc78ecSespie 				      info);
95f7cc78ecSespie   if (status != 0)
96f7cc78ecSespie     {
97f7cc78ecSespie       (*info->memory_error_func) (status, start, info);
98f7cc78ecSespie       longjmp (priv->bailout, 1);
99f7cc78ecSespie     }
100f7cc78ecSespie   else
101f7cc78ecSespie     priv->max_fetched = addr;
102f7cc78ecSespie 
103f7cc78ecSespie   return 1;
104f7cc78ecSespie }
105f7cc78ecSespie 
106f7cc78ecSespie /* Print the vax instruction at address MEMADDR in debugged memory,
107f7cc78ecSespie    on INFO->STREAM.  Returns length of the instruction, in bytes.  */
108f7cc78ecSespie 
109f7cc78ecSespie int
print_insn_vax(memaddr,info)110f7cc78ecSespie print_insn_vax (memaddr, info)
111f7cc78ecSespie      bfd_vma memaddr;
112f7cc78ecSespie      disassemble_info *info;
113f7cc78ecSespie {
114f7cc78ecSespie   const struct vot *votp;
115*d2201f2fSdrahn   const char *argp;
116f7cc78ecSespie   unsigned char *arg;
117f7cc78ecSespie   struct private priv;
118f7cc78ecSespie   bfd_byte *buffer = priv.the_buffer;
119f7cc78ecSespie 
120f7cc78ecSespie   info->private_data = (PTR) &priv;
121f7cc78ecSespie   priv.max_fetched = priv.the_buffer;
122f7cc78ecSespie   priv.insn_start = memaddr;
123*d2201f2fSdrahn 
124f7cc78ecSespie   if (setjmp (priv.bailout) != 0)
125f7cc78ecSespie     {
126f7cc78ecSespie       /* Error return.  */
127f7cc78ecSespie       return -1;
128f7cc78ecSespie     }
129f7cc78ecSespie 
130*d2201f2fSdrahn   argp = NULL;
1315f210c2aSfgsch   /* Check if the info buffer has more than one byte left since
1325f210c2aSfgsch      the last opcode might be a single byte with no argument data.  */
1335f210c2aSfgsch   if (info->buffer_length - (memaddr - info->buffer_vma) > 1)
1345f210c2aSfgsch     {
135f7cc78ecSespie       FETCH_DATA (info, buffer + 2);
1365f210c2aSfgsch     }
1375f210c2aSfgsch   else
1385f210c2aSfgsch     {
1395f210c2aSfgsch       FETCH_DATA (info, buffer + 1);
1405f210c2aSfgsch       buffer[1] = 0;
1415f210c2aSfgsch     }
1425f210c2aSfgsch 
143f7cc78ecSespie   for (votp = &votstrs[0]; votp->name[0]; votp++)
144f7cc78ecSespie     {
145f7cc78ecSespie       register vax_opcodeT opcode = votp->detail.code;
146f7cc78ecSespie 
147f7cc78ecSespie       /* 2 byte codes match 2 buffer pos. */
148f7cc78ecSespie       if ((bfd_byte) opcode == buffer[0]
149f7cc78ecSespie 	  && (opcode >> 8 == 0 || opcode >> 8 == buffer[1]))
150f7cc78ecSespie 	{
151f7cc78ecSespie 	  argp = votp->detail.args;
152f7cc78ecSespie 	  break;
153f7cc78ecSespie 	}
154f7cc78ecSespie     }
155f7cc78ecSespie   if (argp == NULL)
156f7cc78ecSespie     {
157f7cc78ecSespie       /* Handle undefined instructions. */
158f7cc78ecSespie       (*info->fprintf_func) (info->stream, ".word 0x%x",
159f7cc78ecSespie 			     (buffer[0] << 8) + buffer[1]);
160f7cc78ecSespie       return 2;
161f7cc78ecSespie     }
162f7cc78ecSespie 
163f7cc78ecSespie   /* Point at first byte of argument data, and at descriptor for first
164f7cc78ecSespie      argument.  */
165f7cc78ecSespie   arg = buffer + ((votp->detail.code >> 8) ? 2 : 1);
166f7cc78ecSespie 
167f7cc78ecSespie   /* Make sure we have it in mem */
168f7cc78ecSespie   FETCH_DATA (info, arg);
169f7cc78ecSespie 
170f7cc78ecSespie   (*info->fprintf_func) (info->stream, "%s", votp->name);
171f7cc78ecSespie   if (*argp)
172f7cc78ecSespie     (*info->fprintf_func) (info->stream, " ");
173f7cc78ecSespie 
174f7cc78ecSespie   while (*argp)
175f7cc78ecSespie     {
176f7cc78ecSespie       arg += print_insn_arg (argp, arg, memaddr + arg - buffer, info);
177f7cc78ecSespie       argp += 2;
178f7cc78ecSespie       if (*argp)
179f7cc78ecSespie 	(*info->fprintf_func) (info->stream, ",");
180f7cc78ecSespie     }
181f7cc78ecSespie 
182f7cc78ecSespie   return arg - buffer;
183f7cc78ecSespie }
184f7cc78ecSespie 
185f7cc78ecSespie /* Returns number of bytes "eaten" by the operand, or return -1 if an
186f7cc78ecSespie    invalid operand was found, or -2 if an opcode tabel error was
187f7cc78ecSespie    found. */
188f7cc78ecSespie 
189f7cc78ecSespie static int
print_insn_arg(d,p0,addr,info)190f7cc78ecSespie print_insn_arg (d, p0, addr, info)
191f7cc78ecSespie      const char *d;
192f7cc78ecSespie      unsigned char *p0;
193f7cc78ecSespie      bfd_vma addr;		/* PC for this arg to be relative to */
194f7cc78ecSespie      disassemble_info *info;
195f7cc78ecSespie {
196f7cc78ecSespie   int arg_len;
197f7cc78ecSespie 
198f7cc78ecSespie   /* check validity of addressing length */
199f7cc78ecSespie   switch (d[1])
200f7cc78ecSespie     {
201f7cc78ecSespie     case 'b' : arg_len = 1;	break;
202f7cc78ecSespie     case 'd' : arg_len = 8;	break;
203f7cc78ecSespie     case 'f' : arg_len = 4;	break;
204f7cc78ecSespie     case 'g' : arg_len = 8;	break;
205f7cc78ecSespie     case 'h' : arg_len = 16;	break;
206f7cc78ecSespie     case 'l' : arg_len = 4;	break;
207f7cc78ecSespie     case 'o' : arg_len = 16;	break;
208f7cc78ecSespie     case 'w' : arg_len = 2;	break;
209f7cc78ecSespie     case 'q' : arg_len = 8;	break;
210f7cc78ecSespie     default  : abort();
211f7cc78ecSespie     }
212f7cc78ecSespie 
213f7cc78ecSespie   /* branches have no mode byte */
214f7cc78ecSespie   if (d[0] == 'b')
215f7cc78ecSespie     {
216f7cc78ecSespie       unsigned char *p = p0;
217f7cc78ecSespie 
218f7cc78ecSespie       if (arg_len == 1)
219f7cc78ecSespie 	(*info->print_address_func) (addr + 1 + NEXTBYTE (p), info);
220f7cc78ecSespie       else
221f7cc78ecSespie 	(*info->print_address_func) (addr + 2 + NEXTWORD (p), info);
222f7cc78ecSespie 
223f7cc78ecSespie       return p - p0;
224f7cc78ecSespie     }
225f7cc78ecSespie 
226*d2201f2fSdrahn   return print_insn_mode (d, arg_len, p0, addr, info);
227f7cc78ecSespie }
228f7cc78ecSespie 
229f7cc78ecSespie static int
print_insn_mode(d,size,p0,addr,info)230*d2201f2fSdrahn print_insn_mode (d, size, p0, addr, info)
231*d2201f2fSdrahn      const char *d;
232f7cc78ecSespie      int size;
233f7cc78ecSespie      unsigned char *p0;
234f7cc78ecSespie      bfd_vma addr;		/* PC for this arg to be relative to */
235f7cc78ecSespie      disassemble_info *info;
236f7cc78ecSespie {
237f7cc78ecSespie   unsigned char *p = p0;
238f7cc78ecSespie   unsigned char mode, reg;
239f7cc78ecSespie 
240f7cc78ecSespie   /* fetch and interpret mode byte */
241f7cc78ecSespie   mode = (unsigned char) NEXTBYTE (p);
242f7cc78ecSespie   reg = mode & 0xF;
243f7cc78ecSespie   switch (mode & 0xF0)
244f7cc78ecSespie     {
245f7cc78ecSespie     case 0x00:
246f7cc78ecSespie     case 0x10:
247f7cc78ecSespie     case 0x20:
248f7cc78ecSespie     case 0x30: /* literal mode			$number */
249*d2201f2fSdrahn       if (d[1] == 'd' || d[1] == 'f' || d[1] == 'g' || d[1] == 'h')
250*d2201f2fSdrahn 	(*info->fprintf_func) (info->stream, "$0x%x [%c-float]", mode, d[1]);
251*d2201f2fSdrahn       else
252f7cc78ecSespie         (*info->fprintf_func) (info->stream, "$0x%x", mode);
253f7cc78ecSespie       break;
254f7cc78ecSespie     case 0x40: /* index:			base-addr[Rn] */
255*d2201f2fSdrahn       p += print_insn_mode (d, size, p0 + 1, addr + 1, info);
256f7cc78ecSespie       (*info->fprintf_func) (info->stream, "[%s]", reg_names[reg]);
257f7cc78ecSespie       break;
258f7cc78ecSespie     case 0x50: /* register:			Rn */
259f7cc78ecSespie       (*info->fprintf_func) (info->stream, "%s", reg_names[reg]);
260f7cc78ecSespie       break;
261f7cc78ecSespie     case 0x60: /* register deferred:		(Rn) */
262f7cc78ecSespie       (*info->fprintf_func) (info->stream, "(%s)", reg_names[reg]);
263f7cc78ecSespie       break;
264f7cc78ecSespie     case 0x70: /* autodecrement:		-(Rn) */
265f7cc78ecSespie       (*info->fprintf_func) (info->stream, "-(%s)", reg_names[reg]);
266f7cc78ecSespie       break;
267f7cc78ecSespie     case 0x80: /* autoincrement:		(Rn)+ */
268f7cc78ecSespie       if (reg == 0xF)
269f7cc78ecSespie 	{	/* immediate? */
270f7cc78ecSespie 	  int i;
271f7cc78ecSespie 
272f7cc78ecSespie 	  FETCH_DATA (info, p + size);
273f7cc78ecSespie 	  (*info->fprintf_func) (info->stream, "$0x");
274*d2201f2fSdrahn 	  if (d[1] == 'd' || d[1] == 'f' || d[1] == 'g' || d[1] == 'h')
275*d2201f2fSdrahn 	    {
276*d2201f2fSdrahn 	      int float_word;
277*d2201f2fSdrahn 
278*d2201f2fSdrahn 	      float_word = p[0] | (p[1] << 8);
279*d2201f2fSdrahn 	      if ((d[1] == 'd' || d[1] == 'f')
280*d2201f2fSdrahn 		  && (float_word & 0xff80) == 0x8000)
281*d2201f2fSdrahn 		{
282*d2201f2fSdrahn 		  (*info->fprintf_func) (info->stream, "[invalid %c-float]",
283*d2201f2fSdrahn 					 d[1]);
284*d2201f2fSdrahn 		}
285*d2201f2fSdrahn 	      else
286*d2201f2fSdrahn 		{
287*d2201f2fSdrahn 	          for (i = 0; i < size; i++)
288*d2201f2fSdrahn 		    (*info->fprintf_func) (info->stream, "%02x",
289*d2201f2fSdrahn 		                           p[size - i - 1]);
290*d2201f2fSdrahn 	          (*info->fprintf_func) (info->stream, " [%c-float]", d[1]);
291*d2201f2fSdrahn 		}
292*d2201f2fSdrahn 	    }
293*d2201f2fSdrahn 	  else
294*d2201f2fSdrahn 	    {
295f7cc78ecSespie 	      for (i = 0; i < size; i++)
296f7cc78ecSespie 	        (*info->fprintf_func) (info->stream, "%02x", p[size - i - 1]);
297*d2201f2fSdrahn 	    }
298f7cc78ecSespie 	  p += size;
299f7cc78ecSespie 	}
300f7cc78ecSespie       else
301f7cc78ecSespie 	(*info->fprintf_func) (info->stream, "(%s)+", reg_names[reg]);
302f7cc78ecSespie       break;
303f7cc78ecSespie     case 0x90: /* autoincrement deferred:	@(Rn)+ */
304f7cc78ecSespie       if (reg == 0xF)
305f7cc78ecSespie 	(*info->fprintf_func) (info->stream, "*0x%x", NEXTLONG (p));
306f7cc78ecSespie       else
307f7cc78ecSespie 	(*info->fprintf_func) (info->stream, "@(%s)+", reg_names[reg]);
308f7cc78ecSespie       break;
309f7cc78ecSespie     case 0xB0: /* displacement byte deferred:	*displ(Rn) */
310f7cc78ecSespie       (*info->fprintf_func) (info->stream, "*");
311f7cc78ecSespie     case 0xA0: /* displacement byte:		displ(Rn) */
312f7cc78ecSespie       if (reg == 0xF)
313f7cc78ecSespie 	(*info->print_address_func) (addr + 2 + NEXTBYTE (p), info);
314f7cc78ecSespie       else
315f7cc78ecSespie 	(*info->fprintf_func) (info->stream, "0x%x(%s)", NEXTBYTE (p),
316f7cc78ecSespie 			       reg_names[reg]);
317f7cc78ecSespie       break;
318f7cc78ecSespie     case 0xD0: /* displacement word deferred:	*displ(Rn) */
319f7cc78ecSespie       (*info->fprintf_func) (info->stream, "*");
320f7cc78ecSespie     case 0xC0: /* displacement word:		displ(Rn) */
321f7cc78ecSespie       if (reg == 0xF)
322f7cc78ecSespie 	(*info->print_address_func) (addr + 3 + NEXTWORD (p), info);
323f7cc78ecSespie       else
324f7cc78ecSespie 	(*info->fprintf_func) (info->stream, "0x%x(%s)", NEXTWORD (p),
325f7cc78ecSespie 			       reg_names[reg]);
326f7cc78ecSespie       break;
327f7cc78ecSespie     case 0xF0: /* displacement long deferred:	*displ(Rn) */
328f7cc78ecSespie       (*info->fprintf_func) (info->stream, "*");
329f7cc78ecSespie     case 0xE0: /* displacement long:		displ(Rn) */
330f7cc78ecSespie       if (reg == 0xF)
331f7cc78ecSespie 	(*info->print_address_func) (addr + 5 + NEXTLONG (p), info);
332f7cc78ecSespie       else
333f7cc78ecSespie 	(*info->fprintf_func) (info->stream, "0x%x(%s)", NEXTLONG (p),
334f7cc78ecSespie 			       reg_names[reg]);
335f7cc78ecSespie       break;
336f7cc78ecSespie     }
337f7cc78ecSespie 
338f7cc78ecSespie   return p - p0;
339f7cc78ecSespie }
340