Rizin
unix-like reverse engineering framework and cli tools
asm_lm32.c
Go to the documentation of this file.
1 // SPDX-FileCopyrightText: 2015 Felix Held
2 // SPDX-License-Identifier: BSD-2-Clause
3 
4 #include <rz_types.h>
5 #include <rz_util.h>
6 #include <rz_lib.h>
7 #include <rz_asm.h>
8 #include "../arch/lm32/lm32_isa.h"
9 
10 #define LM32_UNUSED 0
11 
12 // str has to be at least 8 chars elements long
13 static int reg_number_to_string(ut8 reg, char *str) {
14  ut8 match_idx = 0xff;
15  int i;
16  for (i = 0; i < RzAsmLm32RegNumber; i++) {
17  if (RzAsmLm32Regs[i].number == reg) {
18  match_idx = i;
19  break;
20  }
21  }
22  // register number not found in array. this shouldn't happen
23  if (match_idx == 0xff) {
24  return -1;
25  }
26  strcpy(str, RzAsmLm32Regs[match_idx].name);
27  return 0;
28 }
29 
30 #if LM32_UNUSED
31 static int string_to_reg_number(const char *str, ut8 *num) {
32  ut8 match_idx = 0xff;
33  int i;
34  for (i = 0; i < RzAsmLm32RegNumber; i++) {
35  if (!strcmp(RzAsmLm32Regs[i].name, str)) {
36  match_idx = i;
37  break;
38  }
39  }
40  // register name string not found in array
41  if (match_idx == 0xff)
42  return -1;
43  *num = RzAsmLm32Regs[match_idx].number;
44  return 0;
45 }
46 
47 static int string_to_csr_number(const char *str, ut8 *num) {
48  ut8 match_idx = 0xff;
49  int i;
50  for (i = 0; i < RzAsmLm32CsrNumber; i++) {
51  if (!strcmp(RzAsmLm32Csrs[i].name, str)) {
52  match_idx = i;
53  break;
54  }
55  }
56  // csr name string not found in array
57  if (match_idx == 0xff)
58  return -1;
59  *num = RzAsmLm32Csrs[match_idx].number;
60  return 0;
61 }
62 
63 static int string_to_opcode(const char *str, ut8 *num) {
64  ut8 tmp_num = 0xff;
65  int i;
66  for (i = 0; i < RzAsmLm32OpcodeNumber; i++) {
67  if (!strcmp(RzAsmLm32OpcodeList[i].name, str)) {
68  tmp_num = i;
69  }
70  }
71  // string not found in array
72  if (tmp_num == 0xff)
73  return -1;
74  *num = tmp_num;
75  return 0;
76 }
77 #endif
78 
79 // str has to be at least 8 chars elements long
80 static int csr_number_to_string(ut8 csr, char *str) {
81  ut8 match_idx = 0xff;
82  int i;
83  for (i = 0; i < RzAsmLm32CsrNumber; i++) {
84  if (RzAsmLm32Csrs[i].number == csr) {
85  match_idx = i;
86  break;
87  }
88  }
89  // csr number not found in array
90  if (match_idx == 0xff) {
91  return -1;
92  }
93  strcpy(str, RzAsmLm32Csrs[match_idx].name);
94  return 0;
95 }
96 
97 // sign_loc is the location of the sign bit before the shift
99  ut32 tmp = val << shift;
100  if (tmp & (1 << (shift + sign_loc))) {
101  tmp |= ~((1 << (shift + sign_loc + 1)) - 1);
102  }
103  return tmp;
104 }
105 
108 }
109 
112 }
113 
116 }
117 
120 }
121 
122 // ret == b ra
124  //"ra" == 0x1d
125  return (instr->op == lm32_op_b) && (instr->src0_reg == 0x1d);
126 }
127 
128 // mv rX, rY == or rX, rY, r0
130  return (instr->op == lm32_op_or) && !instr->src1_reg;
131 }
132 
133 // mvhi rX, imm16 == orhi rX, r0, imm16
135  return (instr->op == lm32_op_orhi) && !instr->src0_reg;
136 }
137 
138 // not rX, rY == xnor rX, rY, r0
140  return (instr->op == lm32_op_xnor) && !instr->src1_reg;
141 }
142 
143 // mvi rX, imm16 == addi rX, r0, imm16
145  return (instr->op == lm32_op_addi) && !instr->src0_reg;
146 }
147 
148 // nop == addi r0, r0, 0
150  return (instr->op == lm32_op_addi) && !instr->dest_reg &&
151  !instr->src0_reg && !instr->immediate;
152 }
153 
154 // raise instruction is used for break, scall
156  return instr->op == raise_instr;
157 }
158 
160  instr->op = extract_opcode(instr->value);
161  if (instr->op >= RzAsmLm32OpcodeNumber) {
162  return -1;
163  }
164  instr->op_decode = RzAsmLm32OpcodeList[instr->op];
165 
166  switch (instr->op_decode.type) {
168  instr->dest_reg = extract_reg_v(instr->value);
169  instr->src0_reg = extract_reg_u(instr->value);
171  extract_imm16(instr->value));
172  break;
174  instr->dest_reg = extract_reg_v(instr->value);
175  instr->src0_reg = extract_reg_u(instr->value);
177  extract_imm16(instr->value));
178  break;
180  instr->dest_reg = extract_reg_v(instr->value);
181  instr->src0_reg = extract_reg_u(instr->value);
182  instr->immediate = extract_imm16(instr->value);
183  break;
184  case reg_imm5:
185  if (is_invalid_imm5_instr(instr)) {
186  return -1;
187  }
188  instr->dest_reg = extract_reg_v(instr->value);
189  instr->src0_reg = extract_reg_u(instr->value);
190  instr->immediate = extract_imm5(instr->value);
191  break;
192  case raise_instr:
193  if (is_invalid_imm5_instr(instr)) {
194  return -1;
195  }
196  // might be less bits used, but this shouldn't hurt
197  // invalid parameters are caught in print_pseudo_instruction anyway
198  instr->immediate = extract_imm5(instr->value);
199  break;
200  case one_reg:
201  if (is_invalid_one_reg_instr(instr)) {
202  return -1;
203  }
204  instr->src0_reg = extract_reg_u(instr->value);
205  break;
206  case two_regs:
207  if (is_invalid_two_reg_instr(instr)) {
208  return -1;
209  }
210  instr->dest_reg = extract_reg_w(instr->value);
211  instr->src0_reg = extract_reg_u(instr->value);
212  break;
213  case three_regs:
214  instr->dest_reg = extract_reg_w(instr->value);
215  instr->src0_reg = extract_reg_v(instr->value);
216  instr->src1_reg = extract_reg_u(instr->value);
217  break;
218  case reg_csr: // wcsr
219  if (is_invalid_wcsr_instr(instr)) {
220  return -1;
221  }
222  instr->src0_reg = extract_reg_v(instr->value);
223  instr->csr = extract_reg_u(instr->value);
224  break;
225  case csr_reg: // rcsr
226  // bitmask is the same as the two register one
227  if (is_invalid_two_reg_instr(instr)) {
228  return -1;
229  }
230  instr->dest_reg = extract_reg_w(instr->value);
231  instr->csr = extract_reg_u(instr->value);
232  break;
233  case imm26:
235  extract_imm26(instr->value));
236  break;
237  case reserved:
238  default:
239  return -1;
240  }
241 
242  // see if the instruction corresponds to a pseudo-instruction
243  instr->pseudoInstruction = is_pseudo_instr_ret(instr) || is_pseudo_instr_mv(instr) ||
244  is_pseudo_instr_mvhi(instr) || is_pseudo_instr_not(instr) || is_pseudo_instr_mvi(instr) ||
246 
247  return 0;
248 }
249 
251  switch (instr->op_decode.type) {
255  case reg_imm5:
256  case two_regs:
257  if (reg_number_to_string(instr->dest_reg, instr->dest_reg_str)) {
258  return -1;
259  }
260  if (reg_number_to_string(instr->src0_reg, instr->src0_reg_str)) {
261  return -1;
262  }
263  break;
264  case one_reg:
265  if (reg_number_to_string(instr->src0_reg, instr->src0_reg_str)) {
266  return -1;
267  }
268  break;
269  case three_regs:
270  if (reg_number_to_string(instr->dest_reg, instr->dest_reg_str)) {
271  return -1;
272  }
273  if (reg_number_to_string(instr->src0_reg, instr->src0_reg_str)) {
274  return -1;
275  }
276  if (reg_number_to_string(instr->src1_reg, instr->src1_reg_str)) {
277  return -1;
278  }
279  break;
280  case reg_csr:
281  if (reg_number_to_string(instr->src0_reg, instr->src0_reg_str)) {
282  return -1;
283  }
284  if (csr_number_to_string(instr->csr, instr->csr_reg_str)) {
285  return -1;
286  }
287  break;
288  case csr_reg:
289  if (reg_number_to_string(instr->dest_reg, instr->dest_reg_str)) {
290  return -1;
291  }
292  if (csr_number_to_string(instr->csr, instr->csr_reg_str)) {
293  return -1;
294  }
295  break;
296  case raise_instr:
297  case imm26:
298  break;
299  default:
300  return -1;
301  }
302  return 0;
303 }
304 
306  if (!instr->pseudoInstruction) {
307  return -1;
308  }
309  switch (instr->op) {
310  // ret == b ra
311  case lm32_op_b:
312  strcpy(str, "ret");
313  break;
314  // mv rX, rY == or rX, rY, r0
315  case lm32_op_or:
316  sprintf(str, "mv %s, %s", instr->dest_reg_str, instr->src0_reg_str);
317  break;
318  // mvhi rX, imm16 == orhi rX, r0, imm16
319  case lm32_op_orhi:
320  sprintf(str, "mvhi %s, 0x%x", instr->dest_reg_str, instr->immediate);
321  break;
322  // not rX, rY == xnor rX, rY, r0
323  case lm32_op_xnor:
324  sprintf(str, "not %s, %s", instr->dest_reg_str, instr->src0_reg_str);
325  break;
326  // mvi rX, imm16 == addi rX, r0, imm16
327  // nop == addi r0, r0, 0
328  case lm32_op_addi:
329  if (is_pseudo_instr_nop(instr)) { // nop
330  strcpy(str, "nop");
331  } else { // mvi
332  sprintf(str, "mvi %s, 0x%x", instr->dest_reg_str, instr->immediate);
333  }
334  break;
335  // break, scall
336  case lm32_op_raise:
337  switch (instr->immediate) {
338  case 0x2: // break
339  strcpy(str, "break");
340  break;
341  case 0x7: // scall
342  strcpy(str, "scall");
343  break;
344  default:
345  return -1;
346  }
347  break;
348  default:
349  return -1;
350  }
351  return 0;
352 }
353 
354 static int rz_asm_lm32_stringify(RzAsmLm32Instruction *instr, char *str) {
355  if (write_reg_names_to_struct(instr)) {
356  return -1;
357  }
358 
359  // pseudo instructions need some special handling
360  if (instr->pseudoInstruction) {
361  // return after printing the decoded pseudo instruction, so it doesn't get overwritten
362  return print_pseudo_instruction(instr, str);
363  }
364 
365  // get opcode string
366  strcpy(str, instr->op_decode.name);
367 
368  // get parameters (registers, immediate) string
369  switch (instr->op_decode.type) {
371  sprintf(str, "%s %s, %s, 0x%x", instr->op_decode.name, instr->dest_reg_str, instr->src0_reg_str,
372  instr->immediate);
373  break;
375  case reg_imm5:
376  sprintf(str, "%s %s, %s, 0x%x", instr->op_decode.name, instr->dest_reg_str, instr->src0_reg_str,
377  instr->immediate);
378  break;
380  // print the branch/call destination address
381  sprintf(str, "%s %s, %s, 0x%x", instr->op_decode.name, instr->dest_reg_str, instr->src0_reg_str,
382  instr->immediate + instr->addr);
383  break;
384  case one_reg:
385  sprintf(str, "%s %s", instr->op_decode.name, instr->src0_reg_str);
386  break;
387  case two_regs:
388  sprintf(str, "%s %s, %s", instr->op_decode.name, instr->dest_reg_str, instr->src0_reg_str);
389  break;
390  case three_regs:
391  sprintf(str, "%s %s, %s, %s", instr->op_decode.name, instr->dest_reg_str, instr->src0_reg_str,
392  instr->src1_reg_str);
393  break;
394  case reg_csr:
395  sprintf(str, "%s %s, %s", instr->op_decode.name, instr->csr_reg_str, instr->src0_reg_str);
396  break;
397  case csr_reg:
398  sprintf(str, "%s %s, %s", instr->op_decode.name, instr->dest_reg_str, instr->csr_reg_str);
399  break;
400  case imm26:
401  // print the branch/call destination address
402  sprintf(str, "%s 0x%x", instr->op_decode.name, instr->immediate + instr->addr);
403  break;
404  // case raise_instr: //unneeded; handled as pseudo instruction
405  default:
406  return -1;
407  }
408  return 0;
409 }
410 
411 #if 0
412 
413 static int rz_asm_lm32_destringify(const char *string, RzAsmLm32Instruction *instr) {
414  //TODO
415  return -1;
416 }
417 
418 static int rz_asm_lm32_encode(RzAsmLm32Instruction *instr, ut32 *val) {
419  //TODO
420  return -1;
421 }
422 
423 static int assemble(RzAsm *a, RzAsmOp *ao, const char *str) {
424  //TODO
425  return -1;
426 }
427 #endif
428 
429 static int disassemble(RzAsm *a, RzAsmOp *op, const ut8 *buf, int len) {
430  RzAsmLm32Instruction instr = { 0 };
431  instr.value = buf[0] << 24 | buf[1] << 16 | buf[2] << 8 | buf[3];
432  instr.addr = a->pc;
433  if (rz_asm_lm32_decode(&instr)) {
434  rz_strbuf_set(&op->buf_asm, "invalid");
435  a->invhex = 1;
436  return -1;
437  }
438  // op->buf_asm is 256 chars long, which is more than sufficient
439  if (rz_asm_lm32_stringify(&instr, rz_strbuf_get(&op->buf_asm))) {
440  rz_strbuf_set(&op->buf_asm, "invalid");
441  a->invhex = 1;
442  return -1;
443  }
444  return 4;
445 }
446 
448  .name = "lm32",
449  .arch = "lm32",
450  .desc = "disassembly plugin for Lattice Micro 32 ISA",
451  .author = "Felix Held",
452  .license = "BSD",
453  .bits = 32,
454  .endian = RZ_SYS_ENDIAN_BIG,
455  .disassemble = &disassemble,
456 };
457 
458 #ifndef RZ_PLUGIN_INCORE
461  .data = &rz_asm_plugin_lm32,
463 };
464 #endif
size_t len
Definition: 6502dis.c:15
lzma_index ** i
Definition: index.h:629
static RZ_NULLABLE RzILOpBitVector * shift(RzILOpBitVector *val, RZ_NULLABLE RzILOpBool **carry_out, arm_shifter type, RZ_OWN RzILOpBitVector *dist)
Definition: arm_il32.c:190
ut16 val
Definition: armass64_const.h:6
static AssembleFunction assemble[2]
Definition: armass.c:6207
static st32 shift_and_signextend(ut8 shift, ut8 sign_loc, ut32 val)
Definition: asm_lm32.c:98
static int reg_number_to_string(ut8 reg, char *str)
Definition: asm_lm32.c:13
static int rz_asm_lm32_decode(RzAsmLm32Instruction *instr)
Definition: asm_lm32.c:159
static bool is_pseudo_instr_mv(RzAsmLm32Instruction *instr)
Definition: asm_lm32.c:129
static int write_reg_names_to_struct(RzAsmLm32Instruction *instr)
Definition: asm_lm32.c:250
static bool is_pseudo_instr_mvi(RzAsmLm32Instruction *instr)
Definition: asm_lm32.c:144
static bool is_pseudo_instr_raise(RzAsmLm32Instruction *instr)
Definition: asm_lm32.c:155
static int rz_asm_lm32_stringify(RzAsmLm32Instruction *instr, char *str)
Definition: asm_lm32.c:354
static bool is_invalid_wcsr_instr(RzAsmLm32Instruction *instr)
Definition: asm_lm32.c:118
RZ_API RzLibStruct rizin_plugin
Definition: asm_lm32.c:459
static bool is_pseudo_instr_mvhi(RzAsmLm32Instruction *instr)
Definition: asm_lm32.c:134
static int print_pseudo_instruction(RzAsmLm32Instruction *instr, char *str)
Definition: asm_lm32.c:305
static bool is_pseudo_instr_nop(RzAsmLm32Instruction *instr)
Definition: asm_lm32.c:149
static bool is_invalid_one_reg_instr(RzAsmLm32Instruction *instr)
Definition: asm_lm32.c:110
static bool is_pseudo_instr_not(RzAsmLm32Instruction *instr)
Definition: asm_lm32.c:139
static bool is_invalid_two_reg_instr(RzAsmLm32Instruction *instr)
Definition: asm_lm32.c:114
static int csr_number_to_string(ut8 csr, char *str)
Definition: asm_lm32.c:80
static int disassemble(RzAsm *a, RzAsmOp *op, const ut8 *buf, int len)
Definition: asm_lm32.c:429
static bool is_invalid_imm5_instr(RzAsmLm32Instruction *instr)
Definition: asm_lm32.c:106
static bool is_pseudo_instr_ret(RzAsmLm32Instruction *instr)
Definition: asm_lm32.c:123
RzAsmPlugin rz_asm_plugin_lm32
Definition: asm_lm32.c:447
#define RZ_API
uint32_t ut32
voidpf void * buf
Definition: ioapi.h:138
sprintf
Definition: kernel.h:365
#define reg(n)
uint8_t ut8
Definition: lh5801.h:11
static static fork const void static count static fd const char const char static newpath char char char static envp time_t static t const char static mode static whence const char static dir time_t static t unsigned static seconds const char struct utimbuf static buf static inc static sig const char static mode static oldfd struct tms static buf static getgid static geteuid const char static filename static arg static mask struct ustat static ubuf static getppid static setsid static egid sigset_t static set struct timeval struct timezone static tz fd_set fd_set fd_set struct timeval static timeout const char char static bufsiz const char static swapflags void static offset const char static length static mode static who const char struct statfs static buf unsigned unsigned num
Definition: sflib.h:126
static const ut32 RzAsmLm32Imm26SignBitPos
Definition: lm32_isa.h:295
static const ut32 RzAsmLm32InstrImm5InvalidBitsMask
Definition: lm32_isa.h:297
static ut32 extract_imm26(ut32 instr_dword)
Definition: lm32_isa.h:328
static ut8 extract_opcode(ut32 instr_dword)
Definition: lm32_isa.h:304
#define RzAsmLm32OpcodeNumber
Definition: lm32_isa.h:180
static const ut32 RzAsmLm32InstrWcsrInvalidBitsMask
Definition: lm32_isa.h:300
static const ut32 RzAsmLm32InstrTwoRegsInvalidBitsMask
Definition: lm32_isa.h:299
static const RzAsmLm32Csr RzAsmLm32Csrs[RzAsmLm32CsrNumber]
Definition: lm32_isa.h:20
@ reg_imm16_signextend
Definition: lm32_isa.h:95
@ reg_imm16_zeroextend
Definition: lm32_isa.h:97
@ two_regs
Definition: lm32_isa.h:101
@ raise_instr
Definition: lm32_isa.h:99
@ csr_reg
Definition: lm32_isa.h:104
@ imm26
Definition: lm32_isa.h:105
@ one_reg
Definition: lm32_isa.h:100
@ reg_imm16_shift2_signextend
Definition: lm32_isa.h:96
@ three_regs
Definition: lm32_isa.h:102
@ reg_imm5
Definition: lm32_isa.h:98
@ reserved
Definition: lm32_isa.h:94
@ reg_csr
Definition: lm32_isa.h:103
static ut8 extract_reg_w(ut32 instr_dword)
Definition: lm32_isa.h:316
static ut8 extract_imm5(ut32 instr_dword)
Definition: lm32_isa.h:320
static ut8 extract_reg_v(ut32 instr_dword)
Definition: lm32_isa.h:312
static const RzAsmLm32Opcode RzAsmLm32OpcodeList[RzAsmLm32OpcodeNumber]
Definition: lm32_isa.h:182
#define RzAsmLm32RegNumber
Definition: lm32_isa.h:49
static const ut32 RzAsmLm32InstrOneRegInvalidBitsMask
Definition: lm32_isa.h:298
@ lm32_op_or
Definition: lm32_isa.h:155
@ lm32_op_addi
Definition: lm32_isa.h:122
@ lm32_op_xnor
Definition: lm32_isa.h:150
@ lm32_op_raise
Definition: lm32_isa.h:152
@ lm32_op_b
Definition: lm32_isa.h:157
@ lm32_op_orhi
Definition: lm32_isa.h:139
#define RzAsmLm32CsrNumber
Definition: lm32_isa.h:18
static const RzAsmLm32Reg RzAsmLm32Regs[RzAsmLm32RegNumber]
Definition: lm32_isa.h:51
static ut8 extract_reg_u(ut32 instr_dword)
Definition: lm32_isa.h:308
static ut16 extract_imm16(ut32 instr_dword)
Definition: lm32_isa.h:324
static const ut32 RzAsmLm32Imm16SignBitPos
Definition: lm32_isa.h:293
@ RZ_LIB_TYPE_ASM
Definition: rz_lib.h:72
RZ_API const char * rz_strbuf_set(RzStrBuf *sb, const char *s)
Definition: strbuf.c:153
RZ_API char * rz_strbuf_get(RzStrBuf *sb)
Definition: strbuf.c:321
#define RZ_SYS_ENDIAN_BIG
Definition: rz_types.h:527
#define st32
Definition: rz_types_base.h:12
#define RZ_VERSION
Definition: rz_version.h:8
#define a(i)
Definition: sha256.c:41
Definition: z80asm.h:102
char src1_reg_str[RzAsmLm32RegNameLength]
Definition: lm32_isa.h:267
char dest_reg_str[RzAsmLm32RegNameLength]
Definition: lm32_isa.h:261
RzAsmLm32Opcode op_decode
Definition: lm32_isa.h:258
char csr_reg_str[RzAsmLm32RegNameLength]
Definition: lm32_isa.h:270
char src0_reg_str[RzAsmLm32RegNameLength]
Definition: lm32_isa.h:264
RzAsmLm32InstructionType type
Definition: lm32_isa.h:176
char name[RzAsmLm32OpNameLength]
Definition: lm32_isa.h:177
const char * name
Definition: rz_asm.h:130
const char * version
Definition: rz_asm.h:133
Definition: dis.c:32