1 /* radare - LGPL - Copyright 2015-2019 - qnix */
2 
3 #include <string.h>
4 #include <r_types.h>
5 #include <r_lib.h>
6 #include <r_asm.h>
7 #include <r_anal.h>
8 #include "../../asm/arch/riscv/riscv-opc.c"
9 #include "../../asm/arch/riscv/riscv.h"
10 #define ARRAY_SIZE(a) (sizeof(a) / sizeof(*a))
11 #define RISCVARGSMAX (8)
12 #define RISCVARGSIZE (64)
13 #define RISCVARGN(x) ((x)->arg[(x)->num++])
14 
15 static bool init = false;
16 static const char * const *riscv_gpr_names = riscv_gpr_names_abi;
17 static const char * const *riscv_fpr_names = riscv_fpr_names_abi;
18 
19 typedef struct riscv_args {
20 	int num;
21 	char arg[RISCVARGSMAX][RISCVARGSIZE];
22 } riscv_args_t;
23 
24 #define is_any(...) _is_any(o->name, __VA_ARGS__, NULL)
_is_any(const char * str,...)25 static bool _is_any(const char *str, ...) {
26 	char *cur;
27 	va_list va;
28 	va_start (va, str);
29 	while (true) {
30 		cur = va_arg (va, char *);
31 		if (!cur) {
32 			break;
33 		}
34 		if (!strcmp (str, cur)) {
35 			va_end (va);
36 			return true;
37 		}
38 	}
39 	va_end (va);
40 	return false;
41 }
42 
arg_p2(char * buf,unsigned long val,const char * const * array,size_t size)43 static void arg_p2(char *buf, unsigned long val, const char* const* array, size_t size) {
44 	const char *s = (val >= size || array[val]) ? array[val] : "unknown";
45 	snprintf (buf, RISCVARGSIZE, "%s", s);
46 }
47 
get_opcode(insn_t word)48 static struct riscv_opcode *get_opcode(insn_t word) {
49 	struct riscv_opcode *op = NULL;
50 	static const struct riscv_opcode *riscv_hash[OP_MASK_OP + 1] = {0};
51 
52 #define OP_HASH_IDX(i) ((i) & (riscv_insn_length (i) == 2 ? 3 : OP_MASK_OP))
53 
54 	if (!init) {
55 		size_t i;
56 		for (i=0;i<OP_MASK_OP+1; i++) {
57 			riscv_hash[i] = 0;
58 		}
59 		for (op=riscv_opcodes; op <= &riscv_opcodes[NUMOPCODES - 1]; op++) {
60 			if (!riscv_hash[OP_HASH_IDX (op->match)]) {
61 				riscv_hash[OP_HASH_IDX (op->match)] = op;
62 			}
63 		}
64 		init = true;
65 	}
66 	return (struct riscv_opcode *)riscv_hash[OP_HASH_IDX (word)];
67 }
68 
69 /* Print insn arguments for 32/64-bit code.  */
get_insn_args(riscv_args_t * args,const char * d,insn_t l,uint64_t pc)70 static void get_insn_args(riscv_args_t *args, const char *d, insn_t l, uint64_t pc) {
71 	int rs1 = (l >> OP_SH_RS1) & OP_MASK_RS1;
72 	int rd = (l >> OP_SH_RD) & OP_MASK_RD;
73 	uint64_t target;
74 	args->num = 0;
75 
76 	for (; *d != '\0' && args->num < RISCVARGSMAX; d++) {
77 		switch (*d) {
78 			/* Xcustom */
79 		case '^':
80 			switch (*++d) {
81 			case 'd':
82 				snprintf (RISCVARGN(args), RISCVARGSIZE , "%d", rd);
83 				break;
84 			case 's':
85 				snprintf (RISCVARGN(args), RISCVARGSIZE , "%d", rs1);
86 				break;
87 			case 't':
88 				snprintf (RISCVARGN(args), RISCVARGSIZE , "%d", (int) EXTRACT_OPERAND (RS2, l));
89 				break;
90 			case 'j':
91 				snprintf (RISCVARGN(args), RISCVARGSIZE , "%d", (int) EXTRACT_OPERAND (CUSTOM_IMM, l));
92 				break;
93 			}
94 			break;
95 
96 		case 'C': /* RVC */
97 			switch (*++d) {
98 			case 's': /* RS1 x8-x15 */
99 			case 'w': /* RS1 x8-x15 */
100 				snprintf (RISCVARGN(args), RISCVARGSIZE , "%s",
101 				  riscv_gpr_names[EXTRACT_OPERAND (CRS1S, l) + 8]);
102 				break;
103 			case 't': /* RS2 x8-x15 */
104 			case 'x': /* RS2 x8-x15 */
105 				snprintf (RISCVARGN(args), RISCVARGSIZE , "%s",
106 				  riscv_gpr_names[EXTRACT_OPERAND (CRS2S, l) + 8]);
107 				break;
108 			case 'U': /* RS1, constrained to equal RD in CI format*/
109 				snprintf (RISCVARGN(args), RISCVARGSIZE , "%s", riscv_gpr_names[rd]);
110 				break;
111 			case 'c': /* RS1, constrained to equal sp */
112 				snprintf (RISCVARGN(args), RISCVARGSIZE , "%s", riscv_gpr_names[X_SP]);
113 				break;
114 			case 'V': /* RS2 */
115 				snprintf (RISCVARGN(args), RISCVARGSIZE , "%s",
116 				  riscv_gpr_names[EXTRACT_OPERAND (CRS2, l)]);
117 				break;
118 			case 'i':
119 				snprintf (RISCVARGN(args), RISCVARGSIZE , "%d", (int)EXTRACT_RVC_SIMM3 (l));
120 				break;
121 			case 'j':
122 				snprintf (RISCVARGN(args), RISCVARGSIZE , "%d", (int)EXTRACT_RVC_IMM (l));
123 				break;
124 			case 'k':
125 				snprintf (RISCVARGN(args), RISCVARGSIZE , "%d", (int)EXTRACT_RVC_LW_IMM (l));
126 				break;
127 			case 'l':
128 				snprintf (RISCVARGN(args), RISCVARGSIZE , "%d", (int)EXTRACT_RVC_LD_IMM (l));
129 				break;
130 			case 'm':
131 				snprintf (RISCVARGN(args), RISCVARGSIZE , "%d", (int)EXTRACT_RVC_LWSP_IMM (l));
132 				break;
133 			case 'n':
134 				snprintf (RISCVARGN(args), RISCVARGSIZE , "%d", (int)EXTRACT_RVC_LDSP_IMM (l));
135 				break;
136 			case 'K':
137 				snprintf (RISCVARGN(args), RISCVARGSIZE , "%d", (int)EXTRACT_RVC_ADDI4SPN_IMM (l));
138 				break;
139 			case 'L':
140 				snprintf (RISCVARGN(args), RISCVARGSIZE , "%d", (int)EXTRACT_RVC_ADDI16SP_IMM (l));
141 				break;
142 			case 'M':
143 				snprintf (RISCVARGN(args), RISCVARGSIZE , "%d", (int)EXTRACT_RVC_SWSP_IMM (l));
144 				break;
145 			case 'N':
146 				snprintf (RISCVARGN(args), RISCVARGSIZE , "%d", (int)EXTRACT_RVC_SDSP_IMM (l));
147 				break;
148 			case 'p':
149 				target = EXTRACT_RVC_B_IMM (l) + pc;
150 				snprintf (RISCVARGN(args), RISCVARGSIZE , "0x%"PFMT64x, (ut64) target);
151 				break;
152 			case 'a':
153 				target = EXTRACT_RVC_J_IMM (l) + pc;
154 				snprintf (RISCVARGN(args), RISCVARGSIZE , "0x%"PFMT64x, (ut64)target);
155 				break;
156 			case 'u':
157 				snprintf (RISCVARGN(args), RISCVARGSIZE , "0x%x",
158 				  (int) (EXTRACT_RVC_IMM (l) & (RISCV_BIGIMM_REACH-1)));
159 				break;
160 			case '>':
161 				snprintf (RISCVARGN(args), RISCVARGSIZE , "0x%x", (int) EXTRACT_RVC_IMM (l) & 0x3f);
162 				break;
163 			case '<':
164 				snprintf (RISCVARGN(args), RISCVARGSIZE , "0x%x", (int) EXTRACT_RVC_IMM (l) & 0x1f);
165 				break;
166 			case 'T': /* floating-point RS2 */
167 				snprintf (RISCVARGN(args), RISCVARGSIZE , "%s",
168 				  riscv_fpr_names[EXTRACT_OPERAND (CRS2, l)]);
169 				break;
170 			case 'D': /* floating-point RS2 x8-x15 */
171 				snprintf (RISCVARGN(args), RISCVARGSIZE , "%s",
172 				  riscv_fpr_names[EXTRACT_OPERAND (CRS2S, l) + 8]);
173 				break;
174 			}
175 			break;
176 
177 		case ',':
178 		case '(':
179 		case ')':
180 		case '[':
181 		case ']':
182 			break;
183 		case '0':
184 			/* Only print constant 0 if it is the last argument */
185 			if (!d[1]) {
186 				snprintf (RISCVARGN(args), RISCVARGSIZE , "0");
187 			}
188 			break;
189 
190 		case 'b':
191 		case 's':
192 			snprintf (RISCVARGN(args), RISCVARGSIZE , "%s", riscv_gpr_names[rs1]);
193 			break;
194 
195 		case 't':
196 			snprintf (RISCVARGN(args), RISCVARGSIZE , "%s",
197 			  riscv_gpr_names[EXTRACT_OPERAND (RS2, l)]);
198 			break;
199 
200 		case 'u':
201 			snprintf (RISCVARGN(args), RISCVARGSIZE , "0x%x",
202 			  (unsigned) EXTRACT_UTYPE_IMM (l) >> RISCV_IMM_BITS);
203 			break;
204 
205 		case 'm':
206 			arg_p2 (RISCVARGN(args), EXTRACT_OPERAND (RM, l),
207 			  riscv_rm, ARRAY_SIZE (riscv_rm));
208 			break;
209 
210 		case 'P':
211 			arg_p2 (RISCVARGN(args), EXTRACT_OPERAND (PRED, l),
212 			  riscv_pred_succ, ARRAY_SIZE (riscv_pred_succ));
213 			break;
214 
215 		case 'Q':
216 			arg_p2 (RISCVARGN(args), EXTRACT_OPERAND (SUCC, l),
217 			  riscv_pred_succ, ARRAY_SIZE (riscv_pred_succ));
218 			break;
219 		case 'o':
220 		case 'j':
221 			snprintf (RISCVARGN(args), RISCVARGSIZE , "%d", (int) EXTRACT_ITYPE_IMM (l));
222 			break;
223 		case 'q':
224 			snprintf (RISCVARGN(args), RISCVARGSIZE , "%d", (int) EXTRACT_STYPE_IMM (l));
225 			break;
226 		case 'a':
227 			target = EXTRACT_UJTYPE_IMM (l) + pc;
228 			snprintf (RISCVARGN(args), RISCVARGSIZE , "0x%"PFMT64x, (ut64)target);
229 			break;
230 		case 'p':
231 			target = EXTRACT_SBTYPE_IMM (l) + pc;
232 			snprintf (RISCVARGN(args), RISCVARGSIZE , "0x%"PFMT64x, (ut64)target);
233 			break;
234 		case 'd':
235 			snprintf (RISCVARGN(args), RISCVARGSIZE , "%s", riscv_gpr_names[rd]);
236 			break;
237 		case 'z':
238 			snprintf (RISCVARGN(args), RISCVARGSIZE , "%s", riscv_gpr_names[0]);
239 			break;
240 		case '>':
241 			snprintf (RISCVARGN(args), RISCVARGSIZE , "0x%x", (int) EXTRACT_OPERAND (SHAMT, l));
242 			break;
243 		case '<':
244 			snprintf (RISCVARGN(args), RISCVARGSIZE , "0x%x", (int) EXTRACT_OPERAND (SHAMTW, l));
245 			break;
246 		case 'S':
247 		case 'U':
248 			snprintf (RISCVARGN(args), RISCVARGSIZE , "%s", riscv_fpr_names[rs1]);
249 			break;
250 		case 'T':
251 			snprintf (RISCVARGN(args), RISCVARGSIZE , "%s", riscv_fpr_names[EXTRACT_OPERAND (RS2, l)]);
252 			break;
253 		case 'D':
254 			snprintf (RISCVARGN(args), RISCVARGSIZE , "%s", riscv_fpr_names[rd]);
255 			break;
256 		case 'R':
257 			snprintf (RISCVARGN(args), RISCVARGSIZE , "%s", riscv_fpr_names[EXTRACT_OPERAND (RS3, l)]);
258 			break;
259 		case 'E':
260 			{
261 				const char* csr_name = NULL;
262 				unsigned int csr = EXTRACT_OPERAND (CSR, l);
263 				switch (csr)
264 				 {
265 #define DECLARE_CSR(name, num) case num: csr_name = #name; break;
266 #include "../../asm/arch/riscv/riscv-opc.h"
267 #undef DECLARE_CSR
268 				 }
269 				if (csr_name) {
270 					snprintf (RISCVARGN(args), RISCVARGSIZE , "%s", csr_name);
271 				} else {
272 					snprintf (RISCVARGN(args), RISCVARGSIZE , "0x%x", csr);
273 				}
274 				break;
275 			}
276 		case 'Z':
277 			snprintf (RISCVARGN(args), RISCVARGSIZE , "%d", rs1);
278 			break;
279 		default:
280 			/* xgettext:c-format */
281 			snprintf (RISCVARGN(args), RISCVARGSIZE , "# internal error, undefined modifier (%c)",
282 			  *d);
283 			return;
284 		}
285 	}
286 }
287 
arg_n(riscv_args_t * args,int n)288 static const char* arg_n(riscv_args_t* args, int n) {
289 	if (n >= args->num || !strcmp (args->arg[n], "zero")) {
290 		return "0";
291 	}
292 	return args->arg[n];
293 }
294 
riscv_op(RAnal * anal,RAnalOp * op,ut64 addr,const ut8 * data,int len,RAnalOpMask mask)295 static int riscv_op(RAnal *anal, RAnalOp *op, ut64 addr, const ut8 *data, int len, RAnalOpMask mask) {
296 	const int no_alias = 1;
297 	riscv_args_t args = {0};
298 	ut64 word = 0;
299 	int xlen = anal->bits;
300 	op->size = 4;
301 	op->addr = addr;
302 	op->type = R_ANAL_OP_TYPE_UNK;
303 
304 	if (len >= sizeof (ut64)) {
305 		word = r_read_ble64 (data, anal->big_endian);
306 	} else if (len >= sizeof (ut32)) {
307 		word = r_read_ble16 (data, anal->big_endian);
308 	} else {
309 		op->type = R_ANAL_OP_TYPE_ILL;
310 		return -1;
311 	}
312 
313 	struct riscv_opcode *o = get_opcode (word);
314 	if (word == UT64_MAX) {
315 		op->type = R_ANAL_OP_TYPE_ILL;
316 		return -1;
317 	}
318 	if (!o || !o->name) {
319 		return op->size;
320 	}
321 	if (mask & R_ANAL_OP_MASK_DISASM) {
322 		op->mnemonic = strdup (o->name);
323 	}
324 
325 	for (; o <= &riscv_opcodes[NUMOPCODES - 1]; o++) {
326 		if (no_alias && (o->pinfo & INSN_ALIAS)) {
327 			continue;
328 		}
329 		if (isdigit ((ut8)(o->subset[0])) && atoi (o->subset) != xlen) {
330 			continue;
331 		}
332 		if (o->match_func && !(o->match_func)(o, word)) {
333 			continue;
334 		}
335 		break;
336 	}
337 
338 	if (o > &riscv_opcodes[NUMOPCODES - 1]) {
339 		return -1;
340 	}
341 
342 	if (o->args) {
343 		const char *name = o->name;
344 		// Test for compressed instruction
345 		if (!strncmp ("c.", o->name, 2)) {
346 			name += 2;
347 			op->size = 2;
348 		}
349 #define ARG(x) (arg_n (&args, (x)))
350 		get_insn_args (&args, o->args, word, addr);
351 		if (!strcmp (name, "nop")) {
352 			esilprintf (op, ",");
353 		}
354 		// math
355 		else if (!strncmp (name, "addi16sp", 8)) {
356 			esilprintf (op, "%s,sp,+,%s,=", ARG (1), ARG (0));
357 			if (!strcmp (ARG (0), riscv_gpr_names[X_SP])) {
358 				op->stackop = R_ANAL_STACK_INC;
359 				op->stackptr = r_num_math (NULL, ARG (1));
360 			}
361 		} else if (!strncmp (name, "addiw", 5)) {
362 			r_strbuf_appendf (&op->esil, "%s,0xffffffff,%s,&,", ARG (2), ARG (1));
363 			r_strbuf_appendf (&op->esil, "+,%s,=,", ARG (0));
364 			r_strbuf_appendf (&op->esil, "32,%s,~=", ARG (0));
365 			if (!strcmp (ARG (0), riscv_gpr_names[X_SP]) &&
366 				!strcmp (ARG (1), riscv_gpr_names[X_SP])) {
367 				op->stackop = R_ANAL_STACK_INC;
368 				op->stackptr = r_num_math (NULL, ARG (2));
369 			}
370 		} else if (!strncmp (name, "addw", 4)) {
371 			esilprintf (op, "0xffffffff,%s,&,", ARG (2));
372 			r_strbuf_appendf (&op->esil, "0xffffffff,%s,&,", ARG (1));
373 			r_strbuf_appendf (&op->esil, "+,%s,=,", ARG (0));
374 			r_strbuf_appendf (&op->esil, "32,%s,~=", ARG (0));
375 		} else if (!strncmp (name, "add", 3)) {
376 			esilprintf (op, "%s,%s,+,%s,=", ARG (2), ARG (1), ARG (0));
377 			if (name[3] == 'i' && !strcmp (ARG (0), riscv_gpr_names[X_SP]) &&
378 				!strcmp (ARG (1), riscv_gpr_names[X_SP])) {
379 				op->stackop = R_ANAL_STACK_INC;
380 				op->stackptr = -(signed)r_num_math (NULL, ARG (2));
381 			}
382 		} else if (!strncmp (name, "subw", 4)) {
383 			esilprintf (op, "0xffffffff,%s,&,", ARG (2));
384 			r_strbuf_appendf (&op->esil, "0xffffffff,%s,&,", ARG (1));
385 			r_strbuf_appendf (&op->esil, "-,%s,=,", ARG (0));
386 			r_strbuf_appendf (&op->esil, "32,%s,~=", ARG (0));
387 		} else if (!strncmp (name, "sub", 3)) {
388 			esilprintf (op, "%s,%s,-,%s,=", ARG (2), ARG (1), ARG (0));
389 			if (name[3] == 'i' && !strcmp (ARG (0), riscv_gpr_names[X_SP]) &&
390 				!strcmp (ARG (1), riscv_gpr_names[X_SP])) {
391 				op->stackop = R_ANAL_STACK_INC;
392 				op->stackptr = r_num_math (NULL, ARG (2));
393 			}
394 		} else if (!strncmp (name, "mulw", 4)) {
395 			esilprintf (op, "0xffffffff,%s,&,", ARG (2));
396 			r_strbuf_appendf (&op->esil, "0xffffffff,%s,&,", ARG (1));
397 			r_strbuf_appendf (&op->esil, "*,%s,=,", ARG (0));
398 			r_strbuf_appendf (&op->esil, "32,%s,~=", ARG (0));
399 		} else if (!strncmp (name, "mul", 3)) {
400 			esilprintf (op, "%s,%s,*,%s,=", ARG (2), ARG (1), ARG (0));
401 		} else if (!strncmp (name, "div", 3)) {
402 			esilprintf (op, "%s,%s,/,%s,=", ARG (2), ARG (1), ARG (0));
403 		} else if (!strncmp (name, "rem", 3)) {
404 			esilprintf (op, "%s,%s,%%,%s,=", ARG (2), ARG (1), ARG (0));
405 		} else if (!strncmp (name, "xor", 3)) {
406 			esilprintf (op, "%s,%s,^,%s,=", ARG (2), ARG (1), ARG (0));
407 		} else if (!strncmp (name, "or", 2)) {
408 			esilprintf (op, "%s,%s,|,%s,=", ARG (2), ARG (1), ARG (0));
409 		} else if (!strncmp (name, "and", 3)) {
410 			esilprintf (op, "%s,%s,&,%s,=", ARG (2), ARG (1), ARG (0));
411 		} else if (!strcmp (name, "auipc")) {
412 			esilprintf (op, "%s000,$$,+,%s,=", ARG (1), ARG (0));
413 		} else if (!strncmp (name, "sll", 3)) {
414 			esilprintf (op, "%s,%s,<<,%s,=", ARG (2), ARG (1), ARG (0));
415 			if (name[3] == 'w' || !strncmp (name, "slliw", 5)) {
416 				r_strbuf_appendf (&op->esil, ",32,%s,~=", ARG (0));
417 			}
418 		} else if (!strcmp (name, "srlw") || !strcmp (name, "srliw")) {
419 			esilprintf (op, "%s,0xffffffff,%s,&,>>,%s,=", ARG (2), ARG (1), ARG (0));
420 		} else if (!strncmp (name, "srl", 3)) {
421 			esilprintf (op, "%s,%s,>>,%s,=", ARG (2), ARG (1), ARG (0));
422 		} else if (!strcmp (name, "sraiw")) {
423 			esilprintf (op, "%s,%s,>>>>,%s,=,", ARG (2), ARG (1), ARG (0));
424 			r_strbuf_appendf (&op->esil, "%s,64,-,%s,~=", ARG (2), ARG(0));
425 		} else if (!strncmp (name, "sra", 3)) {
426 			esilprintf (op, "%s,%s,>>>>,%s,=", ARG (2), ARG (1), ARG (0));
427 		}
428 		// assigns
429 		else if (!strcmp (name, "mv")) {
430 			esilprintf (op, "%s,%s,=", ARG (1), ARG (0));
431 		} else if (!strcmp (name, "li")) {
432 			esilprintf (op, "%s,%s,=", ARG (1), ARG (0));
433 		} else if (!strcmp (name, "lui")) {
434 			esilprintf (op, "%s000,%s,=", ARG (1), ARG (0));
435 			if (anal->bits == 64) {
436 				r_strbuf_appendf (&op->esil, ",32,%s,~=", ARG (0));
437 			}
438 		}
439 		// csr instrs
440 		// <csr op> rd, rs1, CSR
441 		else if (!strncmp (name, "csrrw", 5)) {
442 			// Writes rs1 into CSR, places the old value in rd
443 			esilprintf (op, "%s,0,+,%s,%s,=,%s,=", ARG (1), ARG (2), ARG (1), ARG (0));
444 		} else if (!strncmp (name, "csrrs", 5)) {
445 			// Ors rs1 with CSR, places old value in rd
446 			esilprintf (op, "%s,0,+,%s,%s,|=,%s,=", ARG (1), ARG (2), ARG (1), ARG (0));
447 		} else if (!strncmp (name, "csrrc", 5)) {
448 			// Ands the inverse of rs1 with CSR, places old value in rd
449 			esilprintf (op, "%s,0,+,%s,1,+,0,-,%s,&=,%s,=", ARG (1), ARG (1), ARG (2), ARG (0));
450 		}
451 		// stores
452 		else if (!strcmp (name, "sd") || !strcmp (name, "sdsp")) {
453 			esilprintf (op, "%s,%s,%s,+,=[8]", ARG (0), ARG (2), ARG (1));
454 		} else if (!strcmp (name, "sw") || !strcmp (name, "swsp")) {
455 			esilprintf (op, "%s,%s,%s,+,=[4]", ARG (0), ARG (2), ARG (1));
456 		} else if (!strcmp (name, "sh") || !strcmp (name, "shsp")) {
457 			esilprintf (op, "%s,%s,%s,+,=[2]", ARG (0), ARG (2), ARG (1));
458 		} else if (!strcmp (name, "sb") || !strcmp (name, "sbsp")) {
459 			esilprintf (op, "%s,%s,%s,+,=[1]", ARG (0), ARG (2), ARG (1));
460 		} else if (!strcmp (name, "fsq") || !strcmp (name, "fsqsp")) {
461 			esilprintf (op, "%s,%s,+,[16],%s,=", ARG (2), ARG (1), ARG (0));
462 		} else if (!strcmp (name, "fsd") || !strcmp (name, "fsdsp")) {
463 			esilprintf (op, "%s,%s,%s,+,=[8]", ARG (0), ARG (2), ARG (1));
464 		} else if (!strcmp (name, "fsw") || !strcmp (name, "fswsp")) {
465 			esilprintf (op, "%s,%s,%s,+,=[4]", ARG (0), ARG (2), ARG (1));
466 		} else if (!strcmp (name, "fsh") || !strcmp (name, "fshsp")) {
467 			esilprintf (op, "%s,%s,%s,+,=[2]", ARG (0), ARG (2), ARG (1));
468 		} else if (!strcmp (name, "fsb") || !strcmp (name, "fsbsp")) {
469 			esilprintf (op, "%s,%s,%s,+,=[1]", ARG (0), ARG (2), ARG (1));
470 		}
471 		// loads
472 		else if (!strcmp (name, "ld") || !strcmp (name, "ldsp")) {
473 			esilprintf (op, "%s,%s,+,[8],%s,=", ARG (2), ARG (1), ARG (0));
474 		} else if (!strcmp (name, "lw") || !strcmp (name, "lwu") || !strcmp (name, "lwsp")) {
475 			esilprintf (op, "%s,%s,+,[4],%s,=", ARG (2), ARG (1), ARG (0));
476 			if ((anal->bits == 64) && strcmp (name, "lwu")) {
477 				r_strbuf_appendf (&op->esil, ",32,%s,~=", ARG (0));
478 			}
479 		} else if (!strcmp (name, "lh") || !strcmp (name, "lhu") || !strcmp (name, "lhsp")) {
480 			esilprintf (op, "%s,%s,+,[2],%s,=", ARG (2), ARG (1), ARG (0));
481 			if (strcmp (name, "lwu")) {
482 				r_strbuf_appendf (&op->esil, ",16,%s,~=", ARG (0));
483 			}
484 		} else if (!strcmp (name, "lb") || !strcmp (name, "lbu") || !strcmp (name, "lbsp")) {
485 			esilprintf (op, "%s,%s,+,[1],%s,=", ARG (2), ARG (1), ARG (0));
486 			if (strcmp (name, "lbu")) {
487 				r_strbuf_appendf (&op->esil, ",8,%s,~=", ARG (0));
488 			}
489 		} else if (!strcmp (name, "flq") || !strcmp (name, "flqsp")) {
490 			esilprintf (op, "%s,%s,+,[16],%s,=", ARG (2), ARG (1), ARG (0));
491 		} else if (!strcmp (name, "fld") || !strcmp (name, "fldsp")) {
492 			esilprintf (op, "%s,%s,+,[8],%s,=", ARG (2), ARG (1), ARG (0));
493 		} else if (!strcmp (name, "flw") || !strcmp (name, "flwsp")) {
494 			esilprintf (op, "%s,%s,+,[4],%s,=", ARG (2), ARG (1), ARG (0));
495 		} else if (!strcmp (name, "flh") || !strcmp (name, "flhsp")) {
496 			esilprintf (op, "%s,%s,+,[2],%s,=", ARG (2), ARG (1), ARG (0));
497 		} else if (!strcmp (name, "flb") || !strcmp (name, "flbsp")) {
498 			esilprintf (op, "%s,%s,+,[1],%s,=", ARG (2), ARG (1), ARG (0));
499 		}
500 		// jumps
501 		else if (!strcmp (name, "jalr")) {
502 			if (strcmp (ARG (0), "0")) {
503 				esilprintf (op, "%s,%s,+,pc,=,%d,$$,+,%s,=", ARG (2), ARG (1), op->size, ARG (0));
504 			} else {
505 				esilprintf (op, "%s,%s,+,pc,=", ARG (2), ARG (1));
506 			}
507 		} else if (!strcmp (name, "jal")) {
508 			if (strcmp (ARG (0), "0")) {
509 				if (args.num == 1) {
510 					esilprintf (op, "%d,$$,+,ra,=,%s,pc,=", op->size, ARG (0));
511 				} else {
512 					esilprintf (op, "%d,$$,+,%s,=,%s,pc,=", op->size, ARG (0), ARG (1));
513 				}
514 			} else {
515 				esilprintf (op, "%s,pc,=", ARG (1));
516 			}
517 		} else if (!strcmp (name, "jr") || !strcmp (name, "j")) {
518 			esilprintf (op, "%s,pc,=", ARG (0));
519 		} else if (!strcmp (name, "ecall") || !strcmp (name, "ebreak")) {
520 			esilprintf (op, "TRAP");
521 		}
522 		// Branches & cmps
523 		else if (!strcmp (name, "beq")) {
524 			esilprintf (op, "%s,%s,==,$z,?{,%s,pc,=,},", ARG (1), ARG (0), ARG (2));
525 		} else if (!strcmp (name, "bne")) {
526 			esilprintf (op, "%s,%s,==,$z,!,?{,%s,pc,=,},", ARG (1), ARG (0), ARG (2));
527 		} else if (!strcmp (name, "ble") || !strcmp (name, "bleu")) {
528 			esilprintf (op, "%s,%s,<=,?{,%s,pc,=,},", ARG (1), ARG (0), ARG (2));
529 		} else if (!strcmp (name, "blt") || !strcmp (name, "bltu")) {
530 			esilprintf (op, "%s,%s,<,?{,%s,pc,=,},", ARG (1), ARG (0), ARG (2));
531 		} else if (!strcmp (name, "bge") || !strcmp (name, "bgeu")) {
532 			esilprintf (op, "%s,%s,>=,?{,%s,pc,=,},", ARG (1), ARG (0), ARG (2));
533 		} else if (!strcmp (name, "bgt") || !strcmp (name, "bgtu")) {
534 			esilprintf (op, "%s,%s,>,?{,%s,pc,=,},", ARG (1), ARG (0), ARG (2));
535 		} else if (!strcmp (name, "beqz")) {
536 			esilprintf (op, "%s,0,==,$z,?{,%s,pc,=,},", ARG (0), ARG (1));
537 		} else if (!strcmp (name, "bnez")) {
538 			esilprintf (op, "%s,0,==,$z,!,?{,%s,pc,=,},", ARG (0), ARG (1));
539 		} else if (!strcmp (name, "blez")) {
540 			esilprintf (op, "%s,0,<=,?{,%s,pc,=,},", ARG (0), ARG (1));
541 		} else if (!strcmp (name, "bltz")) {
542 			esilprintf (op, "%s,0,<,?{,%s,pc,=,},", ARG (0), ARG (1));
543 		} else if (!strcmp (name, "bgez")) {
544 			esilprintf (op, "%s,0,>=,?{,%s,pc,=,},", ARG (0), ARG (1));
545 		} else if (!strcmp (name, "bgtz")) {
546 			esilprintf (op, "%s,0,>,?{,%s,pc,=,},", ARG (0), ARG (1));
547 		} else if (!strncmp (name, "seq", 3)) {
548 			esilprintf (op, "%s,%s,==,%s,=", ARG (2), ARG (1), ARG (0));
549 		} else if (!strncmp (name, "sne", 3)) {
550 			esilprintf (op, "%s,%s,!=,%s,=", ARG (2), ARG (1), ARG (0));
551 		} else if (!strncmp (name, "sle", 3)) {
552 			esilprintf (op, "%s,%s,<=,%s,=", ARG (2), ARG (1), ARG (0));
553 		} else if (!strncmp (name, "slt", 3)) {
554 			esilprintf (op, "%s,%s,<,%s,=", ARG (2), ARG (1), ARG (0));
555 		} else if (!strncmp (name, "sge", 3)) {
556 			esilprintf (op, "%s,%s,>=,%s,=", ARG (2), ARG (1), ARG (0));
557 		} else if (!strncmp (name, "sgt", 3)) {
558 			esilprintf (op, "%s,%s,>,%s,=", ARG (2), ARG (1), ARG (0));
559 		}
560 		// debug
561 		//else if (strcmp (name, "unimp") != 0 && name[0] != 'f' && name[1] != 'm') {
562 		//	int i;
563 		//	eprintf("[esil] missing risc v esil: %s", name);
564 		//	for (i = 0; i < args.num; i++) {
565 		//		eprintf(" %s", ARG(i));
566 		//	}
567 		//	eprintf("\n");
568 		//}
569 #undef ARG
570 	}
571 
572 // branch/jumps/calls/rets
573 	if (is_any ("jal")) {
574 		// decide whether it's jump or call
575 		int rd = (word >> OP_SH_RD) & OP_MASK_RD;
576 		op->type = (rd == 0) ? R_ANAL_OP_TYPE_JMP: R_ANAL_OP_TYPE_CALL;
577 		op->jump = EXTRACT_UJTYPE_IMM (word) + addr;
578 		op->fail = addr + op->size;
579 	} else if (is_any ("c.jal")) {
580 		op->type = R_ANAL_OP_TYPE_CALL;
581 		op->jump = EXTRACT_RVC_IMM (word) + addr;
582 		op->fail = addr + op->size;
583 	} else if (is_any ("jr")) {
584 		op->type = R_ANAL_OP_TYPE_JMP;
585 	} else if (is_any ("c.j", "jump")) {
586 		op->type = R_ANAL_OP_TYPE_JMP;
587 		op->jump = EXTRACT_RVC_J_IMM (word) + addr;
588 	} else if (is_any ("jalr")) {
589 		// decide whether it's ret or call
590 		int rd = (word >> OP_SH_RD) & OP_MASK_RD;
591 		op->type = (rd == 0) ? R_ANAL_OP_TYPE_RET: R_ANAL_OP_TYPE_UCALL;
592 	} else if (is_any ("c.ret")) {
593 		op->type = R_ANAL_OP_TYPE_RET;
594 	} else if (is_any ("c.jalr")) {
595 		op->type = R_ANAL_OP_TYPE_UCALL;
596 	} else if (is_any ("c.jr")) {
597 		op->type = R_ANAL_OP_TYPE_RET;
598 	} else if (is_any ("beqz", "beq", "blez", "bgez", "ble",
599 			   "bleu", "bge", "bgeu", "bltz", "bgtz", "blt", "bltu",
600 			   "bgt", "bgtu", "bnez", "bne")) {
601 		op->type = R_ANAL_OP_TYPE_CJMP;
602 		op->jump = EXTRACT_SBTYPE_IMM (word) + addr;
603 		op->fail = addr + op->size;
604 	} else if (is_any ("c.beqz", "c.bnez")) {
605 		op->type = R_ANAL_OP_TYPE_CJMP;
606 		op->jump = EXTRACT_RVC_B_IMM (word) + addr;
607 		op->fail = addr + op->size;
608 // math
609 	} else if (is_any ("addi", "addw", "addiw", "add", "auipc", "c.addi",
610 			   "c.addw", "c.add", "c.addiw", "c.addi4spn", "c.addi16sp")) {
611 		op->type = R_ANAL_OP_TYPE_ADD;
612 	} else if (is_any ("c.mv", "csrrw", "csrrc", "csrrs")) {
613 		op->type = R_ANAL_OP_TYPE_MOV;
614 	} else if (is_any ("subi", "subw", "sub", "c.sub", "c.subw")) {
615 		op->type = R_ANAL_OP_TYPE_SUB;
616 	} else if (is_any ("xori", "xor", "c.xor")) {
617 		op->type = R_ANAL_OP_TYPE_XOR;
618 	} else if (is_any ("andi", "and", "c.andi", "c.and")) {
619 		op->type = R_ANAL_OP_TYPE_AND;
620 	} else if (is_any ("ori", "or", "c.or")) {
621 		op->type = R_ANAL_OP_TYPE_OR;
622 	} else if (is_any ("not")) {
623 		op->type = R_ANAL_OP_TYPE_NOT;
624 	} else if (is_any ("c.nop")) {
625 		op->type = R_ANAL_OP_TYPE_NOP;
626 	} else if (is_any ("mul", "mulh", "mulhu", "mulhsu", "mulw")) {
627 		op->type = R_ANAL_OP_TYPE_MUL;
628 	} else if (is_any ("div", "divu", "divw", "divuw")) {
629 		op->type = R_ANAL_OP_TYPE_DIV;
630 	} else if (is_any ("sll", "slli", "sllw", "slliw", "c.slli")) {
631 		op->type = R_ANAL_OP_TYPE_SHL;
632 	} else if (is_any ("srl", "srlw", "srliw", "c.srli")) {
633 		op->type = R_ANAL_OP_TYPE_SHR;
634 	} else if (is_any ("sra", "sra", "srai", "sraiw", "c.srai")) {
635 		op->type = R_ANAL_OP_TYPE_SAR;
636 // memory
637 	} else if (is_any ("sd", "sb", "sh", "sw", "c.sd", "c.sw",
638 			   "c.swsp", "c.sdsp")) {
639 		op->type = R_ANAL_OP_TYPE_STORE;
640 	} else if (is_any ("ld", "lw", "lwu", "lui", "li",
641 			   "lb", "lbu", "lh", "lhu", "la", "lla", "c.ld",
642 			   "c.lw", "c.lwsp", "c.li", "c.lui")) {
643 		op->type = R_ANAL_OP_TYPE_LOAD;
644 	}
645 	if (mask & R_ANAL_OP_MASK_VAL && args.num) {
646 		int i, j = 1;
647 		op->dst = R_NEW0 (RAnalValue);
648 		char *argf = strdup (o->args);
649 		char *comma = strtok (argf, ",");
650 		if (comma && strchr (comma, '(')) {
651 			op->dst->delta = (st64)r_num_get (NULL, args.arg[0]);
652 			op->dst->reg = r_reg_get (anal->reg, args.arg[1], -1);
653 			j = 2;
654 		} else if (isdigit ((unsigned char)args.arg[j][0])) {
655 			op->dst->imm = r_num_get (NULL, args.arg[0]);
656 		} else {
657 			op->dst->reg = r_reg_get (anal->reg, args.arg[0], -1);
658 		}
659 		for (i = 0; j < args.num; i++, j++) {
660 			op->src[i] = R_NEW0 (RAnalValue);
661 			comma = strtok (NULL, ",");
662 			if (comma && strchr (comma, '(')) {
663 				op->src[i]->delta = (st64)r_num_get (NULL, args.arg[j]);
664 				op->src[i]->reg = r_reg_get (anal->reg, args.arg[j + 1], -1);
665 				j++;
666 			} else if (isalpha ((unsigned char)args.arg[j][0])) {
667 				op->src[i]->reg = r_reg_get (anal->reg, args.arg[j], -1);
668 			} else {
669 				op->src[i]->imm = r_num_get (NULL, args.arg[j]);
670 			}
671 		}
672 		free (argf);
673 	}
674 	return op->size;
675 }
676 
get_reg_profile(RAnal * anal)677 static char *get_reg_profile(RAnal *anal) {
678 	const char *p = NULL;
679 	switch (anal->bits) {
680 	case 32: p =
681 		"=PC	pc\n"
682 		"=A0	a0\n"
683 		"=A1	a1\n"
684 		"=A2	a2\n"
685 		"=A3	a3\n"
686 		"=A4	a4\n"
687 		"=A5	a5\n"
688 		"=A6	a6\n"
689 		"=A7	a7\n"
690 		"=R0	a0\n"
691 		"=R1	a1\n"
692 		"=SP	sp\n" // ABI: stack pointer
693 		"=LR	ra\n" // ABI: return address
694 		"=BP	s0\n" // ABI: frame pointer
695 		"=SN	a7\n" // ABI: syscall numer
696 		"gpr	pc	.32	0	0\n"
697 		// RV32I regs (ABI names)
698 		// From user-Level ISA Specification, section 2.1
699 		// "zero" has been left out as it ignores writes and always reads as zero
700 		"gpr	ra	.32	4	0\n" // =x1
701 		"gpr	sp	.32	8	0\n" // =x2
702 		"gpr	gp	.32	12	0\n" // =x3
703 		"gpr	tp	.32	16	0\n" // =x4
704 		"gpr	t0	.32	20	0\n" // =x5
705 		"gpr	t1	.32	24	0\n" // =x6
706 		"gpr	t2	.32	28	0\n" // =x7
707 		"gpr	s0	.32	32	0\n" // =x8
708 		"gpr	s1	.32	36	0\n" // =x9
709 		"gpr	a0	.32	40	0\n" // =x10
710 		"gpr	a1	.32	44	0\n" // =x11
711 		"gpr	a2	.32	48	0\n" // =x12
712 		"gpr	a3	.32	52	0\n" // =x13
713 		"gpr	a4	.32	56	0\n" // =x14
714 		"gpr	a5	.32	60	0\n" // =x15
715 		"gpr	a6	.32	64	0\n" // =x16
716 		"gpr	a7	.32	68	0\n" // =x17
717 		"gpr	s2	.32	72	0\n" // =x18
718 		"gpr	s3	.32	76	0\n" // =x19
719 		"gpr	s4	.32	80	0\n" // =x20
720 		"gpr	s5	.32	84	0\n" // =x21
721 		"gpr	s6	.32	88	0\n" // =x22
722 		"gpr	s7	.32	92	0\n" // =x23
723 		"gpr	s8	.32	96	0\n" // =x24
724 		"gpr	s9	.32	100	0\n" // =x25
725 		"gpr	s10	.32	104	0\n" // =x26
726 		"gpr	s11	.32	108	0\n" // =x27
727 		"gpr	t3	.32	112	0\n" // =x28
728 		"gpr	t4	.32	116	0\n" // =x29
729 		"gpr	t5	.32	120	0\n" // =x30
730 		"gpr	t6	.32	124	0\n" // =x31
731 		// RV32F/D regs (ABI names)
732 		// From user-Level ISA Specification, section 8.1 and 9.1
733 		"fpu	ft0	.64	128	0\n" // =f0
734 		"fpu	ft1	.64	136	0\n" // =f1
735 		"fpu	ft2	.64	144	0\n" // =f2
736 		"fpu	ft3	.64	152	0\n" // =f3
737 		"fpu	ft4	.64	160	0\n" // =f4
738 		"fpu	ft5	.64	168	0\n" // =f5
739 		"fpu	ft6	.64	176	0\n" // =f6
740 		"fpu	ft7	.64	184	0\n" // =f7
741 		"fpu	fs0	.64	192	0\n" // =f8
742 		"fpu	fs1	.64	200	0\n" // =f9
743 		"fpu	fa0	.64	208	0\n" // =f10
744 		"fpu	fa1	.64	216	0\n" // =f11
745 		"fpu	fa2	.64	224	0\n" // =f12
746 		"fpu	fa3	.64	232	0\n" // =f13
747 		"fpu	fa4	.64	240	0\n" // =f14
748 		"fpu	fa5	.64	248	0\n" // =f15
749 		"fpu	fa6	.64	256	0\n" // =f16
750 		"fpu	fa7	.64	264	0\n" // =f17
751 		"fpu	fs2	.64	272	0\n" // =f18
752 		"fpu	fs3	.64	280	0\n" // =f19
753 		"fpu	fs4	.64	288	0\n" // =f20
754 		"fpu	fs5	.64	296	0\n" // =f21
755 		"fpu	fs6	.64	304	0\n" // =f22
756 		"fpu	fs7	.64	312	0\n" // =f23
757 		"fpu	fs8	.64	320	0\n" // =f24
758 		"fpu	fs9	.64	328	0\n" // =f25
759 		"fpu	fs10	.64	336	0\n" // =f26
760 		"fpu	fs11	.64	344	0\n" // =f27
761 		"fpu	ft8	.64	352	0\n" // =f28
762 		"fpu	ft9	.64	360	0\n" // =f29
763 		"fpu	ft10	.64	368	0\n" // =f30
764 		"fpu	ft11	.64	376	0\n" // =f31
765 		"fpu	fcsr	.32	384	0\n"
766 		"flg	nx	.1	3072	0\n"
767 		"flg	uf	.1	3073	0\n"
768 		"flg	of	.1	3074	0\n"
769 		"flg	dz	.1	3075	0\n"
770 		"flg	nv	.1	3076	0\n"
771 		"flg	frm	.3	3077	0\n"
772 		;
773 
774 		break;
775 	case 64: p =
776 		"=PC	pc\n"
777 		"=SP	sp\n" // ABI: stack pointer
778 		"=LR	ra\n" // ABI: return address
779 		"=BP	s0\n" // ABI: frame pointer
780 		"=A0	a0\n"
781 		"=A1	a1\n"
782 		"=A2	a2\n"
783 		"=A3	a3\n"
784 		"=A4	a4\n"
785 		"=A5	a5\n"
786 		"=A6	a6\n"
787 		"=A7	a7\n"
788 		"=R0	a0\n"
789 		"=R1	a1\n"
790 		"=SN	a7\n" // ABI: syscall numer
791 		"gpr	pc	.64	0	0\n"
792 		// RV64I regs (ABI names)
793 		// From user-Level ISA Specification, section 2.1 and 4.1
794 		// "zero" has been left out as it ignores writes and always reads as zero
795 		"gpr	ra	.64	8	0\n" // =x1
796 		"gpr	sp	.64	16	0\n" // =x2
797 		"gpr	gp	.64	24	0\n" // =x3
798 		"gpr	tp	.64	32	0\n" // =x4
799 		"gpr	t0	.64	40	0\n" // =x5
800 		"gpr	t1	.64	48	0\n" // =x6
801 		"gpr	t2	.64	56	0\n" // =x7
802 		"gpr	s0	.64	64	0\n" // =x8
803 		"gpr	s1	.64	72	0\n" // =x9
804 		"gpr	a0	.64	80	0\n" // =x10
805 		"gpr	a1	.64	88	0\n" // =x11
806 		"gpr	a2	.64	96	0\n" // =x12
807 		"gpr	a3	.64	104	0\n" // =x13
808 		"gpr	a4	.64	112	0\n" // =x14
809 		"gpr	a5	.64	120	0\n" // =x15
810 		"gpr	a6	.64	128	0\n" // =x16
811 		"gpr	a7	.64	136	0\n" // =x17
812 		"gpr	s2	.64	144	0\n" // =x18
813 		"gpr	s3	.64	152	0\n" // =x19
814 		"gpr	s4	.64	160	0\n" // =x20
815 		"gpr	s5	.64	168	0\n" // =x21
816 		"gpr	s6	.64	176	0\n" // =x22
817 		"gpr	s7	.64	184	0\n" // =x23
818 		"gpr	s8	.64	192	0\n" // =x24
819 		"gpr	s9	.64	200	0\n" // =x25
820 		"gpr	s10	.64	208	0\n" // =x26
821 		"gpr	s11	.64	216	0\n" // =x27
822 		"gpr	t3	.64	224	0\n" // =x28
823 		"gpr	t4	.64	232	0\n" // =x29
824 		"gpr	t5	.64	240	0\n" // =x30
825 		"gpr	t6	.64	248	0\n" // =x31
826 		// RV64F/D regs (ABI names)
827 		"fpu	ft0	.64	256	0\n" // =f0
828 		"fpu	ft1	.64	264	0\n" // =f1
829 		"fpu	ft2	.64	272	0\n" // =f2
830 		"fpu	ft3	.64	280	0\n" // =f3
831 		"fpu	ft4	.64	288	0\n" // =f4
832 		"fpu	ft5	.64	296	0\n" // =f5
833 		"fpu	ft6	.64	304	0\n" // =f6
834 		"fpu	ft7	.64	312	0\n" // =f7
835 		"fpu	fs0	.64	320	0\n" // =f8
836 		"fpu	fs1	.64	328	0\n" // =f9
837 		"fpu	fa0	.64	336	0\n" // =f10
838 		"fpu	fa1	.64	344	0\n" // =f11
839 		"fpu	fa2	.64	352	0\n" // =f12
840 		"fpu	fa3	.64	360	0\n" // =f13
841 		"fpu	fa4	.64	368	0\n" // =f14
842 		"fpu	fa5	.64	376	0\n" // =f15
843 		"fpu	fa6	.64	384	0\n" // =f16
844 		"fpu	fa7	.64	392	0\n" // =f17
845 		"fpu	fs2	.64	400	0\n" // =f18
846 		"fpu	fs3	.64	408	0\n" // =f19
847 		"fpu	fs4	.64	416	0\n" // =f20
848 		"fpu	fs5	.64	424	0\n" // =f21
849 		"fpu	fs6	.64	432	0\n" // =f22
850 		"fpu	fs7	.64	440	0\n" // =f23
851 		"fpu	fs8	.64	448	0\n" // =f24
852 		"fpu	fs9	.64	456	0\n" // =f25
853 		"fpu	fs10	.64	464	0\n" // =f26
854 		"fpu	fs11	.64	472	0\n" // =f27
855 		"fpu	ft8	.64	480	0\n" // =f28
856 		"fpu	ft9	.64	488	0\n" // =f29
857 		"fpu	ft10	.64	496	0\n" // =f30
858 		"fpu	ft11	.64	504	0\n" // =f31
859 		"fpu	fcsr	.32	512	0\n"
860 		"flg	nx	.1	4096	0\n"
861 		"flg	uf	.1	4097	0\n"
862 		"flg	of	.1	4098	0\n"
863 		"flg	dz	.1	4099	0\n"
864 		"flg	nv	.1	4100	0\n"
865 		"flg	frm	.3	4101	0\n"
866 		;
867 
868 		break;
869 	}
870 	return (p && *p)? strdup (p): NULL;
871 }
872 
873 RAnalPlugin r_anal_plugin_riscv = {
874 	.name = "riscv",
875 	.desc = "RISC-V analysis plugin",
876 	.license = "GPL",
877 	.arch = "riscv",
878 	.bits = 32|64,
879 	.op = &riscv_op,
880 	.get_reg_profile = &get_reg_profile,
881 };
882 
883 #ifndef R2_PLUGIN_INCORE
884 R_API RLibStruct radare_plugin = {
885 	.type = R_LIB_TYPE_ANAL,
886 	.data = &r_anal_plugin_riscv,
887 	.version = R2_VERSION
888 };
889 #endif
890