Rizin
unix-like reverse engineering framework and cli tools
riscv.c
Go to the documentation of this file.
1 // SPDX-FileCopyrightText: 2011-2015 Free Software Foundation, Inc.
2 // SPDX-License-Identifier: GPL-3.0-or-later
3 
4 /* RISC-V disassembler
5  Copyright 2011-2015 Free Software Foundation, Inc.
6  Contributed by Andrew Waterman (waterman@cs.berkeley.edu) at UC Berkeley.
7  Based on MIPS target.
8  This file is part of the GNU opcodes library.
9  This library is free software; you can redistribute it and/or modify
10  it under the terms of the GNU General Public License as published by
11  the Free Software Foundation; either version 3, or (at your option)
12  any later version.
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  You should have received a copy of the GNU General Public License
18  along with this program; see the file COPYING3. If not,
19  see <http://www.gnu.org/licenses/>.
20 
21  - Code changes to make r2 friendly (qnix@0x80.org)
22 */
23 
24 #include <stdio.h>
25 #include <stdlib.h>
26 #include <stdint.h>
27 #include <ctype.h>
28 #include <stdarg.h>
29 #include <rz_asm.h>
30 #include <rz_lib.h>
31 #include <string.h>
32 
33 #include "riscv-opc.h"
34 #include "riscv.h"
35 
36 #define ARRAY_SIZE(a) (sizeof(a) / sizeof(*a))
37 
38 // TODO : an conf to chose between abi or numeric
39 static const char * const *riscv_gpr_names = riscv_gpr_names_abi;
40 static const char * const *riscv_fpr_names = riscv_fpr_names_abi;
41 static int init = 0;
42 
43 static void arg_p (char *buf, unsigned long val, const char* const* array, size_t size) {
44  const char *s = val >= size || array[val] ? array[val] : "unknown";
45  sprintf (buf+strlen (buf), "%s", s);
46 }
47 
48 /* Print insn arguments for 32/64-bit code. */
49 static void get_insn_args (char *buf, const char *d, insn_t l, uint64_t pc) {
50  int rs1 = (l >> OP_SH_RS1) & OP_MASK_RS1;
51  int rd = (l >> OP_SH_RD) & OP_MASK_RD;
52  uint64_t target;
53 
54  if (*d != '\0') {
55  sprintf (buf+strlen (buf), " ");
56  }
57 
58  for (; *d != '\0'; d++) {
59  switch (*d) {
60  /* Xcustom */
61  case '^':
62  switch (*++d) {
63  case 'd':
64  sprintf (buf+strlen (buf), "%d", rd);
65  break;
66  case 's':
67  sprintf (buf+strlen (buf), "%d", rs1);
68  break;
69  case 't':
70  sprintf (buf+strlen (buf), "%d", (int) EXTRACT_OPERAND (RS2, l));
71  break;
72  case 'j':
73  sprintf (buf+strlen (buf), "%d", (int) EXTRACT_OPERAND (CUSTOM_IMM, l));
74  break;
75  }
76  break;
77 
78  case 'C': /* RVC */
79  switch (*++d) {
80  case 's': /* RS1 x8-x15 */
81  case 'w': /* RS1 x8-x15 */
82  sprintf (buf+strlen (buf), "%s",
83  riscv_gpr_names[EXTRACT_OPERAND (CRS1S, l) + 8]);
84  break;
85  case 't': /* RS2 x8-x15 */
86  case 'x': /* RS2 x8-x15 */
87  sprintf (buf+strlen (buf), "%s",
88  riscv_gpr_names[EXTRACT_OPERAND (CRS2S, l) + 8]);
89  break;
90  case 'U': /* RS1, constrained to equal RD */
91  sprintf (buf+strlen (buf), "%s", riscv_gpr_names[rd]);
92  break;
93  case 'c': /* RS1, constrained to equal sp */
94  sprintf (buf+strlen (buf), "%s", riscv_gpr_names[X_SP]);
95  break;
96  case 'V': /* RS2 */
97  sprintf (buf+strlen (buf), "%s",
98  riscv_gpr_names[EXTRACT_OPERAND (CRS2, l)]);
99  break;
100  case 'i':
101  sprintf (buf+strlen (buf), "%d", (int)EXTRACT_RVC_SIMM3 (l));
102  break;
103  case 'j':
104  sprintf (buf+strlen (buf), "%d", (int)EXTRACT_RVC_IMM (l));
105  break;
106  case 'k':
107  sprintf (buf+strlen (buf), "%d", (int)EXTRACT_RVC_LW_IMM (l));
108  break;
109  case 'l':
110  sprintf (buf+strlen (buf), "%d", (int)EXTRACT_RVC_LD_IMM (l));
111  break;
112  case 'm':
113  sprintf (buf+strlen (buf), "%d", (int)EXTRACT_RVC_LWSP_IMM (l));
114  break;
115  case 'n':
116  sprintf (buf+strlen (buf), "%d", (int)EXTRACT_RVC_LDSP_IMM (l));
117  break;
118  case 'K':
119  sprintf (buf+strlen (buf), "%d", (int)EXTRACT_RVC_ADDI4SPN_IMM (l));
120  break;
121  case 'L':
122  sprintf (buf+strlen (buf), "%d", (int)EXTRACT_RVC_ADDI16SP_IMM (l));
123  break;
124  case 'M':
125  sprintf (buf+strlen (buf), "%d", (int)EXTRACT_RVC_SWSP_IMM (l));
126  break;
127  case 'N':
128  sprintf (buf+strlen (buf), "%d", (int)EXTRACT_RVC_SDSP_IMM (l));
129  break;
130  case 'p':
131  target = EXTRACT_RVC_B_IMM (l) + pc;
132  sprintf (buf+strlen (buf), "0x%"PFMT64x, (ut64) target);
133  break;
134  case 'a':
135  target = EXTRACT_RVC_J_IMM (l) + pc;
136  sprintf (buf+strlen (buf), "0x%"PFMT64x, (ut64)target);
137  break;
138  case 'u':
139  sprintf (buf+strlen (buf), "0x%x",
140  (int) (EXTRACT_RVC_IMM (l) & (RISCV_BIGIMM_REACH-1)));
141  break;
142  case '>':
143  sprintf (buf+strlen (buf), "0x%x", (int) EXTRACT_RVC_IMM (l) & 0x3f);
144  break;
145  case '<':
146  sprintf (buf+strlen (buf), "0x%x", (int) EXTRACT_RVC_IMM (l) & 0x1f);
147  break;
148  case 'T': /* floating-point RS2 */
149  sprintf (buf+strlen (buf), "%s",
150  riscv_fpr_names[EXTRACT_OPERAND (CRS2, l)]);
151  break;
152  case 'D': /* floating-point RS2 x8-x15 */
153  sprintf (buf+strlen (buf), "%s",
154  riscv_fpr_names[EXTRACT_OPERAND (CRS2S, l) + 8]);
155  break;
156  }
157  break;
158 
159  case ',':
160  sprintf (buf+strlen (buf), "%c ", *d);
161  break;
162  case '(':
163  case ')':
164  case '[':
165  case ']':
166  sprintf (buf+strlen (buf), "%c", *d);
167  break;
168  case '0':
169  /* Only print constant 0 if it is the last argument */
170  if (!d[1]) {
171  sprintf (buf+strlen (buf), "0");
172  }
173  break;
174 
175  case 'b':
176  case 's':
177  sprintf (buf+strlen (buf), "%s", riscv_gpr_names[rs1]);
178  break;
179 
180  case 't':
181  sprintf (buf+strlen (buf), "%s",
183  break;
184 
185  case 'u':
186  sprintf (buf+strlen (buf), "0x%x",
187  (unsigned) EXTRACT_UTYPE_IMM (l) >> RISCV_IMM_BITS);
188  break;
189 
190  case 'm':
191  arg_p (buf, EXTRACT_OPERAND (RM, l),
193  break;
194 
195  case 'P':
196  arg_p (buf, EXTRACT_OPERAND (PRED, l),
198  break;
199 
200  case 'Q':
201  arg_p (buf, EXTRACT_OPERAND (SUCC, l),
203  break;
204  case 'o':
205  case 'j':
206  sprintf (buf+strlen (buf), "%d", (int) EXTRACT_ITYPE_IMM (l));
207  break;
208  case 'q':
209  sprintf (buf+strlen (buf), "%d", (int) EXTRACT_STYPE_IMM (l));
210  break;
211  case 'a':
212  target = EXTRACT_UJTYPE_IMM (l) + pc;
213  sprintf (buf+strlen (buf), "0x%"PFMT64x, (ut64)target);
214  break;
215  case 'p':
216  target = EXTRACT_SBTYPE_IMM (l) + pc;
217  sprintf (buf+strlen (buf), "0x%"PFMT64x, (ut64)target);
218  break;
219  case 'd':
220  sprintf (buf+strlen (buf), "%s", riscv_gpr_names[rd]);
221  break;
222  case 'z':
223  sprintf (buf+strlen (buf), "%s", riscv_gpr_names[0]);
224  break;
225  case '>':
226  sprintf (buf+strlen (buf), "0x%x", (int) EXTRACT_OPERAND (SHAMT, l));
227  break;
228  case '<':
229  sprintf (buf+strlen (buf), "0x%x", (int) EXTRACT_OPERAND (SHAMTW, l));
230  break;
231  case 'S':
232  case 'U':
233  sprintf (buf+strlen (buf), "%s", riscv_fpr_names[rs1]);
234  break;
235  case 'T':
236  sprintf (buf+strlen (buf), "%s", riscv_fpr_names[EXTRACT_OPERAND (RS2, l)]);
237  break;
238  case 'D':
239  sprintf (buf+strlen (buf), "%s", riscv_fpr_names[rd]);
240  break;
241  case 'R':
242  sprintf (buf+strlen (buf), "%s", riscv_fpr_names[EXTRACT_OPERAND (RS3, l)]);
243  break;
244  case 'E':
245  {
246  const char* csr_name = NULL;
247  unsigned int csr = EXTRACT_OPERAND (CSR, l);
248  switch (csr)
249  {
250 #define DECLARE_CSR(name, num) case num: csr_name = #name; break;
251 #include "riscv-opc.h"
252 #undef DECLARE_CSR
253  }
254  if (csr_name) {
255  sprintf (buf+strlen (buf), "%s", csr_name);
256  } else {
257  sprintf (buf+strlen (buf), "0x%x", csr);
258  }
259  break;
260  }
261  case 'Z':
262  sprintf (buf+strlen (buf), "%d", rs1);
263  break;
264  default:
265  /* xgettext:c-format */
266  sprintf (buf+strlen (buf), "# internal error, undefined modifier (%c)",
267  *d);
268  return;
269  }
270  }
271 }
272 
273 static struct riscv_opcode *get_opcode (insn_t word) {
274  struct riscv_opcode *op;
275  static const struct riscv_opcode *riscv_hash[OP_MASK_OP + 1] = {0};
276 
277 #define OP_HASH_IDX(i) ((i) & (riscv_insn_length (i) == 2 ? 3 : OP_MASK_OP))
278 
279  if (!init) {
280  for (op=riscv_opcodes; op < &riscv_opcodes[NUMOPCODES]; op++) {
281  if (!riscv_hash[OP_HASH_IDX (op->match)]) {
282  riscv_hash[OP_HASH_IDX (op->match)] = op;
283  }
284  }
285  init = 1;
286  }
287 
288  return (struct riscv_opcode *)riscv_hash[OP_HASH_IDX (word)];
289 }
290 
291 static int riscv_disassemble(RzAsm *a, RzAsmOp *rop, insn_t word, int xlen, int len) {
292  const bool no_alias = false;
293  const struct riscv_opcode *op = get_opcode (word);
294  if (!op) {
295  return -1;
296  }
297  for (; op < &riscv_opcodes[NUMOPCODES]; op++) {
298  if ( !(op->match_func)(op, word) ) {
299  continue;
300  }
301  if (no_alias && (op->pinfo & INSN_ALIAS)) {
302  continue;
303  }
304  if (isdigit ((ut8)op->subset[0]) && atoi (op->subset) != xlen ) {
305  continue;
306  }
307  if (op->name && op->args) {
308  rz_asm_op_set_asm (rop, op->name);
309  get_insn_args (rz_asm_op_get_asm (rop), op->args, word, a->pc);
310  return 0;
311  }
312  rz_asm_op_set_asm (rop, sdb_fmt ("invalid word(%"PFMT64x")", (ut64)word));
313  return -1;
314  }
315  return 0;
316 }
317 
318 static int riscv_dis(RzAsm *a, RzAsmOp *rop, const ut8 *buf, ut64 len) {
319  insn_t insn = {0};
320  if (len < 2) {
321  return -1;
322  }
323  memcpy (&insn, buf, RZ_MIN (sizeof (insn), len));
324  int insn_len = riscv_insn_length(insn);
325  if (len < insn_len) {
326  return -1;
327  }
328  riscv_disassemble (a, rop, insn, a->bits, len);
329  return insn_len;
330 }
size_t len
Definition: 6502dis.c:15
ut8 op
Definition: 6502dis.c:13
#define rd()
RZ_API void rz_asm_op_set_asm(RzAsmOp *op, const char *str)
Definition: aop.c:53
RZ_API char * rz_asm_op_get_asm(RzAsmOp *op)
Definition: aop.c:37
ut16 val
Definition: armass64_const.h:6
#define NULL
Definition: cris-opc.c:27
RZ_API char * sdb_fmt(const char *fmt,...)
Definition: fmt.c:26
#define NUMOPCODES
Definition: hppa.h:1079
voidpf void uLong size
Definition: ioapi.h:138
voidpf void * buf
Definition: ioapi.h:138
sprintf
Definition: kernel.h:365
uint8_t ut8
Definition: lh5801.h:11
memcpy(mem, inblock.get(), min(CONTAINING_RECORD(inblock.get(), MEMBLOCK, data) ->size, size))
#define OP_MASK_OP
Definition: mips.h:64
#define OP_MASK_RD
Definition: mips.h:84
#define OP_SH_RD
Definition: mips.h:85
#define RS2(x)
Definition: sparc.h:203
static const char *const riscv_gpr_names_abi[NGPR]
Definition: riscv-opc.c:39
static const char *const riscv_fpr_names_abi[NFPR]
Definition: riscv-opc.c:54
static struct riscv_opcode * riscv_opcodes
Definition: riscv-opc.c:685
static const char *const * riscv_fpr_names
Definition: riscv.c:40
#define ARRAY_SIZE(a)
Definition: riscv.c:36
static int riscv_dis(RzAsm *a, RzAsmOp *rop, const ut8 *buf, ut64 len)
Definition: riscv.c:318
static void arg_p(char *buf, unsigned long val, const char *const *array, size_t size)
Definition: riscv.c:43
static void get_insn_args(char *buf, const char *d, insn_t l, uint64_t pc)
Definition: riscv.c:49
static int init
Definition: riscv.c:41
static int riscv_disassemble(RzAsm *a, RzAsmOp *rop, insn_t word, int xlen, int len)
Definition: riscv.c:291
static const char *const * riscv_gpr_names
Definition: riscv.c:39
static struct riscv_opcode * get_opcode(insn_t word)
Definition: riscv.c:273
#define OP_HASH_IDX(i)
#define EXTRACT_RVC_LD_IMM(x)
Definition: riscv.h:89
#define EXTRACT_RVC_J_IMM(x)
Definition: riscv.h:101
#define EXTRACT_RVC_LDSP_IMM(x)
Definition: riscv.h:93
#define EXTRACT_SBTYPE_IMM(x)
Definition: riscv.h:71
#define EXTRACT_STYPE_IMM(x)
Definition: riscv.h:69
#define X_SP
Definition: riscv.h:241
#define EXTRACT_RVC_IMM(x)
Definition: riscv.h:77
#define EXTRACT_RVC_SWSP_IMM(x)
Definition: riscv.h:95
#define EXTRACT_UTYPE_IMM(x)
Definition: riscv.h:73
#define RISCV_BIGIMM_REACH
Definition: riscv.h:190
#define EXTRACT_RVC_SDSP_IMM(x)
Definition: riscv.h:97
static const char *const riscv_rm[8]
Definition: riscv.h:47
#define EXTRACT_RVC_LWSP_IMM(x)
Definition: riscv.h:91
#define OP_SH_RS1
Definition: riscv.h:204
#define EXTRACT_UJTYPE_IMM(x)
Definition: riscv.h:75
#define OP_MASK_RS1
Definition: riscv.h:203
#define EXTRACT_RVC_B_IMM(x)
Definition: riscv.h:99
#define EXTRACT_ITYPE_IMM(x)
Definition: riscv.h:67
#define EXTRACT_OPERAND(FIELD, INSN)
Definition: riscv.h:264
#define EXTRACT_RVC_SIMM3(x)
Definition: riscv.h:81
#define INSN_ALIAS
Definition: riscv.h:297
#define EXTRACT_RVC_ADDI4SPN_IMM(x)
Definition: riscv.h:83
#define EXTRACT_RVC_ADDI16SP_IMM(x)
Definition: riscv.h:85
#define EXTRACT_RVC_LW_IMM(x)
Definition: riscv.h:87
#define RISCV_IMM_BITS
Definition: riscv.h:187
static const char *const riscv_pred_succ[16]
Definition: riscv.h:52
static unsigned int riscv_insn_length(insn_t insn)
Definition: riscv.h:33
static RzSocket * s
Definition: rtr.c:28
#define PFMT64x
Definition: rz_types.h:393
#define RZ_MIN(x, y)
#define isdigit(c)
Definition: safe-ctype.h:131
unsigned long uint64_t
Definition: sftypes.h:28
#define d(i)
Definition: sha256.c:44
#define a(i)
Definition: sha256.c:41
Definition: dis.c:32
ut64(WINAPI *w32_GetEnabledXStateFeatures)()