Rizin
unix-like reverse engineering framework and cli tools
nios2-dis.c
Go to the documentation of this file.
1 /* Altera Nios II disassemble routines
2  Copyright (C) 2012, 2013 Free Software Foundation, Inc.
3  Contributed by Nigel Gray (ngray@altera.com).
4  Contributed by Mentor Graphics, Inc.
5 
6  This file is part of the GNU opcodes library.
7 
8  This library is free software; you can redistribute it and/or modify
9  it under the terms of the GNU General Public License as published by
10  the Free Software Foundation; either version 3, or (at your option)
11  any later version.
12 
13  It is distributed in the hope that it will be useful, but WITHOUT
14  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
15  or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
16  License for more details.
17 
18  You should have received a copy of the GNU General Public License
19  along with this file; see the file COPYING. If not, write to the
20  Free Software Foundation, 51 Franklin Street - Fifth Floor, Boston,
21  MA 02110-1301, USA. */
22 
23 #include "sysdep.h"
24 #include "disas-asm.h"
25 #include "opcode/nios2.h"
26 #include "libiberty.h"
27 #include <string.h>
28 #include <assert.h>
29 #include <stdlib.h>
30 
31 /* No symbol table is available when this code runs out in an embedded
32  system as when it is used for disassembler support in a monitor. */
33 #if !defined(EMBEDDED_ENV)
34 #define SYMTAB_AVAILABLE 1
35 #include "elf-bfd.h"
36 //#include "elf/nios2.h"
37 #endif
38 
39 /* Length of Nios II instruction in bytes. */
40 #define INSNLEN 4
41 
42 /* Data structures used by the opcode hash table. */
43 typedef struct _nios2_opcode_hash
44 {
45  const struct nios2_opcode *opcode;
48 
51 
52 /* Separate hash table for pseudo-ops. */
54 
55 /* Function to initialize the opcode hash table. */
56 static void
58 {
59  unsigned int i;
60  register const struct nios2_opcode *op;
61 
62  for (i = 0; i <= OP_MASK_OP; ++i) {
63  nios2_hash[0] = NULL;
64  }
65  for (i = 0; i <= OP_MASK_OP; i++) {
66  for (op = nios2_opcodes; op < &nios2_opcodes[NUMOPCODES]; op++) {
67  nios2_opcode_hash *new_hash;
68  nios2_opcode_hash **bucket = NULL;
69 
70  if ((op->pinfo & NIOS2_INSN_MACRO) == NIOS2_INSN_MACRO) {
71  if (i == ((op->match >> OP_SH_OP) & OP_MASK_OP) && (op->pinfo & (NIOS2_INSN_MACRO_MOV | NIOS2_INSN_MACRO_MOVI) & 0x7fffffff)) {
72  bucket = &(nios2_ps_hash[i]);
73  }
74  } else if (i == ((op->match >> OP_SH_OP) & OP_MASK_OP)) {
75  bucket = &(nios2_hash[i]);
76  }
77 
78  if (bucket) {
79  new_hash =
81  if (!new_hash) {
82  fprintf (stderr,
83  "error allocating memory...broken disassembler\n");
84  abort ();
85  }
86  new_hash->opcode = op;
87  new_hash->next = NULL;
88  while (*bucket) {
89  bucket = &((*bucket)->next);
90  }
91  *bucket = new_hash;
92  }
93  }
94  }
95  nios2_hash_init = 1;
96 #ifdef DEBUG_HASHTABLE
97  for (i = 0; i <= OP_MASK_OP; ++i)
98  {
99  nios2_opcode_hash *tmp_hash = nios2_hash[i];
100  printf ("index: 0x%02X ops: ", i);
101  while (tmp_hash != NULL)
102  {
103  printf ("%s ", tmp_hash->opcode->name);
104  tmp_hash = tmp_hash->next;
105  }
106  printf ("\n");
107  }
108 
109  for (i = 0; i <= OP_MASK_OP; ++i)
110  {
111  nios2_opcode_hash *tmp_hash = nios2_ps_hash[i];
112  printf ("index: 0x%02X ops: ", i);
113  while (tmp_hash != NULL)
114  {
115  printf ("%s ", tmp_hash->opcode->name);
116  tmp_hash = tmp_hash->next;
117  }
118  printf ("\n");
119  }
120 #endif /* DEBUG_HASHTABLE */
121 }
122 
123 /* Return a pointer to an nios2_opcode struct for a given instruction
124  opcode, or NULL if there is an error. */
125 const struct nios2_opcode *
126 nios2_find_opcode_hash (unsigned long opcode)
127 {
129 
130  /* Build a hash table to shorten the search time. */
131  if (!nios2_hash_init) {
133  }
134 
135  /* First look in the pseudo-op hashtable. */
136  for (entry = nios2_ps_hash[(opcode >> OP_SH_OP) & OP_MASK_OP];
137  entry; entry = entry->next) {
138  if (entry->opcode->match == (opcode & entry->opcode->mask)) {
139  return entry->opcode;
140  }
141  }
142 
143  /* Otherwise look in the main hashtable. */
144  for (entry = nios2_hash[(opcode >> OP_SH_OP) & OP_MASK_OP];
145  entry; entry = entry->next) {
146  if (entry->opcode->match == (opcode & entry->opcode->mask)) {
147  return entry->opcode;
148  }
149  }
150 
151  return NULL;
152 }
153 
154 /* There are 32 regular registers, 32 coprocessor registers,
155  and 32 control registers. */
156 #define NUMREGNAMES 32
157 
158 /* Return a pointer to the base of the coprocessor register name array. */
159 static struct nios2_reg *
161 {
162  static struct nios2_reg *cached = NULL;
163 
164  if (!cached)
165  {
166  int i;
167  for (i = NUMREGNAMES; i < nios2_num_regs; i++) {
168  if (!strcmp (nios2_regs[i].name, "c0")) {
169  cached = nios2_regs + i;
170  break;
171  }
172  }
173  assert (cached);
174  }
175  return cached;
176 }
177 
178 /* Return a pointer to the base of the control register name array. */
179 static struct nios2_reg *
181 {
182  static struct nios2_reg *cached = NULL;
183 
184  if (!cached)
185  {
186  int i;
187  for (i = NUMREGNAMES; i < nios2_num_regs; i++) {
188  if (!strcmp (nios2_regs[i].name, "status")) {
189  cached = nios2_regs + i;
190  break;
191  }
192  }
193  assert (cached);
194  }
195  return cached;
196 }
197 
198 /* The function nios2_print_insn_arg uses the character pointed
199  to by ARGPTR to determine how it print the next token or separator
200  character in the arguments to an instruction. */
201 static int
202 nios2_print_insn_arg (const char *argptr,
203  unsigned long opcode, bfd_vma address,
205 {
206  unsigned long i = 0;
207  struct nios2_reg *reg_base;
208 
209  switch (*argptr)
210  {
211  case ',':
212  case '(':
213  case ')':
214  (*info->fprintf_func) (info->stream, "%c", *argptr);
215  break;
216  case 'd':
217  i = GET_INSN_FIELD (RRD, opcode);
218 
219  if (GET_INSN_FIELD (OP, opcode) == OP_MATCH_CUSTOM && GET_INSN_FIELD (CUSTOM_C, opcode) == 0) {
220  reg_base = nios2_coprocessor_regs ();
221  } else {
222  reg_base = nios2_regs;
223  }
224 
225  if (i < NUMREGNAMES) {
226  (*info->fprintf_func) (info->stream, "%s", reg_base[i].name);
227  } else {
228  (*info->fprintf_func) (info->stream, "unknown");
229  }
230  break;
231  case 's':
232  i = GET_INSN_FIELD (RRS, opcode);
233 
234  if (GET_INSN_FIELD (OP, opcode) == OP_MATCH_CUSTOM && GET_INSN_FIELD (CUSTOM_A, opcode) == 0) {
235  reg_base = nios2_coprocessor_regs ();
236  } else {
237  reg_base = nios2_regs;
238  }
239 
240  if (i < NUMREGNAMES) {
241  (*info->fprintf_func) (info->stream, "%s", reg_base[i].name);
242  } else {
243  (*info->fprintf_func) (info->stream, "unknown");
244  }
245  break;
246  case 't':
247  i = GET_INSN_FIELD (RRT, opcode);
248 
249  if (GET_INSN_FIELD (OP, opcode) == OP_MATCH_CUSTOM && GET_INSN_FIELD (CUSTOM_B, opcode) == 0) {
250  reg_base = nios2_coprocessor_regs ();
251  } else {
252  reg_base = nios2_regs;
253  }
254 
255  if (i < NUMREGNAMES) {
256  (*info->fprintf_func) (info->stream, "%s", reg_base[i].name);
257  } else {
258  (*info->fprintf_func) (info->stream, "unknown");
259  }
260  break;
261  case 'i':
262  /* 16-bit signed immediate. */
263  i = (int) (GET_INSN_FIELD (IMM16, opcode) << 16) >> 16;
264  (*info->fprintf_func) (info->stream, "%ld", i);
265  break;
266  case 'u':
267  /* 16-bit unsigned immediate. */
268  i = GET_INSN_FIELD (IMM16, opcode);
269  (*info->fprintf_func) (info->stream, "%ld", i);
270  break;
271  case 'o':
272  /* 16-bit signed immediate address offset. */
273  i = (int) (GET_INSN_FIELD (IMM16, opcode) << 16) >> 16;
274  address = address + 4 + i;
275  (*info->print_address_func) (address, info);
276  break;
277  case 'p':
278  /* 5-bit unsigned immediate. */
279  i = GET_INSN_FIELD (CACHE_OPX, opcode);
280  (*info->fprintf_func) (info->stream, "%ld", i);
281  break;
282  case 'j':
283  /* 5-bit unsigned immediate. */
284  i = GET_INSN_FIELD (IMM5, opcode);
285  (*info->fprintf_func) (info->stream, "%ld", i);
286  break;
287  case 'l':
288  /* 8-bit unsigned immediate. */
289  /* FIXME - not yet implemented */
290  i = GET_INSN_FIELD (CUSTOM_N, opcode);
291  (*info->fprintf_func) (info->stream, "%lu", i);
292  break;
293  case 'm':
294  /* 26-bit unsigned immediate. */
295  i = GET_INSN_FIELD (IMM26, opcode);
296  /* This translates to an address because it's only used in call
297  instructions. */
298  address = (address & 0xf0000000) | (i << 2);
299  (*info->print_address_func) (address, info);
300  break;
301  case 'c':
302  /* Control register index. */
303  i = GET_INSN_FIELD (IMM5, opcode);
304  reg_base = nios2_control_regs ();
305  (*info->fprintf_func) (info->stream, "%s", reg_base[i].name);
306  break;
307  case 'b':
308  i = GET_INSN_FIELD (IMM5, opcode);
309  (*info->fprintf_func) (info->stream, "%ld", i);
310  break;
311  default:
312  (*info->fprintf_func) (info->stream, "unknown");
313  break;
314  }
315  return 0;
316 }
317 
318 /* nios2_disassemble does all the work of disassembling a Nios II
319  instruction opcode. */
320 static int
321 nios2_disassemble (bfd_vma address, unsigned long opcode,
323 {
324  const struct nios2_opcode *op;
325 
326  info->bytes_per_line = INSNLEN;
327  info->bytes_per_chunk = INSNLEN;
328  info->display_endian = info->endian;
329  info->insn_info_valid = 1;
330  info->branch_delay_insns = 0;
331  info->data_size = 0;
332  info->insn_type = dis_nonbranch;
333  info->target = 0;
334  info->target2 = 0;
335 
336  /* Find the major opcode and use this to disassemble
337  the instruction and its arguments. */
338  op = nios2_find_opcode_hash (opcode);
339 
340  if (op != NULL)
341  {
342  bfd_boolean is_nop = FALSE;
343  if (op->pinfo == NIOS2_INSN_MACRO_MOV)
344  {
345  /* Check for mov r0, r0 and change to nop. */
346  int dst, src;
347  dst = GET_INSN_FIELD (RRD, opcode);
348  src = GET_INSN_FIELD (RRS, opcode);
349  if (dst == 0 && src == 0)
350  {
351  (*info->fprintf_func) (info->stream, "nop");
352  is_nop = TRUE;
353  } else {
354  (*info->fprintf_func) (info->stream, "%s", op->name);
355  }
356  } else {
357  (*info->fprintf_func) (info->stream, "%s", op->name);
358  }
359 
360  if (!is_nop)
361  {
362  const char *argstr = op->args;
363  if (argstr != NULL && *argstr != '\0')
364  {
365  (*info->fprintf_func) (info->stream, " ");
366  while (*argstr != '\0')
367  {
368  nios2_print_insn_arg (argstr, opcode, address, info);
369  ++argstr;
370  }
371  }
372  }
373  }
374  else
375  {
376  /* Handle undefined instructions. */
377  info->insn_type = dis_noninsn;
378  (*info->fprintf_func) (info->stream, "0x%lx", opcode);
379  }
380  /* Tell the caller how far to advance the program counter. */
381  return INSNLEN;
382 }
383 
384 
385 /* print_insn_nios2 is the main disassemble function for Nios II.
386  The function diassembler(abfd) (source in disassemble.c) returns a
387  pointer to this either print_insn_big_nios2 or
388  print_insn_little_nios2, which in turn call this function when the
389  bfd machine type is Nios II. print_insn_nios2 reads the
390  instruction word at the address given, and prints the disassembled
391  instruction on the stream info->stream using info->fprintf_func. */
392 
393 static int
395  enum bfd_endian endianness)
396 {
398  int status;
399 
400  status = (*info->read_memory_func) (address, buffer, INSNLEN, info);
401  if (status == 0)
402  {
403  unsigned long insn;
404  if (endianness == BFD_ENDIAN_BIG) {
405  insn = (unsigned long)bfd_getb32 (buffer);
406  } else {
407  insn = (unsigned long)bfd_getl32 (buffer);
408  }
409  status = nios2_disassemble (address, insn, info);
410  }
411  else
412  {
413  (*info->memory_error_func) (status, address, info);
414  status = -1;
415  }
416  return status;
417 }
418 
419 /* These two functions are the main entry points, accessed from
420  disassemble.c. */
421 int
423 {
424  return print_insn_nios2 (address, info, BFD_ENDIAN_BIG);
425 }
426 
427 int
429 {
430  return print_insn_nios2 (address, info, BFD_ENDIAN_LITTLE);
431 }
ut8 op
Definition: 6502dis.c:13
lzma_index ** i
Definition: index.h:629
lzma_index * src
Definition: index.h:567
RzBinInfo * info(RzBinFile *bf)
Definition: bin_ne.c:86
#define NULL
Definition: cris-opc.c:27
_Use_decl_annotations_ int __cdecl printf(const char *const _Format,...)
Definition: cs_driver.c:93
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 long
Definition: sflib.h:79
@ dis_noninsn
Definition: disas-asm.h:48
@ dis_nonbranch
Definition: disas-asm.h:49
#define OP(v, w, x, y, z)
#define NUMOPCODES
Definition: hppa.h:1079
#define OP_MASK_OP
Definition: mips.h:64
#define OP_SH_OP
Definition: mips.h:65
void * malloc(size_t size)
Definition: malloc.c:123
static const char struct stat static buf struct stat static buf static vhangup int status
Definition: sflib.h:145
char * dst
Definition: lz4.h:724
assert(limit<=UINT32_MAX/2)
unsigned char bfd_byte
Definition: mybfd.h:176
BFD_HOST_U_64_BIT bfd_vma
Definition: mybfd.h:111
static bfd_vma bfd_getb32(const void *p)
Definition: mybfd.h:4979
int bfd_boolean
Definition: mybfd.h:98
bfd_endian
Definition: mybfd.h:4617
@ BFD_ENDIAN_LITTLE
Definition: mybfd.h:4618
@ BFD_ENDIAN_BIG
Definition: mybfd.h:4617
#define TRUE
Definition: mybfd.h:103
#define FALSE
Definition: mybfd.h:102
static bfd_vma bfd_getl32(const void *p)
Definition: mybfd.h:4990
static struct nios2_reg * nios2_coprocessor_regs(void)
Definition: nios2-dis.c:160
static void nios2_init_opcode_hash(void)
Definition: nios2-dis.c:57
static nios2_opcode_hash * nios2_ps_hash[(OP_MASK_OP)+1]
Definition: nios2-dis.c:53
#define INSNLEN
Definition: nios2-dis.c:40
static int nios2_disassemble(bfd_vma address, unsigned long opcode, disassemble_info *info)
Definition: nios2-dis.c:321
static bfd_boolean nios2_hash_init
Definition: nios2-dis.c:49
static nios2_opcode_hash * nios2_hash[(OP_MASK_OP)+1]
Definition: nios2-dis.c:50
#define NUMREGNAMES
Definition: nios2-dis.c:156
struct _nios2_opcode_hash nios2_opcode_hash
const struct nios2_opcode * nios2_find_opcode_hash(unsigned long opcode)
Definition: nios2-dis.c:126
static int nios2_print_insn_arg(const char *argptr, unsigned long opcode, bfd_vma address, disassemble_info *info)
Definition: nios2-dis.c:202
int print_insn_little_nios2(bfd_vma address, disassemble_info *info)
Definition: nios2-dis.c:428
static struct nios2_reg * nios2_control_regs(void)
Definition: nios2-dis.c:180
static int print_insn_nios2(bfd_vma address, disassemble_info *info, enum bfd_endian endianness)
Definition: nios2-dis.c:394
int print_insn_big_nios2(bfd_vma address, disassemble_info *info)
Definition: nios2-dis.c:422
struct nios2_reg * nios2_regs
Definition: nios2-opc.c:169
#define OP_MATCH_CUSTOM
Definition: nios2.h:398
#define GET_INSN_FIELD(X, i)
Definition: nios2.h:126
#define NIOS2_INSN_MACRO_MOV
Definition: nios2.h:102
#define NIOS2_INSN_MACRO
Definition: nios2.h:101
#define NIOS2_INSN_MACRO_MOVI
Definition: nios2.h:103
struct nios2_opcode * nios2_opcodes
Definition: nios2-opc.c:412
int nios2_num_regs
Definition: nios2-opc.c:170
static int
Definition: sfsocketcall.h:114
struct _nios2_opcode_hash * next
Definition: nios2-dis.c:46
const struct nios2_opcode * opcode
Definition: nios2-dis.c:45
Definition: buffer.h:15
Definition: zipcmp.c:77
Definition: z80asm.h:102
const char * name
Definition: nios2.h:81
const char * name
Definition: nios2.h:118
Definition: dis.c:32
#define IMM5(instr)
Definition: v810_disas.h:12