1 /* radare2 - LGPL - Copyright 2014-2019 - pancake */
2 
3 #include <r_anal.h>
4 #include <r_lib.h>
5 #include <capstone.h>
6 #include <systemz.h>
7 // instruction set: http://www.tachyonsoft.com/inst390m.htm
8 
9 #if CS_API_MAJOR < 2
10 #error Old Capstone not supported
11 #endif
12 
13 #define esilprintf(op, fmt, ...) r_strbuf_setf (&op->esil, fmt, ##__VA_ARGS__)
14 #define INSOP(n) insn->detail->sysz.operands[n]
15 
opex(RStrBuf * buf,csh handle,cs_insn * insn)16 static void opex(RStrBuf *buf, csh handle, cs_insn *insn) {
17 	int i;
18 	PJ *pj = pj_new ();
19 	if (!pj) {
20 		return;
21 	}
22 	pj_o (pj);
23 	pj_ka (pj, "operands");
24 	cs_sysz *x = &insn->detail->sysz;
25 	for (i = 0; i < x->op_count; i++) {
26 		cs_sysz_op *op = x->operands + i;
27 		pj_o (pj);
28 		switch (op->type) {
29 		case SYSZ_OP_REG:
30 			pj_ks (pj, "type", "reg");
31 			pj_ks (pj, "value", cs_reg_name (handle, op->reg));
32 			break;
33 		case SYSZ_OP_IMM:
34 			pj_ks (pj, "type", "imm");
35 			pj_kN (pj, "value", op->imm);
36 			break;
37 		case SYSZ_OP_MEM:
38 			pj_ks (pj, "type", "mem");
39 			if (op->mem.base != SYSZ_REG_INVALID) {
40 				pj_ks (pj, "base", cs_reg_name (handle, op->mem.base));
41 			}
42 			pj_kN (pj, "disp", op->mem.disp);
43 			break;
44 		default:
45 			pj_ks (pj, "type", "invalid");
46 			break;
47 		}
48 		pj_end (pj); /* o operand */
49 	}
50 	pj_end (pj); /* a operands */
51 	pj_end (pj);
52 
53 	r_strbuf_init (buf);
54 	r_strbuf_append (buf, pj_string (pj));
55 	pj_free (pj);
56 }
57 
analop(RAnal * a,RAnalOp * op,ut64 addr,const ut8 * buf,int len,RAnalOpMask mask)58 static int analop(RAnal *a, RAnalOp *op, ut64 addr, const ut8 *buf, int len, RAnalOpMask mask) {
59 	csh handle;
60 	cs_insn *insn;
61 	int mode = CS_MODE_BIG_ENDIAN;
62 	int ret = cs_open (CS_ARCH_SYSZ, mode, &handle);
63 	if (ret == CS_ERR_OK) {
64 		cs_option (handle, CS_OPT_DETAIL, CS_OPT_ON);
65 		// capstone-next
66 		int n = cs_disasm (handle, (const ut8*)buf, len, addr, 1, &insn);
67 		if (n < 1) {
68 			op->type = R_ANAL_OP_TYPE_ILL;
69 		} else {
70 			if (mask & R_ANAL_OP_MASK_OPEX) {
71 				opex (&op->opex, handle, insn);
72 			}
73 			op->size = insn->size;
74 			switch (insn->id) {
75 			case SYSZ_INS_BRCL:
76 			case SYSZ_INS_BRASL:
77 				op->type = R_ANAL_OP_TYPE_CALL;
78 				break;
79 			case SYSZ_INS_BR:
80 				op->type = R_ANAL_OP_TYPE_JMP;
81 				break;
82 			case SYSZ_INS_BRC:
83 			case SYSZ_INS_BER:
84 			case SYSZ_INS_BHR:
85 			case SYSZ_INS_BHER:
86 			case SYSZ_INS_BLR:
87 			case SYSZ_INS_BLER:
88 			case SYSZ_INS_BLHR:
89 			case SYSZ_INS_BNER:
90 			case SYSZ_INS_BNHR:
91 			case SYSZ_INS_BNHER:
92 			case SYSZ_INS_BNLR:
93 			case SYSZ_INS_BNLER:
94 			case SYSZ_INS_BNLHR:
95 			case SYSZ_INS_BNOR:
96 			case SYSZ_INS_BOR:
97 			case SYSZ_INS_BASR:
98 			case SYSZ_INS_BRAS:
99 			case SYSZ_INS_BRCT:
100 			case SYSZ_INS_BRCTG:
101 				op->type = R_ANAL_OP_TYPE_CJMP;
102 				break;
103 			case SYSZ_INS_JE:
104 			case SYSZ_INS_JGE:
105 			case SYSZ_INS_JHE:
106 			case SYSZ_INS_JGHE:
107 			case SYSZ_INS_JH:
108 			case SYSZ_INS_JGH:
109 			case SYSZ_INS_JLE:
110 			case SYSZ_INS_JGLE:
111 			case SYSZ_INS_JLH:
112 			case SYSZ_INS_JGLH:
113 			case SYSZ_INS_JL:
114 			case SYSZ_INS_JGL:
115 			case SYSZ_INS_JNE:
116 			case SYSZ_INS_JGNE:
117 			case SYSZ_INS_JNHE:
118 			case SYSZ_INS_JGNHE:
119 			case SYSZ_INS_JNH:
120 			case SYSZ_INS_JGNH:
121 			case SYSZ_INS_JNLE:
122 			case SYSZ_INS_JGNLE:
123 			case SYSZ_INS_JNLH:
124 			case SYSZ_INS_JGNLH:
125 			case SYSZ_INS_JNL:
126 			case SYSZ_INS_JGNL:
127 			case SYSZ_INS_JNO:
128 			case SYSZ_INS_JGNO:
129 			case SYSZ_INS_JO:
130 			case SYSZ_INS_JGO:
131 			case SYSZ_INS_JG:
132 				op->type = R_ANAL_OP_TYPE_CJMP;
133 				op->jump = INSOP(0).imm;
134 				op->fail = addr+op->size;
135 				break;
136 			case SYSZ_INS_J:
137 				op->type = R_ANAL_OP_TYPE_JMP;
138 				op->jump = INSOP(0).imm;
139 				op->fail = UT64_MAX;
140 				break;
141 			}
142 		}
143 		cs_free (insn, n);
144 		cs_close (&handle);
145 	}
146 	return op->size;
147 }
148 
set_reg_profile(RAnal * anal)149 static bool set_reg_profile(RAnal *anal) {
150 	const char *p =
151 		"=PC	r15\n"
152 		"=LR	r14\n"
153 		"=SP	r13\n"
154 		"=BP	r12\n"
155 		"=A0	r0\n"
156 		"=A1	r1\n"
157 		"=A2	r2\n"
158 		"=A3	r3\n"
159 		"=SN	r0\n"
160 		"gpr	sb	.32	36	0\n" // r9
161 		"gpr	sl	.32	40	0\n" // rl0
162 		"gpr	fp	.32	44	0\n" // r11
163 		"gpr	ip	.32	48	0\n" // r12
164 		"gpr	sp	.32	52	0\n" // r13
165 		"gpr	lr	.32	56	0\n" // r14
166 		"gpr	pc	.32	60	0\n" // r15
167 
168 		"gpr	r0	.32	0	0\n"
169 		"gpr	r1	.32	4	0\n"
170 		"gpr	r2	.32	8	0\n"
171 		"gpr	r3	.32	12	0\n"
172 		"gpr	r4	.32	16	0\n"
173 		"gpr	r5	.32	20	0\n"
174 		"gpr	r6	.32	24	0\n"
175 		"gpr	r7	.32	28	0\n"
176 		"gpr	r8	.32	32	0\n"
177 		"gpr	r9	.32	36	0\n"
178 		"gpr	r10	.32	40	0\n"
179 		"gpr	r11	.32	44	0\n"
180 		"gpr	r12	.32	48	0\n"
181 		"gpr	r13	.32	52	0\n"
182 		"gpr	r14	.32	56	0\n"
183 		"gpr	r15	.32	60	0\n"
184 	;
185 	return r_reg_set_profile_string (anal->reg, p);
186 }
187 
archinfo(RAnal * anal,int q)188 static int archinfo(RAnal *anal, int q) {
189 	switch (q) {
190 	case R_ANAL_ARCHINFO_ALIGN:
191 		return 2;
192 	case R_ANAL_ARCHINFO_MAX_OP_SIZE:
193 		return 4;
194 	case R_ANAL_ARCHINFO_MIN_OP_SIZE:
195 		return 2;
196 	}
197 	return 2;
198 }
199 
200 RAnalPlugin r_anal_plugin_sysz = {
201 	.name = "sysz",
202 	.desc = "Capstone SystemZ microanalysis",
203 	.esil = false,
204 	.license = "BSD",
205 	.arch = "sysz",
206 	.bits = 32|64,
207 	.op = &analop,
208 	.archinfo = archinfo,
209 	.set_reg_profile = &set_reg_profile,
210 };
211 
212 #ifndef R2_PLUGIN_INCORE
213 R_API RLibStruct radare_plugin = {
214 	.type = R_LIB_TYPE_ANAL,
215 	.data = &r_anal_plugin_sysz,
216 	.version = R2_VERSION
217 };
218 #endif
219