175fd0b74Schristos /* Print VAX instructions.
2*e992f068Schristos Copyright (C) 1995-2022 Free Software Foundation, Inc.
375fd0b74Schristos Contributed by Pauline Middelink <middelin@polyware.iaf.nl>
475fd0b74Schristos
575fd0b74Schristos This file is part of the GNU opcodes library.
675fd0b74Schristos
775fd0b74Schristos This library is free software; you can redistribute it and/or modify
875fd0b74Schristos it under the terms of the GNU General Public License as published by
975fd0b74Schristos the Free Software Foundation; either version 3, or (at your option)
1075fd0b74Schristos any later version.
1175fd0b74Schristos
1275fd0b74Schristos It is distributed in the hope that it will be useful, but WITHOUT
1375fd0b74Schristos ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
1475fd0b74Schristos or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
1575fd0b74Schristos License for more details.
1675fd0b74Schristos
1775fd0b74Schristos You should have received a copy of the GNU General Public License
1875fd0b74Schristos along with this program; if not, write to the Free Software
1975fd0b74Schristos Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
2075fd0b74Schristos MA 02110-1301, USA. */
2175fd0b74Schristos
2275fd0b74Schristos #include "sysdep.h"
2375fd0b74Schristos #include <setjmp.h>
2475fd0b74Schristos #include <string.h>
2575fd0b74Schristos #include "opcode/vax.h"
26ede78133Schristos #include "disassemble.h"
2775fd0b74Schristos
2875fd0b74Schristos static char *reg_names[] =
2975fd0b74Schristos {
3075fd0b74Schristos "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7",
3175fd0b74Schristos "r8", "r9", "r10", "r11", "ap", "fp", "sp", "pc"
3275fd0b74Schristos };
3375fd0b74Schristos
3475fd0b74Schristos /* Definitions for the function entry mask bits. */
3575fd0b74Schristos static char *entry_mask_bit[] =
3675fd0b74Schristos {
3775fd0b74Schristos /* Registers 0 and 1 shall not be saved, since they're used to pass back
3875fd0b74Schristos a function's result to its caller... */
3975fd0b74Schristos "~r0~", "~r1~",
4075fd0b74Schristos /* Registers 2 .. 11 are normal registers. */
4175fd0b74Schristos "r2", "r3", "r4", "r5", "r6", "r7", "r8", "r9", "r10", "r11",
4275fd0b74Schristos /* Registers 12 and 13 are argument and frame pointer and must not
4375fd0b74Schristos be saved by using the entry mask. */
4475fd0b74Schristos "~ap~", "~fp~",
4575fd0b74Schristos /* Bits 14 and 15 control integer and decimal overflow. */
4675fd0b74Schristos "IntOvfl", "DecOvfl",
4775fd0b74Schristos };
4875fd0b74Schristos
4975fd0b74Schristos /* Sign-extend an (unsigned char). */
5075fd0b74Schristos #define COERCE_SIGNED_CHAR(ch) ((signed char)(ch))
5175fd0b74Schristos
5275fd0b74Schristos /* Get a 1 byte signed integer. */
5375fd0b74Schristos #define NEXTBYTE(p) \
5475fd0b74Schristos (p += 1, FETCH_DATA (info, p), \
5575fd0b74Schristos COERCE_SIGNED_CHAR(p[-1]))
5675fd0b74Schristos
5775fd0b74Schristos /* Get a 2 byte signed integer. */
5875fd0b74Schristos #define COERCE16(x) ((int) (((x) ^ 0x8000) - 0x8000))
5975fd0b74Schristos #define NEXTWORD(p) \
6075fd0b74Schristos (p += 2, FETCH_DATA (info, p), \
6175fd0b74Schristos COERCE16 ((p[-1] << 8) + p[-2]))
6275fd0b74Schristos
6375fd0b74Schristos /* Get a 4 byte signed integer. */
6475fd0b74Schristos #define COERCE32(x) ((int) (((x) ^ 0x80000000) - 0x80000000))
6575fd0b74Schristos #define NEXTLONG(p) \
6675fd0b74Schristos (p += 4, FETCH_DATA (info, p), \
67012573ebSchristos (COERCE32 (((((((unsigned) p[-1] << 8) + p[-2]) << 8) + p[-3]) << 8) + p[-4])))
6875fd0b74Schristos
6975fd0b74Schristos /* Maximum length of an instruction. */
7075fd0b74Schristos #define MAXLEN 25
7175fd0b74Schristos
7275fd0b74Schristos struct private
7375fd0b74Schristos {
7475fd0b74Schristos /* Points to first byte not fetched. */
7575fd0b74Schristos bfd_byte * max_fetched;
7675fd0b74Schristos bfd_byte the_buffer[MAXLEN];
7775fd0b74Schristos bfd_vma insn_start;
7875fd0b74Schristos OPCODES_SIGJMP_BUF bailout;
7975fd0b74Schristos };
8075fd0b74Schristos
8175fd0b74Schristos /* Make sure that bytes from INFO->PRIVATE_DATA->BUFFER (inclusive)
8275fd0b74Schristos to ADDR (exclusive) are valid. Returns 1 for success, longjmps
8375fd0b74Schristos on error. */
8475fd0b74Schristos #define FETCH_DATA(info, addr) \
8575fd0b74Schristos ((addr) <= ((struct private *)(info->private_data))->max_fetched \
8675fd0b74Schristos ? 1 : fetch_data ((info), (addr)))
8775fd0b74Schristos
8875fd0b74Schristos static int
fetch_data(struct disassemble_info * info,bfd_byte * addr)8975fd0b74Schristos fetch_data (struct disassemble_info *info, bfd_byte *addr)
9075fd0b74Schristos {
9175fd0b74Schristos int status;
9275fd0b74Schristos struct private *priv = (struct private *) info->private_data;
9375fd0b74Schristos bfd_vma start = priv->insn_start + (priv->max_fetched - priv->the_buffer);
9475fd0b74Schristos
9575fd0b74Schristos status = (*info->read_memory_func) (start,
9675fd0b74Schristos priv->max_fetched,
9775fd0b74Schristos addr - priv->max_fetched,
9875fd0b74Schristos info);
9975fd0b74Schristos if (status != 0)
10075fd0b74Schristos {
10175fd0b74Schristos (*info->memory_error_func) (status, start, info);
10275fd0b74Schristos OPCODES_SIGLONGJMP (priv->bailout, 1);
10375fd0b74Schristos }
10475fd0b74Schristos else
10575fd0b74Schristos priv->max_fetched = addr;
10675fd0b74Schristos
10775fd0b74Schristos return 1;
10875fd0b74Schristos }
10975fd0b74Schristos
11075fd0b74Schristos /* Entry mask handling. */
11175fd0b74Schristos static unsigned int entry_addr_occupied_slots = 0;
11275fd0b74Schristos static unsigned int entry_addr_total_slots = 0;
11375fd0b74Schristos static bfd_vma * entry_addr = NULL;
11475fd0b74Schristos
11575fd0b74Schristos /* Parse the VAX specific disassembler options. These contain function
11675fd0b74Schristos entry addresses, which can be useful to disassemble ROM images, since
11775fd0b74Schristos there's no symbol table. Returns TRUE upon success, FALSE otherwise. */
11875fd0b74Schristos
119*e992f068Schristos static bool
parse_disassembler_options(const char * options)120ede78133Schristos parse_disassembler_options (const char *options)
12175fd0b74Schristos {
12275fd0b74Schristos const char * entry_switch = "entry:";
12375fd0b74Schristos
12475fd0b74Schristos while ((options = strstr (options, entry_switch)))
12575fd0b74Schristos {
12675fd0b74Schristos options += strlen (entry_switch);
12775fd0b74Schristos
12875fd0b74Schristos /* The greater-than part of the test below is paranoia. */
12975fd0b74Schristos if (entry_addr_occupied_slots >= entry_addr_total_slots)
13075fd0b74Schristos {
13175fd0b74Schristos /* A guesstimate of the number of entries we will have to create. */
132*e992f068Schristos entry_addr_total_slots
133*e992f068Schristos += 1 + strlen (options) / (strlen (entry_switch) + 5);
13475fd0b74Schristos
13575fd0b74Schristos entry_addr = realloc (entry_addr, sizeof (bfd_vma)
13675fd0b74Schristos * entry_addr_total_slots);
13775fd0b74Schristos }
13875fd0b74Schristos
13975fd0b74Schristos if (entry_addr == NULL)
140*e992f068Schristos return false;
14175fd0b74Schristos
14275fd0b74Schristos entry_addr[entry_addr_occupied_slots] = bfd_scan_vma (options, NULL, 0);
14375fd0b74Schristos entry_addr_occupied_slots ++;
14475fd0b74Schristos }
14575fd0b74Schristos
146*e992f068Schristos return true;
14775fd0b74Schristos }
14875fd0b74Schristos
14975fd0b74Schristos #if 0 /* FIXME: Ideally the disassembler should have target specific
15075fd0b74Schristos initialisation and termination function pointers. Then
15175fd0b74Schristos parse_disassembler_options could be the init function and
15275fd0b74Schristos free_entry_array (below) could be the termination routine.
15375fd0b74Schristos Until then there is no way for the disassembler to tell us
15475fd0b74Schristos that it has finished and that we no longer need the entry
15575fd0b74Schristos array, so this routine is suppressed for now. It does mean
15675fd0b74Schristos that we leak memory, but only to the extent that we do not
15775fd0b74Schristos free it just before the disassembler is about to terminate
15875fd0b74Schristos anyway. */
15975fd0b74Schristos
16075fd0b74Schristos /* Free memory allocated to our entry array. */
16175fd0b74Schristos
16275fd0b74Schristos static void
16375fd0b74Schristos free_entry_array (void)
16475fd0b74Schristos {
16575fd0b74Schristos if (entry_addr)
16675fd0b74Schristos {
16775fd0b74Schristos free (entry_addr);
16875fd0b74Schristos entry_addr = NULL;
16975fd0b74Schristos entry_addr_occupied_slots = entry_addr_total_slots = 0;
17075fd0b74Schristos }
17175fd0b74Schristos }
17275fd0b74Schristos #endif
17375fd0b74Schristos /* Check if the given address is a known function entry point. This is
17475fd0b74Schristos the case if there is a symbol of the function type at this address.
17575fd0b74Schristos We also check for synthetic symbols as these are used for PLT entries
17675fd0b74Schristos (weak undefined symbols may not have the function type set). Finally
17775fd0b74Schristos the address may have been forced to be treated as an entry point. The
17875fd0b74Schristos latter helps in disassembling ROM images, because there's no symbol
17975fd0b74Schristos table at all. Forced entry points can be given by supplying several
18075fd0b74Schristos -M options to objdump: -M entry:0xffbb7730. */
18175fd0b74Schristos
182*e992f068Schristos static bool
is_function_entry(struct disassemble_info * info,bfd_vma addr)18375fd0b74Schristos is_function_entry (struct disassemble_info *info, bfd_vma addr)
18475fd0b74Schristos {
18575fd0b74Schristos unsigned int i;
18675fd0b74Schristos
18775fd0b74Schristos /* Check if there's a function or PLT symbol at our address. */
18875fd0b74Schristos if (info->symbols
18975fd0b74Schristos && info->symbols[0]
19075fd0b74Schristos && (info->symbols[0]->flags & (BSF_FUNCTION | BSF_SYNTHETIC))
19175fd0b74Schristos && addr == bfd_asymbol_value (info->symbols[0]))
192*e992f068Schristos return true;
19375fd0b74Schristos
19475fd0b74Schristos /* Check for forced function entry address. */
19575fd0b74Schristos for (i = entry_addr_occupied_slots; i--;)
19675fd0b74Schristos if (entry_addr[i] == addr)
197*e992f068Schristos return true;
19875fd0b74Schristos
199*e992f068Schristos return false;
20075fd0b74Schristos }
20175fd0b74Schristos
20275fd0b74Schristos /* Check if the given address is the last longword of a PLT entry.
20375fd0b74Schristos This longword is data and depending on the value it may interfere
20475fd0b74Schristos with disassembly of further PLT entries. We make use of the fact
20575fd0b74Schristos PLT symbols are marked BSF_SYNTHETIC. */
206*e992f068Schristos static bool
is_plt_tail(struct disassemble_info * info,bfd_vma addr)20775fd0b74Schristos is_plt_tail (struct disassemble_info *info, bfd_vma addr)
20875fd0b74Schristos {
20975fd0b74Schristos if (info->symbols
21075fd0b74Schristos && info->symbols[0]
21175fd0b74Schristos && (info->symbols[0]->flags & BSF_SYNTHETIC)
21275fd0b74Schristos && addr == bfd_asymbol_value (info->symbols[0]) + 8)
213*e992f068Schristos return true;
21475fd0b74Schristos
215*e992f068Schristos return false;
21675fd0b74Schristos }
21775fd0b74Schristos
21875fd0b74Schristos static int
print_insn_mode(const char * d,int size,unsigned char * p0,bfd_vma addr,disassemble_info * info)21975fd0b74Schristos print_insn_mode (const char *d,
22075fd0b74Schristos int size,
22175fd0b74Schristos unsigned char *p0,
22275fd0b74Schristos bfd_vma addr, /* PC for this arg to be relative to. */
22375fd0b74Schristos disassemble_info *info)
22475fd0b74Schristos {
22575fd0b74Schristos unsigned char *p = p0;
22675fd0b74Schristos unsigned char mode, reg;
22775fd0b74Schristos
22875fd0b74Schristos /* Fetch and interpret mode byte. */
22975fd0b74Schristos mode = (unsigned char) NEXTBYTE (p);
23075fd0b74Schristos reg = mode & 0xF;
23175fd0b74Schristos switch (mode & 0xF0)
23275fd0b74Schristos {
23375fd0b74Schristos case 0x00:
23475fd0b74Schristos case 0x10:
23575fd0b74Schristos case 0x20:
23675fd0b74Schristos case 0x30: /* Literal mode $number. */
23775fd0b74Schristos if (d[1] == 'd' || d[1] == 'f' || d[1] == 'g' || d[1] == 'h')
23875fd0b74Schristos (*info->fprintf_func) (info->stream, "$0x%x [%c-float]", mode, d[1]);
23975fd0b74Schristos else
24075fd0b74Schristos (*info->fprintf_func) (info->stream, "$0x%x", mode);
24175fd0b74Schristos break;
24275fd0b74Schristos case 0x40: /* Index: base-addr[Rn] */
243012573ebSchristos {
244012573ebSchristos unsigned char *q = p0 + 1;
245012573ebSchristos unsigned char nextmode = NEXTBYTE (q);
246012573ebSchristos if (nextmode < 0x60 || nextmode == 0x8f)
247012573ebSchristos /* Literal, index, register, or immediate is invalid. In
248012573ebSchristos particular don't recurse into another index mode which
249012573ebSchristos might overflow the_buffer. */
250012573ebSchristos (*info->fprintf_func) (info->stream, "[invalid base]");
251012573ebSchristos else
25275fd0b74Schristos p += print_insn_mode (d, size, p0 + 1, addr + 1, info);
25375fd0b74Schristos (*info->fprintf_func) (info->stream, "[%s]", reg_names[reg]);
254012573ebSchristos }
25575fd0b74Schristos break;
25675fd0b74Schristos case 0x50: /* Register: Rn */
25775fd0b74Schristos (*info->fprintf_func) (info->stream, "%s", reg_names[reg]);
25875fd0b74Schristos break;
25975fd0b74Schristos case 0x60: /* Register deferred: (Rn) */
26075fd0b74Schristos (*info->fprintf_func) (info->stream, "(%s)", reg_names[reg]);
26175fd0b74Schristos break;
26275fd0b74Schristos case 0x70: /* Autodecrement: -(Rn) */
26375fd0b74Schristos (*info->fprintf_func) (info->stream, "-(%s)", reg_names[reg]);
26475fd0b74Schristos break;
26575fd0b74Schristos case 0x80: /* Autoincrement: (Rn)+ */
26675fd0b74Schristos if (reg == 0xF)
26775fd0b74Schristos { /* Immediate? */
26875fd0b74Schristos int i;
26975fd0b74Schristos
27075fd0b74Schristos FETCH_DATA (info, p + size);
27175fd0b74Schristos (*info->fprintf_func) (info->stream, "$0x");
27275fd0b74Schristos if (d[1] == 'd' || d[1] == 'f' || d[1] == 'g' || d[1] == 'h')
27375fd0b74Schristos {
27475fd0b74Schristos int float_word;
27575fd0b74Schristos
27675fd0b74Schristos float_word = p[0] | (p[1] << 8);
27775fd0b74Schristos if ((d[1] == 'd' || d[1] == 'f')
27875fd0b74Schristos && (float_word & 0xff80) == 0x8000)
27975fd0b74Schristos {
28075fd0b74Schristos (*info->fprintf_func) (info->stream, "[invalid %c-float]",
28175fd0b74Schristos d[1]);
28275fd0b74Schristos }
28375fd0b74Schristos else
28475fd0b74Schristos {
28575fd0b74Schristos for (i = 0; i < size; i++)
28675fd0b74Schristos (*info->fprintf_func) (info->stream, "%02x",
28775fd0b74Schristos p[size - i - 1]);
28875fd0b74Schristos (*info->fprintf_func) (info->stream, " [%c-float]", d[1]);
28975fd0b74Schristos }
29075fd0b74Schristos }
29175fd0b74Schristos else
29275fd0b74Schristos {
29375fd0b74Schristos for (i = 0; i < size; i++)
29475fd0b74Schristos (*info->fprintf_func) (info->stream, "%02x", p[size - i - 1]);
29575fd0b74Schristos }
29675fd0b74Schristos p += size;
29775fd0b74Schristos }
29875fd0b74Schristos else
29975fd0b74Schristos (*info->fprintf_func) (info->stream, "(%s)+", reg_names[reg]);
30075fd0b74Schristos break;
30175fd0b74Schristos case 0x90: /* Autoincrement deferred: @(Rn)+ */
30275fd0b74Schristos if (reg == 0xF)
30375fd0b74Schristos (*info->fprintf_func) (info->stream, "*0x%x", NEXTLONG (p));
30475fd0b74Schristos else
30575fd0b74Schristos (*info->fprintf_func) (info->stream, "@(%s)+", reg_names[reg]);
30675fd0b74Schristos break;
30775fd0b74Schristos case 0xB0: /* Displacement byte deferred: *displ(Rn). */
30875fd0b74Schristos (*info->fprintf_func) (info->stream, "*");
309ede78133Schristos /* Fall through. */
31075fd0b74Schristos case 0xA0: /* Displacement byte: displ(Rn). */
31175fd0b74Schristos if (reg == 0xF)
31275fd0b74Schristos (*info->print_address_func) (addr + 2 + NEXTBYTE (p), info);
31375fd0b74Schristos else
31475fd0b74Schristos (*info->fprintf_func) (info->stream, "0x%x(%s)", NEXTBYTE (p),
31575fd0b74Schristos reg_names[reg]);
31675fd0b74Schristos break;
31775fd0b74Schristos case 0xD0: /* Displacement word deferred: *displ(Rn). */
31875fd0b74Schristos (*info->fprintf_func) (info->stream, "*");
319ede78133Schristos /* Fall through. */
32075fd0b74Schristos case 0xC0: /* Displacement word: displ(Rn). */
32175fd0b74Schristos if (reg == 0xF)
32275fd0b74Schristos (*info->print_address_func) (addr + 3 + NEXTWORD (p), info);
32375fd0b74Schristos else
32475fd0b74Schristos (*info->fprintf_func) (info->stream, "0x%x(%s)", NEXTWORD (p),
32575fd0b74Schristos reg_names[reg]);
32675fd0b74Schristos break;
32775fd0b74Schristos case 0xF0: /* Displacement long deferred: *displ(Rn). */
32875fd0b74Schristos (*info->fprintf_func) (info->stream, "*");
329ede78133Schristos /* Fall through. */
33075fd0b74Schristos case 0xE0: /* Displacement long: displ(Rn). */
33175fd0b74Schristos if (reg == 0xF)
33275fd0b74Schristos (*info->print_address_func) (addr + 5 + NEXTLONG (p), info);
33375fd0b74Schristos else
33475fd0b74Schristos (*info->fprintf_func) (info->stream, "0x%x(%s)", NEXTLONG (p),
33575fd0b74Schristos reg_names[reg]);
33675fd0b74Schristos break;
33775fd0b74Schristos }
33875fd0b74Schristos
33975fd0b74Schristos return p - p0;
34075fd0b74Schristos }
34175fd0b74Schristos
34275fd0b74Schristos /* Returns number of bytes "eaten" by the operand, or return -1 if an
34375fd0b74Schristos invalid operand was found, or -2 if an opcode tabel error was
34475fd0b74Schristos found. */
34575fd0b74Schristos
34675fd0b74Schristos static int
print_insn_arg(const char * d,unsigned char * p0,bfd_vma addr,disassemble_info * info)34775fd0b74Schristos print_insn_arg (const char *d,
34875fd0b74Schristos unsigned char *p0,
34975fd0b74Schristos bfd_vma addr, /* PC for this arg to be relative to. */
35075fd0b74Schristos disassemble_info *info)
35175fd0b74Schristos {
35275fd0b74Schristos int arg_len;
35375fd0b74Schristos
35475fd0b74Schristos /* Check validity of addressing length. */
35575fd0b74Schristos switch (d[1])
35675fd0b74Schristos {
35775fd0b74Schristos case 'b' : arg_len = 1; break;
35875fd0b74Schristos case 'd' : arg_len = 8; break;
35975fd0b74Schristos case 'f' : arg_len = 4; break;
36075fd0b74Schristos case 'g' : arg_len = 8; break;
36175fd0b74Schristos case 'h' : arg_len = 16; break;
36275fd0b74Schristos case 'l' : arg_len = 4; break;
36375fd0b74Schristos case 'o' : arg_len = 16; break;
36475fd0b74Schristos case 'w' : arg_len = 2; break;
36575fd0b74Schristos case 'q' : arg_len = 8; break;
36675fd0b74Schristos default : abort ();
36775fd0b74Schristos }
36875fd0b74Schristos
36975fd0b74Schristos /* Branches have no mode byte. */
37075fd0b74Schristos if (d[0] == 'b')
37175fd0b74Schristos {
37275fd0b74Schristos unsigned char *p = p0;
37375fd0b74Schristos
37475fd0b74Schristos if (arg_len == 1)
37575fd0b74Schristos (*info->print_address_func) (addr + 1 + NEXTBYTE (p), info);
37675fd0b74Schristos else
37775fd0b74Schristos (*info->print_address_func) (addr + 2 + NEXTWORD (p), info);
37875fd0b74Schristos
37975fd0b74Schristos return p - p0;
38075fd0b74Schristos }
38175fd0b74Schristos
38275fd0b74Schristos return print_insn_mode (d, arg_len, p0, addr, info);
38375fd0b74Schristos }
38475fd0b74Schristos
38575fd0b74Schristos /* Print the vax instruction at address MEMADDR in debugged memory,
38675fd0b74Schristos on INFO->STREAM. Returns length of the instruction, in bytes. */
38775fd0b74Schristos
38875fd0b74Schristos int
print_insn_vax(bfd_vma memaddr,disassemble_info * info)38975fd0b74Schristos print_insn_vax (bfd_vma memaddr, disassemble_info *info)
39075fd0b74Schristos {
391*e992f068Schristos static bool parsed_disassembler_options = false;
39275fd0b74Schristos const struct vot *votp;
39375fd0b74Schristos const char *argp;
39475fd0b74Schristos unsigned char *arg;
39575fd0b74Schristos struct private priv;
39675fd0b74Schristos bfd_byte *buffer = priv.the_buffer;
39775fd0b74Schristos
39875fd0b74Schristos info->private_data = & priv;
39975fd0b74Schristos priv.max_fetched = priv.the_buffer;
40075fd0b74Schristos priv.insn_start = memaddr;
40175fd0b74Schristos
40275fd0b74Schristos if (! parsed_disassembler_options
40375fd0b74Schristos && info->disassembler_options != NULL)
40475fd0b74Schristos {
40575fd0b74Schristos parse_disassembler_options (info->disassembler_options);
40675fd0b74Schristos
40775fd0b74Schristos /* To avoid repeated parsing of these options. */
408*e992f068Schristos parsed_disassembler_options = true;
40975fd0b74Schristos }
41075fd0b74Schristos
41175fd0b74Schristos if (OPCODES_SIGSETJMP (priv.bailout) != 0)
41275fd0b74Schristos /* Error return. */
41375fd0b74Schristos return -1;
41475fd0b74Schristos
41575fd0b74Schristos argp = NULL;
41675fd0b74Schristos /* Check if the info buffer has more than one byte left since
41775fd0b74Schristos the last opcode might be a single byte with no argument data. */
41875fd0b74Schristos if (info->buffer_length - (memaddr - info->buffer_vma) > 1
41975fd0b74Schristos && (info->stop_vma == 0 || memaddr < (info->stop_vma - 1)))
42075fd0b74Schristos {
42175fd0b74Schristos FETCH_DATA (info, buffer + 2);
42275fd0b74Schristos }
42375fd0b74Schristos else
42475fd0b74Schristos {
42575fd0b74Schristos FETCH_DATA (info, buffer + 1);
42675fd0b74Schristos buffer[1] = 0;
42775fd0b74Schristos }
42875fd0b74Schristos
42975fd0b74Schristos /* Decode function entry mask. */
43075fd0b74Schristos if (is_function_entry (info, memaddr))
43175fd0b74Schristos {
43275fd0b74Schristos int i = 0;
43375fd0b74Schristos int register_mask = buffer[1] << 8 | buffer[0];
43475fd0b74Schristos
43575fd0b74Schristos (*info->fprintf_func) (info->stream, ".word 0x%04x # Entry mask: <",
43675fd0b74Schristos register_mask);
43775fd0b74Schristos
43875fd0b74Schristos for (i = 15; i >= 0; i--)
43975fd0b74Schristos if (register_mask & (1 << i))
44075fd0b74Schristos (*info->fprintf_func) (info->stream, " %s", entry_mask_bit[i]);
44175fd0b74Schristos
44275fd0b74Schristos (*info->fprintf_func) (info->stream, " >");
44375fd0b74Schristos
44475fd0b74Schristos return 2;
44575fd0b74Schristos }
44675fd0b74Schristos
44775fd0b74Schristos /* Decode PLT entry offset longword. */
44875fd0b74Schristos if (is_plt_tail (info, memaddr))
44975fd0b74Schristos {
45075fd0b74Schristos int offset;
45175fd0b74Schristos
45275fd0b74Schristos FETCH_DATA (info, buffer + 4);
453012573ebSchristos offset = ((unsigned) buffer[3] << 24 | buffer[2] << 16
454012573ebSchristos | buffer[1] << 8 | buffer[0]);
45575fd0b74Schristos (*info->fprintf_func) (info->stream, ".long 0x%08x", offset);
45675fd0b74Schristos
45775fd0b74Schristos return 4;
45875fd0b74Schristos }
45975fd0b74Schristos
46075fd0b74Schristos for (votp = &votstrs[0]; votp->name[0]; votp++)
46175fd0b74Schristos {
46275fd0b74Schristos vax_opcodeT opcode = votp->detail.code;
46375fd0b74Schristos
46475fd0b74Schristos /* 2 byte codes match 2 buffer pos. */
46575fd0b74Schristos if ((bfd_byte) opcode == buffer[0]
46675fd0b74Schristos && (opcode >> 8 == 0 || opcode >> 8 == buffer[1]))
46775fd0b74Schristos {
46875fd0b74Schristos argp = votp->detail.args;
46975fd0b74Schristos break;
47075fd0b74Schristos }
47175fd0b74Schristos }
47275fd0b74Schristos if (argp == NULL)
47375fd0b74Schristos {
47475fd0b74Schristos /* Handle undefined instructions. */
47575fd0b74Schristos (*info->fprintf_func) (info->stream, ".word 0x%x",
47675fd0b74Schristos (buffer[0] << 8) + buffer[1]);
47775fd0b74Schristos return 2;
47875fd0b74Schristos }
47975fd0b74Schristos
48075fd0b74Schristos /* Point at first byte of argument data, and at descriptor for first
48175fd0b74Schristos argument. */
48275fd0b74Schristos arg = buffer + ((votp->detail.code >> 8) ? 2 : 1);
48375fd0b74Schristos
48475fd0b74Schristos /* Make sure we have it in mem */
48575fd0b74Schristos FETCH_DATA (info, arg);
48675fd0b74Schristos
48775fd0b74Schristos (*info->fprintf_func) (info->stream, "%s", votp->name);
48875fd0b74Schristos if (*argp)
48975fd0b74Schristos (*info->fprintf_func) (info->stream, " ");
49075fd0b74Schristos
49175fd0b74Schristos while (*argp)
49275fd0b74Schristos {
493*e992f068Schristos arg += print_insn_arg (argp, arg, memaddr + (arg - buffer), info);
49475fd0b74Schristos argp += 2;
49575fd0b74Schristos if (*argp)
49675fd0b74Schristos (*info->fprintf_func) (info->stream, ",");
49775fd0b74Schristos }
49875fd0b74Schristos
49975fd0b74Schristos return arg - buffer;
50075fd0b74Schristos }
50175fd0b74Schristos
502