Rizin
unix-like reverse engineering framework and cli tools
vax-dis.c
Go to the documentation of this file.
1 // SPDX-FileCopyrightText: 1995, 1998, 2000, 2001, 2002, 2005, 2007, 2009, 2012 Free Software Foundation, Inc.
2 // SPDX-License-Identifier: GPL-3.0-or-later
3 
4 /* Print VAX instructions.
5  Copyright 1995, 1998, 2000, 2001, 2002, 2005, 2007, 2009, 2012
6  Free Software Foundation, Inc.
7  Contributed by Pauline Middelink <middelin@polyware.iaf.nl>
8 
9  This file is part of the GNU opcodes library.
10 
11  This library is free software; you can redistribute it and/or modify
12  it under the terms of the GNU General Public License as published by
13  the Free Software Foundation; either version 3, or (at your option)
14  any later version.
15 
16  It is distributed in the hope that it will be useful, but WITHOUT
17  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
18  or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
19  License for more details.
20 
21  You should have received a copy of the GNU General Public License
22  along with this program; if not, write to the Free Software
23  Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
24  MA 02110-1301, USA. */
25 
26 #include "sysdep.h"
27 #include <setjmp.h>
28 #include <string.h>
29 #include <stdio.h>
30 #include <stdlib.h>
31 #include "vax.h"
32 #include "disas-asm.h"
33 
34 static char *reg_names[] = {
35  "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7",
36  "r8", "r9", "r10", "r11", "ap", "fp", "sp", "pc"
37 };
38 
39 #if 0
40 /* Definitions for the function entry mask bits. */
41 static char *entry_mask_bit[] =
42 {
43  /* Registers 0 and 1 shall not be saved, since they're used to pass back
44  a function's result to its caller... */
45  "~r0~", "~r1~",
46  /* Registers 2 .. 11 are normal registers. */
47  "r2", "r3", "r4", "r5", "r6", "r7", "r8", "r9", "r10", "r11",
48  /* Registers 12 and 13 are argument and frame pointer and must not
49  be saved by using the entry mask. */
50  "~ap~", "~fp~",
51  /* Bits 14 and 15 control integer and decimal overflow. */
52  "IntOvfl", "DecOvfl",
53 };
54 
55 #endif
56 /* Sign-extend an (unsigned char). */
57 #define COERCE_SIGNED_CHAR(ch) ((signed char)(ch))
58 
59 /* Get a 1 byte signed integer. */
60 #define NEXTBYTE(p) \
61  ((p) += 1, FETCH_DATA(info, p), \
62  COERCE_SIGNED_CHAR((p)[-1]))
63 
64 /* Get a 2 byte signed integer. */
65 #define COERCE16(x) ((int)(((x) ^ 0x8000) - 0x8000))
66 #define NEXTWORD(p) \
67  ((p) += 2, FETCH_DATA(info, p), \
68  COERCE16(((p)[-1] << 8) + (p)[-2]))
69 
70 /* Get a 4 byte signed integer. */
71 #define COERCE32(x) ((int)(((x) ^ 0x80000000) - 0x80000000))
72 #define NEXTLONG(p) \
73  ((p) += 4, FETCH_DATA(info, p), \
74  (COERCE32(((((((p)[-1] << 8) + (p)[-2]) << 8) + (p)[-3]) << 8) + (p)[-4])))
75 
76 /* Maximum length of an instruction. */
77 #define MAXLEN 25
78 
79 struct private {
80  /* Points to first byte not fetched. */
84  jmp_buf bailout;
85 };
86 
87 /* Make sure that bytes from INFO->PRIVATE_DATA->BUFFER (inclusive)
88  to ADDR (exclusive) are valid. Returns 1 for success, longjmps
89  on error. */
90 #define FETCH_DATA(info, addr) \
91  ((addr) <= ((struct private *)((info)->private_data))->max_fetched \
92  ? 1 \
93  : fetch_data((info), (addr)))
94 
95 static int
97  int status;
98  struct private *priv = (struct private *)info->private_data;
99  bfd_vma start = priv->insn_start + (priv->max_fetched - priv->the_buffer);
100 
101  status = (*info->read_memory_func)(start,
102  priv->max_fetched,
103  addr - priv->max_fetched,
104  info);
105  if (status != 0) {
106  (*info->memory_error_func)(status, start, info);
107  longjmp(priv->bailout, 1);
108  } else {
109  priv->max_fetched = addr;
110  }
111 
112  return 1;
113 }
114 
115 /* Entry mask handling. */
116 #if 0
117 static unsigned int entry_addr_occupied_slots = 0;
118 static unsigned int entry_addr_total_slots = 0;
119 static bfd_vma * entry_addr = NULL;
120 #endif
121 
122 /* Parse the VAX specific disassembler options. These contain function
123  entry addresses, which can be useful to disassemble ROM images, since
124  there's no symbol table. Returns TRUE upon success, FALSE otherwise. */
125 
126 /* Check if the given address is a known function entry point. This is
127  the case if there is a symbol of the function type at this address.
128  We also check for synthetic symbols as these are used for PLT entries
129  (weak undefined symbols may not have the function type set). Finally
130  the address may have been forced to be treated as an entry point. The
131  latter helps in disassembling ROM images, because there's no symbol
132  table at all. Forced entry points can be given by supplying several
133  -M options to objdump: -M entry:0xffbb7730. */
134 
135 static int
136 print_insn_mode(const char *d,
137  int size,
138  unsigned char *p0,
139  bfd_vma addr, /* PC for this arg to be relative to. */
141  unsigned char *p = p0;
142  unsigned char mode, reg;
143 
144  /* Fetch and interpret mode byte. */
145  mode = (unsigned char)NEXTBYTE(p);
146  reg = mode & 0xF;
147  switch (mode & 0xF0) {
148  case 0x00:
149  case 0x10:
150  case 0x20:
151  case 0x30: /* Literal mode $number. */
152  if (d[1] == 'd' || d[1] == 'f' || d[1] == 'g' || d[1] == 'h') {
153  (*info->fprintf_func)(info->stream, "$0x%x [%c-float]", mode, d[1]);
154  } else {
155  (*info->fprintf_func)(info->stream, "$0x%x", mode);
156  }
157  break;
158  case 0x40: /* Index: base-addr[Rn] */
159  p += print_insn_mode(d, size, p0 + 1, addr + 1, info);
160  (*info->fprintf_func)(info->stream, "[%s]", reg_names[reg]);
161  break;
162  case 0x50: /* Register: Rn */
163  (*info->fprintf_func)(info->stream, "%s", reg_names[reg]);
164  break;
165  case 0x60: /* Register deferred: (Rn) */
166  (*info->fprintf_func)(info->stream, "(%s)", reg_names[reg]);
167  break;
168  case 0x70: /* Autodecrement: -(Rn) */
169  (*info->fprintf_func)(info->stream, "-(%s)", reg_names[reg]);
170  break;
171  case 0x80: /* Autoincrement: (Rn)+ */
172  if (reg == 0xF) { /* Immediate? */
173  int i;
174 
175  FETCH_DATA(info, p + size);
176  (*info->fprintf_func)(info->stream, "$0x");
177  if (d[1] == 'd' || d[1] == 'f' || d[1] == 'g' || d[1] == 'h') {
178  int float_word;
179 
180  float_word = p[0] | (p[1] << 8);
181  if ((d[1] == 'd' || d[1] == 'f') && (float_word & 0xff80) == 0x8000) {
182  (*info->fprintf_func)(info->stream, "[invalid %c-float]",
183  d[1]);
184  } else {
185  for (i = 0; i < size; i++) {
186  (*info->fprintf_func)(info->stream, "%02x",
187  p[size - i - 1]);
188  }
189  (*info->fprintf_func)(info->stream, " [%c-float]", d[1]);
190  }
191  } else {
192  for (i = 0; i < size; i++) {
193  (*info->fprintf_func)(info->stream, "%02x", p[size - i - 1]);
194  }
195  }
196  p += size;
197  } else {
198  (*info->fprintf_func)(info->stream, "(%s)+", reg_names[reg]);
199  }
200  break;
201  case 0x90: /* Autoincrement deferred: @(Rn)+ */
202  if (reg == 0xF) {
203  (*info->fprintf_func)(info->stream, "*0x%x", NEXTLONG(p));
204  } else {
205  (*info->fprintf_func)(info->stream, "@(%s)+", reg_names[reg]);
206  }
207  break;
208  case 0xB0: /* Displacement byte deferred: *displ(Rn). */
209  (*info->fprintf_func)(info->stream, "*");
210  // fallthrough
211  case 0xA0: /* Displacement byte: displ(Rn). */
212  if (reg == 0xF) {
213  (*info->print_address_func)(addr + 2 + NEXTBYTE(p), info);
214  } else {
215  (*info->fprintf_func)(info->stream, "0x%x(%s)", NEXTBYTE(p),
216  reg_names[reg]);
217  }
218  break;
219  case 0xD0: /* Displacement word deferred: *displ(Rn). */
220  (*info->fprintf_func)(info->stream, "*");
221  // fallthrough
222  case 0xC0: /* Displacement word: displ(Rn). */
223  if (reg == 0xF) {
224  (*info->print_address_func)(addr + 3 + NEXTWORD(p), info);
225  } else {
226  (*info->fprintf_func)(info->stream, "0x%x(%s)", NEXTWORD(p),
227  reg_names[reg]);
228  }
229  break;
230  case 0xF0: /* Displacement long deferred: *displ(Rn). */
231  (*info->fprintf_func)(info->stream, "*");
232  // fallthrough
233  case 0xE0: /* Displacement long: displ(Rn). */
234  if (reg == 0xF) {
235  (*info->print_address_func)(addr + 5 + NEXTLONG(p), info);
236  } else {
237  (*info->fprintf_func)(info->stream, "0x%x(%s)", NEXTLONG(p),
238  reg_names[reg]);
239  }
240  break;
241  }
242 
243  return p - p0;
244 }
245 
246 /* Returns number of bytes "eaten" by the operand, or return -1 if an
247  invalid operand was found, or -2 if an opcode tabel error was
248  found. */
249 
250 static int
251 print_insn_arg(const char *d,
252  unsigned char *p0,
253  bfd_vma addr, /* PC for this arg to be relative to. */
255  int arg_len;
256 
257  /* Check validity of addressing length. */
258  switch (d[1]) {
259  case 'b': arg_len = 1; break;
260  case 'd': arg_len = 8; break;
261  case 'f': arg_len = 4; break;
262  case 'g': arg_len = 8; break;
263  case 'h': arg_len = 16; break;
264  case 'l': arg_len = 4; break;
265  case 'o': arg_len = 16; break;
266  case 'w': arg_len = 2; break;
267  case 'q': arg_len = 8; break;
268  default: abort();
269  }
270 
271  /* Branches have no mode byte. */
272  if (d[0] == 'b') {
273  unsigned char *p = p0;
274 
275  if (arg_len == 1) {
276  (*info->print_address_func)(addr + 1 + NEXTBYTE(p), info);
277  } else {
278  (*info->print_address_func)(addr + 2 + NEXTWORD(p), info);
279  }
280 
281  return p - p0;
282  }
283 
284  return print_insn_mode(d, arg_len, p0, addr, info);
285 }
286 
287 /* Print the vax instruction at address MEMADDR in debugged memory,
288  on INFO->STREAM. Returns length of the instruction, in bytes. */
289 
291  // static bfd_boolean parsed_disassembler_options = FALSE;
292  const struct vot *votp;
293  const char *argp;
294  unsigned char *arg;
295  struct private priv;
296  bfd_byte *buffer = priv.the_buffer;
297 
298  info->private_data = &priv;
299  priv.max_fetched = priv.the_buffer;
300  priv.insn_start = memaddr;
301 
302  if (setjmp(priv.bailout) != 0) {
303  /* Error return. */
304  return -1;
305  }
306 
307  argp = NULL;
308  /* Check if the info buffer has more than one byte left since
309  the last opcode might be a single byte with no argument data. */
310  if (info->buffer_length - (memaddr - info->buffer_vma) > 1) {
311  FETCH_DATA(info, buffer + 2);
312  } else {
313  FETCH_DATA(info, buffer + 1);
314  buffer[1] = 0;
315  }
316 
317  for (votp = &votstrs[0]; votp->name[0]; votp++) {
318  vax_opcodeT opcode = votp->detail.code;
319 
320  /* 2 byte codes match 2 buffer pos. */
321  if ((bfd_byte)opcode == buffer[0] && (opcode >> 8 == 0 || opcode >> 8 == buffer[1])) {
322  argp = votp->detail.args;
323  break;
324  }
325  }
326  if (!argp) {
327  /* Handle undefined instructions. */
328  (*info->fprintf_func)(info->stream, ".word 0x%x",
329  (buffer[0] << 8) + buffer[1]);
330  return 2;
331  }
332 
333  /* Point at first byte of argument data, and at descriptor for first
334  argument. */
335  arg = buffer + ((votp->detail.code >> 8) ? 2 : 1);
336 
337  /* Make sure we have it in mem */
338  FETCH_DATA(info, arg);
339 
340  (*info->fprintf_func)(info->stream, "%s", votp->name);
341  if (*argp) {
342  (*info->fprintf_func)(info->stream, " ");
343  }
344 
345  while (*argp) {
346  arg += print_insn_arg(argp, arg, memaddr + arg - buffer, info);
347  argp += 2;
348  if (*argp) {
349  (*info->fprintf_func)(info->stream, ", ");
350  }
351  }
352 
353  return arg - buffer;
354 }
lzma_index ** i
Definition: index.h:629
static const char * arg(RzAnalysis *a, csh *handle, cs_insn *insn, char *buf, int n)
Definition: arm_esil32.c:136
RzBinInfo * info(RzBinFile *bf)
Definition: bin_ne.c:86
struct buffer buffer
#define NULL
Definition: cris-opc.c:27
static static sync static getppid static getegid const char static filename char static len const char char static bufsiz static mask static vfork const void static prot static getpgrp const char static swapflags static arg static fd static protocol static who struct sockaddr static addrlen static backlog struct timeval struct timezone static tz const struct iovec static count static mode const void const struct sockaddr static tolen const char static pathname void static offset struct stat static buf void long static basep static whence static length const void static len static semflg const void static shmflg const struct timespec struct timespec static rem const char static group const void start
Definition: sflib.h:133
static static sync static getppid static getegid const char static filename char argp
Definition: sflib.h:62
voidpf void uLong size
Definition: ioapi.h:138
const char int mode
Definition: ioapi.h:137
#define reg(n)
void * p
Definition: libc.cpp:67
static const char struct stat static buf struct stat static buf static vhangup int status
Definition: sflib.h:145
unsigned char bfd_byte
Definition: mybfd.h:176
BFD_HOST_U_64_BIT bfd_vma
Definition: mybfd.h:111
#define d(i)
Definition: sha256.c:44
Definition: buffer.h:15
bfd_byte the_buffer[MAXLEN]
Definition: vax-dis.c:82
jmp_buf bailout
Definition: vax-dis.c:84
bfd_vma insn_start
Definition: vax-dis.c:83
bfd_byte * max_fetched
Definition: vax-dis.c:81
const char * args
Definition: vax.h:31
vax_opcodeT code
Definition: vax.h:32
Definition: vax.h:36
const char * name
Definition: vax.h:37
struct vot_wot detail
Definition: vax.h:38
static int print_insn_arg(const char *d, unsigned char *p0, bfd_vma addr, disassemble_info *info)
Definition: vax-dis.c:251
int print_insn_vax(bfd_vma memaddr, disassemble_info *info)
Definition: vax-dis.c:290
static int fetch_data(struct disassemble_info *info, bfd_byte *addr)
Definition: vax-dis.c:96
#define NEXTWORD(p)
Definition: vax-dis.c:66
static int print_insn_mode(const char *d, int size, unsigned char *p0, bfd_vma addr, disassemble_info *info)
Definition: vax-dis.c:136
#define FETCH_DATA(info, addr)
Definition: vax-dis.c:90
#define NEXTLONG(p)
Definition: vax-dis.c:72
#define NEXTBYTE(p)
Definition: vax-dis.c:60
static char * reg_names[]
Definition: vax-dis.c:34
#define MAXLEN
Definition: vax-dis.c:77
#define vax_opcodeT
Definition: vax.h:25
static const struct vot votstrs[]
Definition: vax.h:47
static int addr
Definition: z80asm.c:58