1 /* radare - LGPL - Copyright 2012-2017 - pancake */
2 
3 #include <stdio.h>
4 #include <stdlib.h>
5 #include <string.h>
6 
7 #include <r_lib.h>
8 #include <r_util.h>
9 #include <r_flag.h>
10 #include <r_anal.h>
11 #include <r_parse.h>
12 
can_replace(const char * str,int idx,int max_operands)13 static int can_replace(const char *str, int idx, int max_operands) {
14 	if (str[idx] > '9' || str[idx] < '1') {
15 		return false;
16 	}
17 	if (str[idx + 1] != '\x00' && str[idx + 1] <= '9' && str[idx + 1] >= '1') {
18 		return false;
19 	}
20 	if ((int)((int)str[idx] - 0x30) > max_operands) {
21 		return false;
22 	}
23 	return true;
24 }
25 
replace(int argc,const char * argv[],char * newstr)26 static int replace(int argc, const char *argv[], char *newstr) {
27 	int i,j,k;
28 	struct {
29 		char *op;
30 		char *str;
31 		int max_operands;
32 	} ops[] = {
33 		{ "add", "1 = 2 + 3", 3},
34 		{ "addi",  "1 = 2 + 3", 3},
35 		{ "addiu",  "1 = 2 + 3", 3},
36 		{ "addu",  "1 = 2 + 3", 3},
37 		{ "and",  "1 = 2 & 3", 3},
38 		{ "andi",  "1 = 2 & 3", 3},
39 		{ "b",  "goto 1", 1},
40 		{ "bal",  "call 1", 1},
41 		{ "begzal", "if (1 >= 0) call 2", 2},
42 		{ "beq",  "if (1 == 2) goto 3", 3},
43 		{ "beqz",  "if (!1) goto 2", 2},
44 		{ "bgez", "if (1 >= 0) goto 2", 2},
45 		{ "bgtz", "if (1 > 0) goto 2", 2},
46 		{ "blez", "if (1 <= 0) goto 2", 2},
47 		{ "bltz", "if (1 < 0) goto 2", 2},
48 		{ "bltzal", "if (1 < 0) call 2", 2},
49 		{ "bne",  "if (1 != 2) goto 3", 3},
50 		{ "bnez",  "if (1) goto 2", 2},
51 		{ "j",   "goto 1", 1},
52 		{ "jal",   "call 1", 1},
53 		{ "jalr",  "call 1", 1},
54 		{ "jr",   "goto 1", 1},
55 		{ "lb",  "1 = byte [3 + 2]", 3},
56 		{ "lbu",  "1 = (unsigned) byte [3 + 2]", 3},
57 		{ "lh",  "1 = halfword [3 + 2]", 3},
58 		{ "lhu",  "1 = (unsigned) halfword [3 + 2]", 3},
59 		{ "li",   "1 = 2", 2},
60 		{ "lui",  "1 = 2 << 16", 2},
61 		{ "lw",  "1 = [3 + 2]", 3},
62 		{ "mfhi",  "1 = hi", 1},
63 		{ "mflo",  "1 = lo", 1},
64 		{ "move",  "1 = 2", 2},
65 		{ "movn",  "if (3) 1 = 2", 3},
66 		{ "movz",  "if (!3) 1 = 2", 3},
67 		{ "mult",  "(hi,lo) = 1 * 2", 2},
68 		{ "multu",  "unsigned (hi,lo) = 1 * 2", 2},
69 		{ "mul",  "1 = 2 * 3", 3},
70 		{ "mulu",  "1 = 2 * 3", 3},
71 		{ "negu",  "1 = ~2", 2},
72 		{ "nop",   "", 0},
73 		{ "nor",   "1 = ~(2 | 3)", 3},
74 		{ "or",   "1 = 2 | 3", 3},
75 		{ "ori",   "1 = 2 | 3", 3},
76 		{ "sb",  "byte [3 + 2] = 1", 3},
77 		{ "sh",  "halfword [3 + 2] = 1", 3},
78 		{ "sll",  "1 = 2 << 3", 3},
79 		{ "sllv",  "1 = 2 << 3", 3},
80 		{ "slr",  "1 = 2 >> 3", 3}, // logic
81 		{ "slt",  "1 = (2 < 3)", 3},
82 		{ "slti",  "1 = (2 < 3)", 3},
83 		{ "sltiu",  "1 = (unsigned) (2 < 3)", 3},
84 		{ "sltu",  "1 = (unsigned) (2 < 3)", 3},
85 		{ "sra",  "1 = (signed) 2 >> 3", 3}, // arithmetic
86 		{ "srl",  "1 = 2 >> 3", 3},
87 		{ "srlv",  "1 = 2 >> 3", 3},
88 		{ "subu",  "1 = 2 - 3", 3},
89 		{ "sub",  "1 = 2 - 3", 3},
90 		{ "sw",  "[3 + 2] = 1", 3},
91 		{ "syscall",  "syscall", 0},
92 		{ "xor",  "1 = 2 ^ 3", 3},
93 		{ "xori",  "1 = 2 ^ 3", 3},
94 		{ NULL }
95 	};
96 
97 	for (i=0; ops[i].op != NULL; i++) {
98 		if (!strcmp (ops[i].op, argv[0])) {
99 			if (newstr != NULL) {
100 				for (j=k=0;ops[i].str[j]!='\0';j++,k++) {
101 					if (can_replace (ops[i].str, j, ops[i].max_operands)) {
102 						const char *w = argv[ ops[i].str[j]-'0' ];
103 						if (w != NULL) {
104 							strcpy (newstr+k, w);
105 							k += strlen (w) - 1;
106 						}
107 					} else {
108 						newstr[k] = ops[i].str[j];
109 					}
110 				}
111 				newstr[k]='\0';
112 			}
113 			return true;
114 		}
115 	}
116 
117 	/* TODO: this is slow */
118 	if (newstr != NULL) {
119 		newstr[0] = '\0';
120 		for (i=0; i<argc; i++) {
121 			strcat (newstr, argv[i]);
122 			strcat (newstr, (i == 0 || i== argc - 1)?" ":", ");
123 		}
124 	}
125 
126 	return false;
127 }
128 
129 #define WSZ 64
parse(RParse * p,const char * data,char * str)130 static int parse(RParse *p, const char *data, char *str) {
131 	int i, len = strlen (data);
132 	char w0[WSZ];
133 	char w1[WSZ];
134 	char w2[WSZ];
135 	char w3[WSZ];
136 	char w4[WSZ];
137 	char *buf, *ptr, *optr;
138 
139 	if (!strcmp (data, "jr ra")) {
140 		strcpy (str, "ret");
141 		return true;
142 	}
143 
144 	// malloc can be slow here :?
145 	if (!(buf = malloc (len + 1))) {
146 		return false;
147 	}
148 	memcpy (buf, data, len+1);
149 
150 	r_str_replace_char (buf, '(', ',');
151 	r_str_replace_char (buf, ')', ' ');
152 	r_str_trim (buf);
153 
154 	if (*buf) {
155 		w0[0]='\0';
156 		w1[0]='\0';
157 		w2[0]='\0';
158 		w3[0]='\0';
159 		w4[0]='\0';
160 		ptr = strchr (buf, ' ');
161 		if (!ptr) {
162 			ptr = strchr (buf, '\t');
163 		}
164 		if (ptr) {
165 			*ptr = '\0';
166 			for (++ptr; *ptr == ' '; ptr++) {
167 				;
168 			}
169 			strncpy (w0, buf, WSZ - 1);
170 			strncpy (w1, ptr, WSZ - 1);
171 
172 			optr=ptr;
173 			ptr = strchr (ptr, ',');
174 			if (ptr) {
175 				*ptr = '\0';
176 				for (++ptr; *ptr == ' '; ptr++) {
177 					;
178 				}
179 				strncpy (w1, optr, WSZ - 1);
180 				strncpy (w2, ptr, WSZ - 1);
181 				optr=ptr;
182 				ptr = strchr (ptr, ',');
183 				if (ptr) {
184 					*ptr = '\0';
185 					for (++ptr; *ptr == ' '; ptr++) {
186 						;
187 					}
188 					strncpy (w2, optr, WSZ - 1);
189 					strncpy (w3, ptr, WSZ - 1);
190 					optr=ptr;
191 // bonus
192 					ptr = strchr (ptr, ',');
193 					if (ptr) {
194 						*ptr = '\0';
195 						for (++ptr; *ptr == ' '; ptr++) {
196 							;
197 						}
198 						strncpy (w3, optr, WSZ - 1);
199 						strncpy (w4, ptr, WSZ - 1);
200 					}
201 				}
202 			}
203 		} else {
204 			strncpy (w0, buf, WSZ - 1);
205 		}
206 		{
207 			const char *wa[] = { w0, w1, w2, w3, w4 };
208 			int nw = 0;
209 			for (i=0; i<4; i++) {
210 				if (wa[i][0] != '\0') {
211 					nw++;
212 				}
213 			}
214 			replace (nw, wa, str);
215 {
216 	char *p = strdup (str);
217 	p = r_str_replace (p, "+ -", "- ", 0);
218 	p = r_str_replace (p, " + ]", " + 0]", 0);
219 
220 	p = r_str_replace (p, "zero", "0", 1);
221 	if (!strncmp (p, "0 = ", 4)) {
222 		*p = 0; // nop
223 	}
224 	if (!strcmp (w1, w2)) {
225 		char a[32], b[32];
226 #define REPLACE(x,y) do { \
227 		int snprintf_len1_ = snprintf (a, 32, x, w1, w1); \
228 		int snprintf_len2_ = snprintf (b, 32, y, w1);	\
229 		if (snprintf_len1_ < 32 && snprintf_len2_ < 32) { \
230 			p = r_str_replace (p, a, b, 0); \
231 		} \
232 	} while (0)
233 
234 		// TODO: optimize
235 		REPLACE ("%s = %s +", "%s +=");
236 		REPLACE ("%s = %s -", "%s -=");
237 		REPLACE ("%s = %s &", "%s &=");
238 		REPLACE ("%s = %s |", "%s |=");
239 		REPLACE ("%s = %s ^", "%s ^=");
240 		REPLACE ("%s = %s >>", "%s >>=");
241 		REPLACE ("%s = %s <<", "%s <<=");
242 	}
243 	p = r_str_replace (p, ":", "0000", 0);
244 	strcpy (str, p);
245 	free (p);
246 }
247 		}
248 	}
249 	free (buf);
250 	return true;
251 }
252 
subvar(RParse * p,RAnalFunction * f,ut64 addr,int oplen,char * data,char * str,int len)253 static bool subvar(RParse *p, RAnalFunction *f, ut64 addr, int oplen, char *data, char *str, int len) {
254 	RListIter *iter;
255 	char *oldstr;
256 	char *tstr = strdup (data);
257 	RAnal *anal = p->analb.anal;
258 
259 	if (!p->varlist) {
260 		free (tstr);
261 		return false;
262 	}
263 	RList *bpargs = p->varlist (f, 'b');
264 	RList *spargs = p->varlist (f, 's');
265 	const bool ucase = IS_UPPER (*tstr);
266 	RAnalVarField *var;
267 	r_list_foreach (spargs, iter, var) {
268 		st64 delta = p->get_ptr_at
269 			? p->get_ptr_at (f, var->delta, addr)
270 			: ST64_MAX;
271 		if (delta == ST64_MAX && var->field) {
272 			delta = var->delta;
273 		} else if (delta == ST64_MAX) {
274 			continue;
275 		}
276 		const char *reg = NULL;
277 		if (p->get_reg_at) {
278 			reg = p->get_reg_at (f, var->delta, addr);
279 		}
280 		if (!reg) {
281 			reg = anal->reg->name[R_REG_NAME_SP];
282 		}
283 		char *tmpf;
284 		//TODO: honor asm pseudo
285 		if (R_ABS (delta) < 10) {
286 			tmpf = "%d(%s)";
287 		} else if (delta > 0) {
288 			tmpf = "0x%x(%s)";
289 		} else {
290 			tmpf = "-0x%x(%s)";
291 		}
292 		oldstr = r_str_newf (tmpf, R_ABS (delta), reg);
293 		if (ucase) {
294 			char *comma = strchr (oldstr, ',');
295 			if (comma) {
296 				*comma = 0;
297 				r_str_case (oldstr, true);
298 				*comma = ',';
299 			}
300 		}
301 		if (strstr (tstr, oldstr)) {
302 			char *newstr = (p->localvar_only)
303 				? r_str_newf ("(%s)", var->name)
304 				: r_str_newf ("%s%s(%s)", delta > 0 ? "" : "-", var->name, reg);
305 			tstr = r_str_replace (tstr, oldstr, newstr, 1);
306 			free (newstr);
307 			free (oldstr);
308 			break;
309 		}
310 		free (oldstr);
311 	}
312 	r_list_foreach (bpargs, iter, var) {
313 		char *tmpf = NULL;
314 		st64 delta = p->get_ptr_at
315 			? p->get_ptr_at (f, var->delta, addr)
316 			: ST64_MAX;
317 		if (delta == ST64_MAX && var->field) {
318 			delta = var->delta + f->bp_off;
319 		} else if (delta == ST64_MAX) {
320 			continue;
321 		}
322 		const char *reg = NULL;
323 		if (p->get_reg_at) {
324 			reg = p->get_reg_at (f, var->delta, addr);
325 		}
326 		if (!reg) {
327 			reg = anal->reg->name[R_REG_NAME_BP];
328 		}
329 		if (R_ABS (delta) < 10) {
330 			tmpf = "%d(%s)";
331 		} else if (delta > 0) {
332 			tmpf = "0x%x(%s)";
333 		} else {
334 			tmpf = "-0x%x(%s)";
335 		}
336 		oldstr = r_str_newf (tmpf, R_ABS (delta), reg);
337 		if (ucase) {
338 			char *comma = strchr (oldstr, ',');
339 			if (comma) {
340 				*comma = 0;
341 				r_str_case (oldstr, true);
342 				*comma = ',';
343 			}
344 		}
345 		if (strstr (tstr, oldstr)) {
346 			char *newstr = (p->localvar_only)
347 				? r_str_newf ("(%s)", var->name)
348 				: r_str_newf ("%s%s(%s)", delta > 0 ? "" : "-", var->name, reg);
349 			tstr = r_str_replace (tstr, oldstr, newstr, 1);
350 			free (newstr);
351 			free (oldstr);
352 			break;
353 		}
354 		free (oldstr);
355 	}
356 	bool ret = true;
357 	if (len > strlen (tstr)) {
358 		strcpy (str, tstr);
359 	} else {
360 		// TOO BIG STRING CANNOT REPLACE HERE
361 		ret = false;
362 	}
363 	free (tstr);
364 	r_list_free (bpargs);
365 	r_list_free (spargs);
366 	return ret;
367 }
368 
369 RParsePlugin r_parse_plugin_mips_pseudo = {
370 	.name = "mips.pseudo",
371 	.desc = "MIPS pseudo syntax",
372 	.init = NULL,
373 	.fini = NULL,
374 	.parse = parse,
375 	.subvar = subvar,
376 };
377 
378 #ifndef R2_PLUGIN_INCORE
379 R_API RLibStruct radare_plugin = {
380 	.type = R_LIB_TYPE_PARSE,
381 	.data = &r_parse_plugin_mips_pseudo,
382 	.version = R2_VERSION
383 };
384 #endif
385