1 /* radare2 - LGPL - Copyright 2013-2020 - pancake */
2 
3 #include <r_asm.h>
4 #include <r_lib.h>
5 
6 #include <capstone.h>
7 #if CS_API_MAJOR >= 5
8 #include <riscv.h>
9 
10 // http://www.mrc.uidaho.edu/mrc/people/jff/digital/RISCVir.html
11 
12 #define OPERAND(x) insn->detail->riscv.operands[x]
13 #define REGID(x) insn->detail->riscv.operands[x].reg
14 #define REG(x) cs_reg_name (*handle, insn->detail->riscv.operands[x].reg)
15 #define IMM(x) insn->detail->riscv.operands[x].imm
16 #define MEMBASE(x) cs_reg_name(*handle, insn->detail->riscv.operands[x].mem.base)
17 #define MEMINDEX(x) insn->detail->riscv.operands[x].mem.index
18 #define MEMDISP(x) insn->detail->riscv.operands[x].mem.disp
19 #define OPCOUNT() insn->detail->riscv.op_count
20 // TODO scale and disp
21 
22 #define SET_VAL(op,i) \
23 	if ((i)<OPCOUNT() && OPERAND(i).type == RISCV_OP_IMM) {\
24 		(op)->val = OPERAND(i).imm;\
25 	}
26 
27 #define CREATE_SRC_DST_3(op) \
28 	(op)->src[0] = r_anal_value_new ();\
29 	(op)->src[1] = r_anal_value_new ();\
30 	(op)->dst = r_anal_value_new ();
31 
32 #define CREATE_SRC_DST_2(op) \
33 	(op)->src[0] = r_anal_value_new ();\
34 	(op)->dst = r_anal_value_new ();
35 
36 #define SET_SRC_DST_3_REGS(op) \
37 	CREATE_SRC_DST_3 (op);\
38 	(op)->dst->reg = r_reg_get (anal->reg, REG (0), R_REG_TYPE_GPR);\
39 	(op)->src[0]->reg = r_reg_get (anal->reg, REG (1), R_REG_TYPE_GPR);\
40 	(op)->src[1]->reg = r_reg_get (anal->reg, REG (2), R_REG_TYPE_GPR);
41 
42 #define SET_SRC_DST_3_IMM(op) \
43 	CREATE_SRC_DST_3 (op);\
44 	(op)->dst->reg = r_reg_get (anal->reg, REG (0), R_REG_TYPE_GPR);\
45 	(op)->src[0]->reg = r_reg_get (anal->reg, REG (1), R_REG_TYPE_GPR);\
46 	(op)->src[1]->imm = IMM (2);
47 
48 #define SET_SRC_DST_2_REGS(op) \
49 	CREATE_SRC_DST_2 (op);\
50 	(op)->dst->reg = r_reg_get (anal->reg, REG (0), R_REG_TYPE_GPR);\
51 	(op)->src[0]->reg = r_reg_get (anal->reg, REG (1), R_REG_TYPE_GPR);
52 
53 #define SET_SRC_DST_3_REG_OR_IMM(op) \
54 	if (OPERAND(2).type == RISCV_OP_IMM) {\
55 		SET_SRC_DST_3_IMM (op);\
56 	} else if (OPERAND(2).type == RISCV_OP_REG) {\
57 		SET_SRC_DST_3_REGS (op);\
58 	}
59 
60 
61 // ESIL macros:
62 
63 // put the sign bit on the stack
64 #define ES_IS_NEGATIVE(arg) "1,"arg",<<<,1,&"
65 
66 
67 // call with delay slot
68 #define ES_CALL_DR(ra, addr) "pc,4,+,"ra",=,"ES_J(addr)
69 #define ES_CALL_D(addr) ES_CALL_DR("ra", addr)
70 
71 // call without delay slot
72 #define ES_CALL_NDR(ra, addr) "pc,"ra",=,"ES_J(addr)
73 #define ES_CALL_ND(addr) ES_CALL_NDR("ra", addr)
74 
75 #define USE_DS 0
76 #if USE_DS
77 // emit ERR trap if executed in a delay slot
78 #define ES_TRAP_DS() "$ds,!,!,?{,$$,1,TRAP,BREAK,},"
79 // jump to address
80 #define ES_J(addr) addr",SETJT,1,SETD"
81 #else
82 #define ES_TRAP_DS() ""
83 #define ES_J(addr) addr",pc,="
84 #endif
85 
86 // sign extend 32 -> 64
87 #define ES_SIGN_EXT64(arg) \
88 	arg",0x80000000,&,0,<,?{,"\
89 		"0xffffffff00000000,"arg",|=,"\
90 	"}"
91 
92 #define PROTECT_ZERO() \
93 	if (REG(0)[0]=='z'){\
94 		r_strbuf_appendf (&op->esil, ",");\
95 	} else
96 
97 #define ESIL_LOAD(size) \
98 	PROTECT_ZERO () {\
99 		r_strbuf_appendf (&op->esil, "%s,["size"],%s,=",\
100 			ARG(1), REG(0));\
101 	}
102 
opex(RStrBuf * buf,csh handle,cs_insn * insn)103 static void opex(RStrBuf *buf, csh handle, cs_insn *insn) {
104 	int i;
105 	PJ *pj = pj_new ();
106 	if (!pj) {
107 		return;
108 	}
109 	pj_o (pj);
110 	pj_ka (pj, "operands");
111 	cs_riscv *x = &insn->detail->riscv;
112 	for (i = 0; i < x->op_count; i++) {
113 		cs_riscv_op *op = x->operands + i;
114 		pj_o (pj);
115 		switch (op->type) {
116 		case RISCV_OP_REG:
117 			pj_ks (pj, "type", "reg");
118 			pj_ks (pj, "value", cs_reg_name (handle, op->reg));
119 			break;
120 		case RISCV_OP_IMM:
121 			pj_ks (pj, "type", "imm");
122 			pj_kN (pj, "value", op->imm);
123 			break;
124 		case RISCV_OP_MEM:
125 			pj_ks (pj, "type", "mem");
126 			if (op->mem.base != RISCV_REG_INVALID) {
127 				pj_ks (pj, "base", cs_reg_name (handle, op->mem.base));
128 			}
129 			pj_kN (pj, "disp", op->mem.disp);
130 			break;
131 		default:
132 			pj_ks (pj, "type", "invalid");
133 			break;
134 		}
135 		pj_end (pj); /* o operand */
136 	}
137 	pj_end (pj); /* a operands */
138 	pj_end (pj);
139 
140 	r_strbuf_init (buf);
141 	r_strbuf_append (buf, pj_string (pj));
142 	pj_free (pj);
143 }
144 
arg(csh * handle,cs_insn * insn,char * buf,int n)145 static const char *arg(csh *handle, cs_insn *insn, char *buf, int n) {
146 	*buf = 0;
147 	switch (insn->detail->riscv.operands[n].type) {
148 	case RISCV_OP_INVALID:
149 		break;
150 	case RISCV_OP_REG:
151 		sprintf (buf, "%s",
152 			cs_reg_name (*handle,
153 				insn->detail->riscv.operands[n].reg));
154 		break;
155 	case RISCV_OP_IMM:
156 	{
157 		st64 x = (st64)insn->detail->riscv.operands[n].imm;
158 		sprintf (buf, "%"PFMT64d, x);
159 		break;
160 	}
161 	case RISCV_OP_MEM:
162 	{
163 		st64 disp = insn->detail->riscv.operands[n].mem.disp;
164 		if (disp < 0) {
165 			sprintf (buf, "%"PFMT64d",%s,-",
166 				(ut64)-insn->detail->riscv.operands[n].mem.disp,
167 				cs_reg_name (*handle,
168 					insn->detail->riscv.operands[n].mem.base));
169 		} else {
170 			sprintf (buf, "0x%"PFMT64x",%s,+",
171 				insn->detail->riscv.operands[n].mem.disp,
172 				cs_reg_name (*handle,
173 					insn->detail->riscv.operands[n].mem.base));
174 		}
175 		break;
176 	}
177 	}
178 	return buf;
179 }
180 
181 #define ARG(x) (*str[x]!=0)?str[x]:arg(handle, insn, str[x], x)
182 
analop_esil(RAnal * a,RAnalOp * op,ut64 addr,const ut8 * buf,int len,csh * handle,cs_insn * insn)183 static int analop_esil(RAnal *a, RAnalOp *op, ut64 addr, const ut8 *buf, int len, csh *handle, cs_insn *insn) {
184 	char str[8][32] = {{0}};
185 	int i;
186 
187 	r_strbuf_init (&op->esil);
188 	r_strbuf_set (&op->esil, "");
189 
190 	if (insn) {
191 		// caching operands
192 		for (i = 0; i < insn->detail->riscv.op_count && i < 8; i++) {
193 			*str[i] = 0;
194 			ARG (i);
195 		}
196 	}
197 
198 	switch (insn->id) {
199 	//case RISCV_INS_NOP:
200 	//	r_strbuf_setf (&op->esil, ",");
201 	//	break;
202 	}
203 	return 0;
204 }
205 
parse_reg_name(RRegItem * reg,csh handle,cs_insn * insn,int reg_num)206 static int parse_reg_name(RRegItem *reg, csh handle, cs_insn *insn, int reg_num) {
207 	if (!reg) {
208 		return -1;
209 	}
210 	switch (OPERAND (reg_num).type) {
211 	case RISCV_OP_REG:
212 		reg->name = (char *)cs_reg_name (handle, OPERAND (reg_num).reg);
213 		break;
214 	case RISCV_OP_MEM:
215 		if (OPERAND (reg_num).mem.base != RISCV_REG_INVALID) {
216 			reg->name = (char *)cs_reg_name (handle, OPERAND (reg_num).mem.base);
217 		}
218 	default:
219 		break;
220 	}
221 	return 0;
222 }
223 
op_fillval(RAnal * anal,RAnalOp * op,csh * handle,cs_insn * insn)224 static void op_fillval(RAnal *anal, RAnalOp *op, csh *handle, cs_insn *insn) {
225 	static RRegItem reg;
226 	switch (op->type & R_ANAL_OP_TYPE_MASK) {
227 	case R_ANAL_OP_TYPE_LOAD:
228 		if (OPERAND(1).type == RISCV_OP_MEM) {
229 			ZERO_FILL (reg);
230 			op->src[0] = r_anal_value_new ();
231 			op->src[0]->reg = &reg;
232 			parse_reg_name (op->src[0]->reg, *handle, insn, 1);
233 			op->src[0]->delta = OPERAND(1).mem.disp;
234 		}
235 		break;
236 	case R_ANAL_OP_TYPE_STORE:
237 		if (OPERAND(1).type == RISCV_OP_MEM) {
238 			ZERO_FILL (reg);
239 			op->dst = r_anal_value_new ();
240 			op->dst->reg = &reg;
241 			parse_reg_name (op->dst->reg, *handle, insn, 1);
242 			op->dst->delta = OPERAND(1).mem.disp;
243 		}
244 		break;
245 	case R_ANAL_OP_TYPE_SHL:
246 	case R_ANAL_OP_TYPE_SHR:
247 	case R_ANAL_OP_TYPE_SAR:
248 	case R_ANAL_OP_TYPE_XOR:
249 	case R_ANAL_OP_TYPE_SUB:
250 	case R_ANAL_OP_TYPE_AND:
251 	case R_ANAL_OP_TYPE_ADD:
252 	case R_ANAL_OP_TYPE_OR:
253 		SET_SRC_DST_3_REG_OR_IMM (op);
254 		break;
255 	case R_ANAL_OP_TYPE_MOV:
256 		SET_SRC_DST_3_REG_OR_IMM (op);
257 		break;
258 	case R_ANAL_OP_TYPE_DIV: // UDIV
259 #if 0
260 capstone bug
261 ------------
262 	$ r2 -a riscv -e cfg.bigendian=1 -c "wx 0083001b" -
263 	// should be 3 regs, right?
264 	[0x00000000]> aoj~{}
265 	[
266 	  {
267 	    "opcode": "divu zero, a0, v1",
268 	    "disasm": "divu zero, a0, v1",
269 	    "mnemonic": "divu",
270 	    "sign": false,
271 	    "prefix": 0,
272 	    "id": 192,
273 	    "opex": {
274 	      "operands": [
275 		{
276 		  "type": "reg",
277 		  "value": "a0"
278 		},
279 		{
280 		  "type": "reg",
281 		  "value": "v1"
282 		}
283 	      ]
284 	    },
285 #endif
286 		if (OPERAND(0).type == RISCV_OP_REG && OPERAND(1).type == RISCV_OP_REG && OPERAND(2).type == RISCV_OP_REG) {
287 			SET_SRC_DST_3_REGS (op);
288 		} else if (OPERAND(0).type == RISCV_OP_REG && OPERAND(1).type == RISCV_OP_REG) {
289 			SET_SRC_DST_2_REGS (op);
290 		} else {
291 			eprintf ("Unknown div at 0x%08"PFMT64x"\n", op->addr);
292 		}
293 		break;
294 	}
295 	if (insn && (insn->id == RISCV_INS_SLTI || insn->id == RISCV_INS_SLTIU)) {
296 		SET_SRC_DST_3_IMM (op);
297 	}
298 }
299 
300 static void set_opdir(RAnalOp *op) {
301         switch (op->type & R_ANAL_OP_TYPE_MASK) {
302         case R_ANAL_OP_TYPE_LOAD:
303                 op->direction = R_ANAL_OP_DIR_READ;
304                 break;
305         case R_ANAL_OP_TYPE_STORE:
306                 op->direction = R_ANAL_OP_DIR_WRITE;
307                 break;
308         case R_ANAL_OP_TYPE_LEA:
309                 op->direction = R_ANAL_OP_DIR_REF;
310                 break;
311         case R_ANAL_OP_TYPE_CALL:
312         case R_ANAL_OP_TYPE_JMP:
313         case R_ANAL_OP_TYPE_UJMP:
314         case R_ANAL_OP_TYPE_UCALL:
315                 op->direction = R_ANAL_OP_DIR_EXEC;
316                 break;
317         default:
318                 break;
319         }
320 }
321 
322 static int analop(RAnal *anal, RAnalOp *op, ut64 addr, const ut8 *buf, int len, RAnalOpMask mask) {
323 	int n, ret, opsize = -1;
324 	static csh hndl = 0;
325 	static int omode = -1;
326 	static int obits = 32;
327 	cs_insn* insn;
328 	int mode = (anal->bits==64)? CS_MODE_RISCV64: CS_MODE_RISCV32;
329 	if (mode != omode || anal->bits != obits) {
330 		cs_close (&hndl);
331 		hndl = 0;
332 		omode = mode;
333 		obits = anal->bits;
334 	}
335 // XXX no arch->cpu ?!?! CS_MODE_MICRO, N64
336 	op->addr = addr;
337 	if (len < 4) {
338 		return -1;
339 	}
340 	op->size = 4;
341 	if (hndl == 0) {
342 		ret = cs_open (CS_ARCH_RISCV, mode, &hndl);
343 		if (ret != CS_ERR_OK) {
344 			goto fin;
345 		}
346 		cs_option (hndl, CS_OPT_DETAIL, CS_OPT_ON);
347 	}
348 	n = cs_disasm (hndl, (ut8*)buf, len, addr, 1, &insn);
349 	if (n < 1 || insn->size < 1) {
350 		goto beach;
351 	}
352 	op->id = insn->id;
353 	opsize = op->size = insn->size;
354 	switch (insn->id) {
355 	case RISCV_INS_C_NOP:
356 		op->type = R_ANAL_OP_TYPE_NOP;
357 		break;
358 	case RISCV_INS_INVALID:
359 		op->type = R_ANAL_OP_TYPE_ILL;
360 		break;
361 	case RISCV_INS_C_JALR:
362 		op->type = R_ANAL_OP_TYPE_UCALL;
363 		break;
364 	case RISCV_INS_C_JR:
365 		op->type = R_ANAL_OP_TYPE_UJMP;
366 		break;
367 	case RISCV_INS_C_MV:
368 		op->type = R_ANAL_OP_TYPE_MOV;
369 		break;
370 	case RISCV_INS_JAL:
371 		op->type = R_ANAL_OP_TYPE_CALL;
372 		op->jump = IMM(0);
373 		op->fail = op->addr + op->size;
374 		break;
375 	case RISCV_INS_MRET:
376 	case RISCV_INS_SRET:
377 	case RISCV_INS_URET:
378 		op->type = R_ANAL_OP_TYPE_RET;
379 		break;
380 	}
381 beach:
382 	set_opdir (op);
383 	if (insn && mask & R_ANAL_OP_MASK_OPEX) {
384 		opex (&op->opex, hndl, insn);
385 	}
386 	if (mask & R_ANAL_OP_MASK_ESIL) {
387 		if (analop_esil (anal, op, addr, buf, len, &hndl, insn) != 0) {
388 			r_strbuf_fini (&op->esil);
389 		}
390 	}
391 	if (mask & R_ANAL_OP_MASK_VAL) {
392 		op_fillval (anal, op, &hndl, insn);
393 	}
394 	cs_free (insn, n);
395 	//cs_close (&handle);
396 fin:
397 	return opsize;
398 }
399 
400 static char *get_reg_profile(RAnal *anal) {
401 	const char *p = NULL;
402 	switch (anal->bits) {
403 	case 32: p =
404 		"=PC	pc\n"
405 		"=SP	sp\n" // ABI: stack pointer
406 		"=LR	ra\n" // ABI: return address
407 		"=BP	s0\n" // ABI: frame pointer
408 		"=A0	a0\n"
409 		"=A1	a1\n"
410 
411 		"gpr	pc	.32	0	0\n"
412 		// RV32I regs (ABI names)
413 		// From user-Level ISA Specification, section 2.1
414 		// "zero" has been left out as it ignores writes and always reads as zero
415 		"gpr	ra	.32	4	0\n" // =x1
416 		"gpr	sp	.32	8	0\n" // =x2
417 		"gpr	gp	.32	12	0\n" // =x3
418 		"gpr	tp	.32	16	0\n" // =x4
419 		"gpr	t0	.32	20	0\n" // =x5
420 		"gpr	t1	.32	24	0\n" // =x6
421 		"gpr	t2	.32	28	0\n" // =x7
422 		"gpr	s0	.32	32	0\n" // =x8
423 		"gpr	s1	.32	36	0\n" // =x9
424 		"gpr	a0	.32	40	0\n" // =x10
425 		"gpr	a1	.32	44	0\n" // =x11
426 		"gpr	a2	.32	48	0\n" // =x12
427 		"gpr	a3	.32	52	0\n" // =x13
428 		"gpr	a4	.32	56	0\n" // =x14
429 		"gpr	a5	.32	60	0\n" // =x15
430 		"gpr	a6	.32	64	0\n" // =x16
431 		"gpr	a7	.32	68	0\n" // =x17
432 		"gpr	s2	.32	72	0\n" // =x18
433 		"gpr	s3	.32	76	0\n" // =x19
434 		"gpr	s4	.32	80	0\n" // =x20
435 		"gpr	s5	.32	84	0\n" // =x21
436 		"gpr	s6	.32	88	0\n" // =x22
437 		"gpr	s7	.32	92	0\n" // =x23
438 		"gpr	s8	.32	96	0\n" // =x24
439 		"gpr	s9	.32	100	0\n" // =x25
440 		"gpr	s10	.32	104	0\n" // =x26
441 		"gpr	s11	.32	108	0\n" // =x27
442 		"gpr	t3	.32	112	0\n" // =x28
443 		"gpr	t4	.32	116	0\n" // =x29
444 		"gpr	t5	.32	120	0\n" // =x30
445 		"gpr	t6	.32	124	0\n" // =x31
446 		// RV32F/D regs (ABI names)
447 		// From user-Level ISA Specification, section 8.1 and 9.1
448 		"gpr	ft0	.64	128	0\n" // =f0
449 		"gpr	ft1	.64	136	0\n" // =f1
450 		"gpr	ft2	.64	144	0\n" // =f2
451 		"gpr	ft3	.64	152	0\n" // =f3
452 		"gpr	ft4	.64	160	0\n" // =f4
453 		"gpr	ft5	.64	168	0\n" // =f5
454 		"gpr	ft6	.64	176	0\n" // =f6
455 		"gpr	ft7	.64	184	0\n" // =f7
456 		"gpr	fs0	.64	192	0\n" // =f8
457 		"gpr	fs1	.64	200	0\n" // =f9
458 		"gpr	fa0	.64	208	0\n" // =f10
459 		"gpr	fa1	.64	216	0\n" // =f11
460 		"gpr	fa2	.64	224	0\n" // =f12
461 		"gpr	fa3	.64	232	0\n" // =f13
462 		"gpr	fa4	.64	240	0\n" // =f14
463 		"gpr	fa5	.64	248	0\n" // =f15
464 		"gpr	fa6	.64	256	0\n" // =f16
465 		"gpr	fa7	.64	264	0\n" // =f17
466 		"gpr	fs2	.64	272	0\n" // =f18
467 		"gpr	fs3	.64	280	0\n" // =f19
468 		"gpr	fs4	.64	288	0\n" // =f20
469 		"gpr	fs5	.64	296	0\n" // =f21
470 		"gpr	fs6	.64	304	0\n" // =f22
471 		"gpr	fs7	.64	312	0\n" // =f23
472 		"gpr	fs8	.64	320	0\n" // =f24
473 		"gpr	fs9	.64	328	0\n" // =f25
474 		"gpr	fs10	.64	336	0\n" // =f26
475 		"gpr	fs11	.64	344	0\n" // =f27
476 		"gpr	ft8	.64	352	0\n" // =f28
477 		"gpr	ft9	.64	360	0\n" // =f29
478 		"gpr	ft10	.64	368	0\n" // =f30
479 		"gpr	ft11	.64	376	0\n" // =f31
480 		"gpr	fcsr	.32	384	0\n"
481 		"flg	nx	.1	3072	0\n"
482 		"flg	uf	.1	3073	0\n"
483 		"flg	of	.1	3074	0\n"
484 		"flg	dz	.1	3075	0\n"
485 		"flg	nv	.1	3076	0\n"
486 		"flg	frm	.3	3077	0\n"
487 		;
488 
489 		break;
490 	case 64: p =
491 		"=PC	pc\n"
492 		"=SP	sp\n" // ABI: stack pointer
493 		"=LR	ra\n" // ABI: return address
494 		"=BP	s0\n" // ABI: frame pointer
495 		"=A0	a0\n"
496 		"=A1	a1\n"
497 
498 		"gpr	pc	.64	0	0\n"
499 		// RV64I regs (ABI names)
500 		// From user-Level ISA Specification, section 2.1 and 4.1
501 		// "zero" has been left out as it ignores writes and always reads as zero
502 		"gpr	ra	.64	8	0\n" // =x1
503 		"gpr	sp	.64	16	0\n" // =x2
504 		"gpr	gp	.64	24	0\n" // =x3
505 		"gpr	tp	.64	32	0\n" // =x4
506 		"gpr	t0	.64	40	0\n" // =x5
507 		"gpr	t1	.64	48	0\n" // =x6
508 		"gpr	t2	.64	56	0\n" // =x7
509 		"gpr	s0	.64	64	0\n" // =x8
510 		"gpr	s1	.64	72	0\n" // =x9
511 		"gpr	a0	.64	80	0\n" // =x10
512 		"gpr	a1	.64	88	0\n" // =x11
513 		"gpr	a2	.64	96	0\n" // =x12
514 		"gpr	a3	.64	104	0\n" // =x13
515 		"gpr	a4	.64	112	0\n" // =x14
516 		"gpr	a5	.64	120	0\n" // =x15
517 		"gpr	a6	.64	128	0\n" // =x16
518 		"gpr	a7	.64	136	0\n" // =x17
519 		"gpr	s2	.64	144	0\n" // =x18
520 		"gpr	s3	.64	152	0\n" // =x19
521 		"gpr	s4	.64	160	0\n" // =x20
522 		"gpr	s5	.64	168	0\n" // =x21
523 		"gpr	s6	.64	176	0\n" // =x22
524 		"gpr	s7	.64	184	0\n" // =x23
525 		"gpr	s8	.64	192	0\n" // =x24
526 		"gpr	s9	.64	200	0\n" // =x25
527 		"gpr	s10	.64	208	0\n" // =x26
528 		"gpr	s11	.64	216	0\n" // =x27
529 		"gpr	t3	.64	224	0\n" // =x28
530 		"gpr	t4	.64	232	0\n" // =x29
531 		"gpr	t5	.64	240	0\n" // =x30
532 		"gpr	t6	.64	248	0\n" // =x31
533 		// RV64F/D regs (ABI names)
534 		"gpr	ft0	.64	256	0\n" // =f0
535 		"gpr	ft1	.64	264	0\n" // =f1
536 		"gpr	ft2	.64	272	0\n" // =f2
537 		"gpr	ft3	.64	280	0\n" // =f3
538 		"gpr	ft4	.64	288	0\n" // =f4
539 		"gpr	ft5	.64	296	0\n" // =f5
540 		"gpr	ft6	.64	304	0\n" // =f6
541 		"gpr	ft7	.64	312	0\n" // =f7
542 		"gpr	fs0	.64	320	0\n" // =f8
543 		"gpr	fs1	.64	328	0\n" // =f9
544 		"gpr	fa0	.64	336	0\n" // =f10
545 		"gpr	fa1	.64	344	0\n" // =f11
546 		"gpr	fa2	.64	352	0\n" // =f12
547 		"gpr	fa3	.64	360	0\n" // =f13
548 		"gpr	fa4	.64	368	0\n" // =f14
549 		"gpr	fa5	.64	376	0\n" // =f15
550 		"gpr	fa6	.64	384	0\n" // =f16
551 		"gpr	fa7	.64	392	0\n" // =f17
552 		"gpr	fs2	.64	400	0\n" // =f18
553 		"gpr	fs3	.64	408	0\n" // =f19
554 		"gpr	fs4	.64	416	0\n" // =f20
555 		"gpr	fs5	.64	424	0\n" // =f21
556 		"gpr	fs6	.64	432	0\n" // =f22
557 		"gpr	fs7	.64	440	0\n" // =f23
558 		"gpr	fs8	.64	448	0\n" // =f24
559 		"gpr	fs9	.64	456	0\n" // =f25
560 		"gpr	fs10	.64	464	0\n" // =f26
561 		"gpr	fs11	.64	472	0\n" // =f27
562 		"gpr	ft8	.64	480	0\n" // =f28
563 		"gpr	ft9	.64	488	0\n" // =f29
564 		"gpr	ft10	.64	496	0\n" // =f30
565 		"gpr	ft11	.64	504	0\n" // =f31
566 		"gpr	fcsr	.32	512	0\n"
567 		"flg	nx	.1	4096	0\n"
568 		"flg	uf	.1	4097	0\n"
569 		"flg	of	.1	4098	0\n"
570 		"flg	dz	.1	4099	0\n"
571 		"flg	nv	.1	4100	0\n"
572 		"flg	frm	.3	4101	0\n"
573 		;
574 
575 		break;
576 	}
577 	return (p && *p)? strdup (p): NULL;
578 }
579 
580 static int archinfo(RAnal *anal, int q) {
581 	switch (q) {
582 	case R_ANAL_ARCHINFO_ALIGN:
583 		return 4;
584 	case R_ANAL_ARCHINFO_MAX_OP_SIZE:
585 		return 4;
586 	case R_ANAL_ARCHINFO_MIN_OP_SIZE:
587 		if (anal->bits == 64) {
588 			return 4;
589 		}
590 		return 2;
591 	}
592 	return 0;
593 }
594 
595 RAnalPlugin r_anal_plugin_riscv_cs = {
596 	.name = "riscv.cs",
597 	.desc = "Capstone RISCV analyzer",
598 	.license = "BSD",
599 	.esil = true,
600 	.arch = "riscv",
601 	.get_reg_profile = get_reg_profile,
602 	.archinfo = archinfo,
603 	.bits = 32|64,
604 	.op = &analop,
605 };
606 
607 #ifndef R2_PLUGIN_INCORE
608 R_API RLibStruct radare_plugin = {
609 	.type = R_LIB_TYPE_ANAL,
610 	.data = &r_anal_plugin_riscv_cs,
611 	.version = R2_VERSION
612 };
613 #endif
614 
615 #else
616 RAnalPlugin r_anal_plugin_riscv_cs = {0};
617 #ifndef R2_PLUGIN_INCORE
618 R_API RLibStruct radare_plugin = {
619 	.type = R_LIB_TYPE_ANAL,
620 	.version = R2_VERSION
621 };
622 #endif
623 #endif
624