Rizin
unix-like reverse engineering framework and cli tools
lanai-dis.c File Reference
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include "ansidecl.h"
#include "opcode/lanai.h"
#include "disas-asm.h"

Go to the source code of this file.

Macros

#define reg(n)   (*info->fprintf_func) (stream, "%s", reg_names[n])
 

Functions

static int is_delayed_branch (unsigned long insn)
 
static int compare_opcodes (char *a, char *b)
 
int print_insn_lanai (bfd_vma memaddr, disassemble_info *info)
 

Variables

static char * reg_names []
 
static char * op_names []
 
static int opcodes_sorted = 0
 

Macro Definition Documentation

◆ reg

#define reg (   n)    (*info->fprintf_func) (stream, "%s", reg_names[n])

Function Documentation

◆ compare_opcodes()

static int compare_opcodes ( char *  a,
char *  b 
)
static

Definition at line 403 of file lanai-dis.c.

405 {
406  struct lanai_opcode *op0 = (struct lanai_opcode *) a;
407  struct lanai_opcode *op1 = (struct lanai_opcode *) b;
408  unsigned long int match0 = op0->match, match1 = op1->match;
409  unsigned long int lose0 = op0->lose, lose1 = op1->lose;
410  register unsigned int i;
411 
412  /* If a bit is set in both match and lose, there is something
413  wrong with the opcode table. */
414  if (match0 & lose0)
415  {
416  fprintf (stderr, "Internal error: bad lanai-opcode.h: \"%s\", %#.8lx, %#.8lx\n",
417  op0->name, match0, lose0);
418  op0->lose &= ~op0->match;
419  lose0 = op0->lose;
420  }
421 
422  if (match1 & lose1)
423  {
424  fprintf (stderr, "Internal error: bad lanai-opcode.h: \"%s\", %#.8lx, %#.8lx\n",
425  op1->name, match1, lose1);
426  op1->lose &= ~op1->match;
427  lose1 = op1->lose;
428  }
429 
430  /* Because the bits that are variable in one opcode are constant in
431  another, it is important to order the opcodes in the right order. */
432  for (i = 0; i < 32; ++i)
433  {
434  unsigned long int x = 1 << i;
435  int x0 = (match0 & x) != 0;
436  int x1 = (match1 & x) != 0;
437 
438  if (x0 != x1) {
439  return x1 - x0;
440  }
441  }
442 
443  for (i = 0; i < 32; ++i)
444  {
445  unsigned long int x = 1 << i;
446  int x0 = (lose0 & x) != 0;
447  int x1 = (lose1 & x) != 0;
448 
449  if (x0 != x1) {
450  return x1 - x0;
451  }
452  }
453 
454  /* They are functionally equal. So as long as the opcode table is
455  valid, we can put whichever one first we want, on aesthetic grounds. */
456 
457  /* Our first aesthetic ground is that aliases defer to real insns. */
458  {
459  int alias_diff = (op0->flags & F_ALIAS) - (op1->flags & F_ALIAS);
460  if (alias_diff != 0) {
461  /* Put the one that isn't an alias first. */
462  return alias_diff;
463  }
464  }
465 
466  /* Except for aliases, two "identical" instructions had
467  better have the same opcode. This is a sanity check on the table. */
468  i = strcmp (op0->name, op1->name);
469  if (i)
470  {
471  if (op0->flags & F_ALIAS) /* If they're both aliases, be arbitrary. */
472  {
473  return i;
474  }
475  else
476  {
477  fprintf (stderr,
478  "Internal error: bad lanai-opcode.h: \"%s\" == \"%s\"\n",
479  op0->name, op1->name);
480  }
481  }
482 
483  /* Fewer arguments are preferred. */
484  {
485  int length_diff = strlen (op0->args) - strlen (op1->args);
486  if (length_diff != 0) {
487  /* Put the one with fewer arguments first. */
488  return length_diff;
489  }
490  }
491 
492  /* Put 1+i before i+1. */
493  {
494  char *p0 = (char *) strchr(op0->args, '+');
495  char *p1 = (char *) strchr(op1->args, '+');
496 
497  if (p0 && p1)
498  {
499  /* There is a plus in both operands. Note that a plus
500  sign cannot be the first character in args,
501  so the following [-1]'s are valid. */
502  if (p0[-1] == 'i' && p1[1] == 'i') {
503  /* op0 is i+1 and op1 is 1+i, so op1 goes first. */
504  return 1;
505  }
506  if (p0[1] == 'i' && p1[-1] == 'i') {
507  /* op0 is 1+i and op1 is i+1, so op0 goes first. */
508  return -1;
509  }
510  }
511  }
512 
513  /* They are, as far as we can tell, identical.
514  Since qsort may have rearranged the table partially, there is
515  no way to tell which one was first in the opcode table as
516  written, so just say there are equal. */
517  return 0;
518 }
#define F_ALIAS
Definition: aarch64.h:722
lzma_index ** i
Definition: index.h:629
int x
Definition: mipsasm.c:20
#define b(i)
Definition: sha256.c:42
#define a(i)
Definition: sha256.c:41
unsigned long lose
Definition: lanai.h:93
unsigned int flags
Definition: lanai.h:95
const char * args
Definition: lanai.h:94
unsigned long match
Definition: lanai.h:92
const char * name
Definition: lanai.h:91

References a, lanai_opcode::args, b, F_ALIAS, lanai_opcode::flags, i, lanai_opcode::lose, lanai_opcode::match, lanai_opcode::name, x, x0, and x1.

Referenced by print_insn_lanai().

◆ is_delayed_branch()

static int is_delayed_branch ( unsigned long  insn)
static

Definition at line 79 of file lanai-dis.c.

81 {
82  int i;
83 
84  for (i = 0; i < NUMOPCODES; i++)
85  {
86  CONST struct lanai_opcode *opcode = &lanai_opcodes[i];
87  if ((opcode->match & insn) == opcode->match && (opcode->lose & insn) == 0) {
88  return (opcode->flags & F_BR);
89  }
90  }
91  return 0;
92 }
#define NUMOPCODES
Definition: hppa.h:1079
#define F_BR
Definition: lanai.h:107
#define lanai_opcodes
Definition: lanai.h:76
#define CONST
Definition: ansidecl.h:246

References CONST, F_BR, lanai_opcode::flags, i, lanai_opcodes, lanai_opcode::lose, lanai_opcode::match, and NUMOPCODES.

Referenced by print_insn_lanai().

◆ print_insn_lanai()

int print_insn_lanai ( bfd_vma  memaddr,
disassemble_info info 
)

Definition at line 106 of file lanai-dis.c.

109 {
110  FILE *stream = info->stream;
111  bfd_byte buffer[4];
112  unsigned int insn;
113  register int i;
114 
115  if (!opcodes_sorted)
116  {
117  qsort ((char *) lanai_opcodes, NUMOPCODES,
118  sizeof (lanai_opcodes[0]),
119  (int (*)(const void *,const void *))compare_opcodes);
120  opcodes_sorted = 1;
121  }
122 
123  {
124  int status =
125  (*info->read_memory_func) (memaddr, buffer, sizeof (buffer), info);
126  if (status != 0)
127  {
128  (*info->memory_error_func) (status, memaddr, info);
129  return -1;
130  }
131  }
132 
133  insn = bfd_getb32 (buffer);
134 
135  info->insn_info_valid = 1; /* We do return this info */
136  info->insn_type = dis_nonbranch; /* Assume non branch insn */
137  info->branch_delay_insns = 0; /* Assume no delay */
138  info->target = 0; /* Assume no target known */
139 
140  for (i = 0; i < NUMOPCODES; i++)
141  {
142  CONST struct lanai_opcode *opcode = &lanai_opcodes[i];
143  if ((opcode->match & insn) == opcode->match
144  && (opcode->lose & insn) == 0)
145  {
146  /* Nonzero means that we have found an instruction which has
147  the effect of adding or or'ing the imm13 field to rs1. */
148  int imm_added_to_rs1 = 0;
149 
150  /* Do we have an `add' or `or' immediate instruction where rs1 is
151  the same as rd? */
152 
153  if (((!(opcode->match & 0x80000000) /* RI insn */
154  && ( !(opcode->match & 0x70000000) /* RI add */
155  || (opcode->match & 0x70000000) == 0x50000000 /* RI or */
156  ))
157  || ((opcode->match & 0xf0000000) == 0xc0000000 /* RR insn */
158  && ( !(opcode->match & 0x00000700) /* RR add */
159  || (opcode->match & 0x00000700) == 0x00000500 /* RR or */ )))
160  && X_RS1(insn) == X_RD(insn))
161  {
162  imm_added_to_rs1 = 1;
163  }
164 
165 #ifdef BAD
166  if (X_RS1 (insn) != X_RD (insn)
167  && strchr (opcode->args, 'r') != 0)
168  /* Can't do simple format if source and dest are different. */
169  continue;
170 #endif
171 
172  (*info->fprintf_func) (stream, "%s", opcode->name);
173 
174  {
175  register CONST char *s;
176  unsigned int imm;
177 
178  for (s = opcode->args; *s != '\0'; ++s)
179  {
180 
181  (*info->fprintf_func) (stream, " ");
182 
183  switch (*s)
184  {
185  /* By default, just print the character. */
186  default:
187  (*info->fprintf_func) (stream, "%c", *s);
188  break;
189 
190 #define reg(n) (*info->fprintf_func) (stream, "%s", reg_names[n])
191 // #define reg(n) (*info->fprintf_func) (stream, "%%%s", reg_names[n])
192  case '1':
193  reg (X_RS1 (insn));
194  break;
195 
196  case '2':
197  reg (X_RS2 (insn));
198  break;
199 
200  case '3':
201  reg (X_RS3 (insn));
202  break;
203 
204  case 'd':
205  reg (X_RD (insn));
206  break;
207 
208 #undef reg
209 
210  case '4': /* Op1 (for RRR) */
211  (*info->fprintf_func) (stream, "%s", op_names[X_OP1(insn)]);
212  break;
213  case '5': /* Op2 (for RRR) */
214  (*info->fprintf_func) (stream, "%s", op_names[X_OP2(insn)]);
215  if (insn & L3_RRR_F) {
216  (*info->fprintf_func) (stream, ".f");
217  }
218  break;
219  case '6': /* Op2 (for RRM) */
220  (*info->fprintf_func) (stream, "%s", op_names[X_OP2(insn)]);
221  break;
222 
223  case 'J':
224  imm = X_C16(insn)<<16;
225  goto print_immediate;
226  case 'j':
227  imm = X_C16(insn);
228  goto print_immediate;
229  case 'L':
230  imm = (X_C16(insn)<<16)|0xffff;
231  goto print_immediate;
232  case 'l':
233  imm = X_C16(insn)|0xffff0000;
234  goto print_immediate;
235  case 'k':
236  /* This should never happen */
237  (*info->fprintf_func) (stream, "***ERROR***");
238  break;
239  case 'o':
240  imm = SIGN_EXT (X_C16(insn), 16);
241  if (X_RS1 (insn) == 0) {
242  goto print_address;
243  }
244  goto print_immediate;
245  case 's':
246  imm = SIGN_EXT (X_C16(insn), 16);
247  goto print_immediate;
248  case 'i':
249  imm = SIGN_EXT (X_C10(insn), 10);
250  if (X_RS1 (insn) == 0) {
251  goto print_address;
252  }
253  goto print_immediate;
254  case 'I':
255  imm = X_C21(insn);
256  goto print_address;
257  case 'Y':
258  imm = X_C21(insn);
259  goto print_address;
260  case 'B':
261  imm = X_C25(insn);
262  goto print_address;
263  case 'b':
264  imm = SIGN_EXT (X_C25(insn), 25);
265  goto print_address;
266 
267  print_immediate:
268  (*info->fprintf_func) (stream, "0x%x", imm);
269  break;
270  print_address:
271  info->target = imm;
272  (*info->print_address_func) (imm, info);
273  break;
274 
275  /* Named registers */
276 
277  case 'P':
278  (*info->fprintf_func) (stream, "%%pc");
279  break;
280 
281  case 'p':
282  (*info->fprintf_func) (stream, "%%ps");
283  break;
284 
285  case 'Q':
286  (*info->fprintf_func) (stream, "%%apc");
287  break;
288 
289  case 'q':
290  (*info->fprintf_func) (stream, "%%aps");
291  break;
292 
293  case 'S':
294  (*info->fprintf_func) (stream, "%%isr");
295  break;
296 
297  case 'M':
298  (*info->fprintf_func) (stream, "%%imr");
299  break;
300 
301  case '!':
302  (*info->fprintf_func) (stream, "%%r1");
303  break;
304 
305  case '0':
306  (*info->fprintf_func) (stream, "%%r0");
307  break;
308 
309  }
310  }
311  }
312 
313  /* If we are adding or or'ing something to rs1, then
314  check to see whether the previous instruction was
315  a mov to the same register as in the or.
316  If so, attempt to print the result of the add or
317  or (in this context add and or do the same thing)
318  and its symbolic value. */
319  if (imm_added_to_rs1)
320  {
321  unsigned long prev_insn;
322  int errcode;
323 
324  errcode =
325  (*info->read_memory_func)
326  (memaddr - 4, buffer, sizeof (buffer), info);
327  prev_insn = bfd_getb32 (buffer);
328 
329  if (errcode == 0)
330  {
331  /* If it is a delayed branch, we need to look at the
332  instruction before the delayed branch. This handles
333  sequences such as
334 
335  mov %hi(_foo), %r4
336  call _printf
337  or %r4, %lo(_foo), %r4
338  */
339 
340  if (is_delayed_branch (prev_insn))
341  {
342  errcode = (*info->read_memory_func)
343  (memaddr - 8, buffer, sizeof (buffer), info);
344  prev_insn = bfd_getb32 (buffer);
345  }
346  }
347 
348  /* If there was a problem reading memory, then assume
349  the previous instruction was not sethi. */
350  if (errcode == 0)
351  {
352  /* Is it an "{and,or} %r0,0x????????,%rd" to the same reg */
353  if (((prev_insn & 0xf07c0000) == 0x00000000
354  || (prev_insn & 0xf07c0000) == 0x50000000 )
355  && X_RD (prev_insn) == X_RS1 (insn)
356  && X_RD (prev_insn) )
357  {
358  (*info->fprintf_func) (stream, "\t! ");
359  info->target
360  = X_C16( insn) << (L3_RI_H& insn ? 16 : 0);
361  if((prev_insn & 0xf07c0000) == 0x50000000 ){
362  info->target
363  |= X_C16(prev_insn) << (L3_RI_H&prev_insn ? 16 : 0);
364  }else{
365  info->target
366  += X_C16(prev_insn) << (L3_RI_H&prev_insn ? 16 : 0);
367  }
368  (*info->print_address_func) (info->target, info);
369  info->insn_type = dis_dref;
370  info->data_size = 4; /* FIXME!!! */
371  }
372  }
373  }
374 
375  info->data_size = F_DATA_SIZE(opcode->flags);
376 
377  if (opcode->flags & (F_UNBR|F_CONDBR|F_JSR))
378  {
379  /* FIXME -- check is_annulled flag */
380  if (opcode->flags & F_UNBR) {
381  info->insn_type = dis_branch;
382  } else if (opcode->flags & F_CONDBR) {
383  info->insn_type = dis_condbranch;
384  } else if (opcode->flags & F_JSR) {
385  info->insn_type = dis_jsr;
386  } else if (opcode->flags & F_BR) {
387  info->branch_delay_insns = 1;
388  }
389  }
390 
391  return sizeof (buffer);
392  }
393  }
394 
395  info->insn_type = dis_noninsn; /* Mark as non-valid instruction */
396  (*info->fprintf_func) (stream, "%#8x", insn);
397  return sizeof (buffer);
398 }
#define imm
#define X_OP2(i)
#define X_RS2(i)
#define X_RD(i)
#define X_RS1(i)
RzBinInfo * info(RzBinFile *bf)
Definition: bin_ne.c:86
struct buffer buffer
@ dis_dref
Definition: disas-asm.h:54
@ dis_noninsn
Definition: disas-asm.h:48
@ dis_nonbranch
Definition: disas-asm.h:49
@ dis_condbranch
Definition: disas-asm.h:51
@ dis_jsr
Definition: disas-asm.h:52
@ dis_branch
Definition: disas-asm.h:50
voidpf stream
Definition: ioapi.h:138
static int is_delayed_branch(unsigned long insn)
Definition: lanai-dis.c:79
static char * op_names[]
Definition: lanai-dis.c:72
#define reg(n)
static int compare_opcodes(char *a, char *b)
Definition: lanai-dis.c:403
static int opcodes_sorted
Definition: lanai-dis.c:94
#define F_DATA_SIZE(X)
Definition: lanai.h:118
#define F_UNBR
Definition: lanai.h:126
#define X_OP1(i)
Definition: lanai.h:381
#define L3_RI_H
Definition: lanai.h:301
#define L3_RRR_F
Definition: lanai.h:307
#define X_RS3(i)
Definition: lanai.h:379
#define F_CONDBR
Definition: lanai.h:125
#define F_JSR
Definition: lanai.h:100
#define SIGN_EXT(value, bits)
Definition: lanai.h:370
#define X_C25(i)
Definition: lanai.h:392
#define X_C10(i)
Definition: lanai.h:389
#define X_C21(i)
Definition: lanai.h:391
#define X_C16(i)
Definition: lanai.h:390
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
static bfd_vma bfd_getb32(const void *p)
Definition: mybfd.h:4979
string FILE
Definition: benchmark.py:21
void qsort(void *a, size_t n, size_t es, int(*cmp)(const void *, const void *))
Definition: qsort.h:130
static RzSocket * s
Definition: rtr.c:28
Definition: buffer.h:15

References lanai_opcode::args, bfd_getb32(), compare_opcodes(), CONST, dis_branch, dis_condbranch, dis_dref, dis_jsr, dis_nonbranch, dis_noninsn, F_BR, F_CONDBR, F_DATA_SIZE, F_JSR, F_UNBR, benchmark::FILE, lanai_opcode::flags, i, imm, info(), is_delayed_branch(), L3_RI_H, L3_RRR_F, lanai_opcodes, lanai_opcode::lose, lanai_opcode::match, lanai_opcode::name, NUMOPCODES, op_names, opcodes_sorted, qsort(), reg, s, SIGN_EXT, status, X_C10, X_C16, X_C21, X_C25, X_OP1, X_OP2, X_RD, X_RS1, X_RS2, and X_RS3.

Referenced by disassemble().

Variable Documentation

◆ op_names

char* op_names[]
static
Initial value:
=
{ "add", "addc", "sub", "subb", "and", "or", "xor", "sh" }

Definition at line 72 of file lanai-dis.c.

Referenced by print_insn_lanai().

◆ opcodes_sorted

int opcodes_sorted = 0
static

Definition at line 94 of file lanai-dis.c.

Referenced by print_insn_lanai().

◆ reg_names

char* reg_names[]
static
Initial value:
=
{ "r0", "r1", "pc", "ps", "sp", "fp", "r6", "r7",
"r8", "r9","r10","r11","r12","r13","r14","r15",
"r16","r17","r18","r19","r20","r21","r22","r23",
"r24","r25","r26","r27","r28","r29","r30","r31",
}

Definition at line 65 of file lanai-dis.c.