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