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