1 /* radare - LGPL - Copyright 2015-2018 - pancake */
2 
3 #include <stdio.h>
4 #include <stdlib.h>
5 #include <string.h>
6 #include <r_lib.h>
7 #include <r_util.h>
8 #include <r_flag.h>
9 #include <r_anal.h>
10 #include <r_parse.h>
11 
replace(int argc,const char * argv[],char * newstr)12 static int replace(int argc, const char *argv[], char *newstr) {
13 #define MAXPSEUDOOPS 10
14 	int i, j, k, d;
15 	char ch;
16 	struct {
17 		int narg;
18 		char *op;
19 		char *str;
20 		int args[MAXPSEUDOOPS];
21 	} ops[] = {
22 		{ 0, "abs", "# = abs(#)", { 1, 1 } },
23 		{ 0, "adc", "# = # + #", { 1, 2, 3 } },
24 		{ 3, "add", "# = # + #", { 1, 2, 3 } },
25 		{ 2, "add", "# += #", { 1, 2 } },
26 		{ 2, "adds", "# += #", { 1, 2 } },
27 		{ 3, "adds", "# = # + #", { 1, 2, 3 } },
28 		{ 3, "addw", "# = # + #", { 1, 2, 3 } },
29 		{ 3, "add.w", "# = # + #", { 1, 2, 3 } },
30 		{ 0, "adf", "# = # + #", { 1, 2, 3 } },
31 		{ 0, "adrp", "# = #", { 1, 2 } },
32 		{ 0, "adr", "# = #", { 1, 2 } },
33 		{ 0, "and", "# = # & #", { 1, 2, 3 } },
34 		{ 0, "ands", "# &= #", { 1, 2 } },
35 		{ 0, "asls", "# = # << #", { 1, 2, 3 } },
36 		{ 0, "asl", "# = # << #", { 1, 2, 3 } },
37 		{ 0, "asrs", "# = # >> #", { 1, 2, 3 } },
38 		{ 0, "asr", "# = # >> #", { 1, 2, 3 } },
39 		{ 0, "b", "jmp #", { 1 } },
40 		{ 0, "cbz", "if !# jmp #", { 1, 2 } },
41 		{ 0, "cbnz", "if # jmp #", { 1, 2 } },
42 		{ 0, "b.w", "jmp #", { 1 } },
43 		{ 0, "b.gt", "jmp ifgt #", { 1 } },
44 		{ 0, "b.le", "jmp ifle #", { 1 } },
45 		{ 0, "beq lr", "ifeq ret", { 0 } },
46 		{ 0, "beq", "je #", { 1 } },
47 		{ 0, "call", "# ()", { 1 } },
48 		{ 0, "bl", "# ()", { 1 } },
49 		{ 0, "blx", "# ()", { 1 } },
50 		{ 0, "bx lr", "ret", { 0 } },
51 		{ 0, "bxeq", "je #", { 1 } },
52 		{ 0, "cmf", "if (# == #)", { 1, 2 } },
53 		{ 0, "cmn", "if (# != #)", { 1, 2 } },
54 		{ 0, "cmp", "if (# == #)", { 1, 2 } },
55 		{ 0, "fcmp", "if (# == #)", { 1, 2 } },
56 		{ 0, "tst", "if ((# & #) == 0)", { 1, 2 } },
57 		{ 0, "dvf", "# = # / #", { 1, 2, 3 } },
58 		{ 0, "eor", "# = # ^ #", { 1, 2, 3 } },
59 		{ 1, "bkpt", "breakpoint #", { 1 } },
60 		{ 1, "udf", "undefined #", { 1 } },
61 		{ 2, "sxtb", "# = (char) #", { 1, 2 } },
62 		{ 2, "sxth", "# = (short) #", { 1, 2 } },
63 		{ 0, "fdv", "# = # / #", { 1, 2, 3 } },
64 		{ 0, "fml", "# = # * #", { 1, 2, 3 } },
65 		{ 2, "ldr", "# = #", { 1, 2 } },
66 		{ 2, "ldrh", "# = (word) #", { 1, 2 } },
67 		{ 3, "ldrh", "# = (word) # + #", { 1, 2, 3 } },
68 		{ 2, "ldrb", "# = (byte) #", { 1, 2 } },
69 		{ 3, "ldrb", "# = (byte) # + #", { 1, 2, 3 } },
70 		{ 2, "ldrsb", "# = (byte) #", { 1, 2 } },
71 		{ 2, "ldr.w", "# = #", { 1, 2 } },
72 		{ 2, "ldrsw", "# = #", { 1, 2 } },
73 		{ 3, "ldr", "# = # + #", { 1, 2, 3 } },
74 		{ 3, "ldrb", "# = (byte) # + #", { 1, 2, 3 } },
75 		{ 3, "ldrsb", "# = (byte) # + #", { 1, 2, 3 } },
76 		{ 3, "ldr.w", "# = # + #", { 1, 2, 3 } },
77 		{ 3, "ldrsw", "# = # + #", { 1, 2, 3 } },
78 		{ 0, "lsl", "# = # << #", { 1, 2, 3 } },
79 		{ 0, "lsr", "# = # >> #", { 1, 2, 3 } },
80 		{ 0, "mov", "# = #", { 1, 2 } },
81 		{ 0, "fmov", "# = #", { 1, 2 } },
82 		{ 0, "mvn", "# = ~#", { 1, 2 } },
83 		{ 0, "movz", "# = #", { 1, 2 } },
84 		{ 0, "movk", "# = #", { 1, 2 } },
85 		{ 0, "movn", "# = ~#", { 1, 2 } },
86 		{ 0, "neg", "# = !#", { 1, 2 } },
87 		{ 0, "sxtw", "# = #", { 1, 2 } },
88 		{ 0, "stur", "# = #", { 2, 1 } },
89 		{ 0, "stp", "# = (#, 2)", { 3, 1 } },
90 		{ 0, "ldp", "(#, 2) = 3", { 1 } },
91 		{ 0, "vmov.i32", "# = #", { 1, 2 } },
92 		{ 0, "muf", "# = # * #", { 1, 2, 3 } },
93 		{ 0, "mul", "# = # * #", { 1, 2, 3 } },
94 		{ 0, "fmul", "# = # * #", { 1, 2, 3 } },
95 		{ 0, "muls", "# = # * #", { 1, 2, 3 } },
96 		{ 0, "div", "# = # / #", { 1, 2, 3 } },
97 		{ 0, "fdiv", "# = # / #", { 1, 2, 3 } },
98 		{ 0, "udiv", "# = (unsigned) # / #", { 1, 2, 3 } },
99 		{ 0, "orr", "# = # | #", { 1, 2, 3 } },
100 		{ 0, "rmf", "# = # % #", { 1, 2, 3 } },
101 		{ 0, "bge", "(>=) goto #", { 1 } },
102 		{ 0, "sbc", "# = # - #", { 1, 2, 3 } },
103 		{ 0, "sqt", "# = sqrt(#)", { 1, 2 } },
104 		{ 0, "lsrs", "# = # >> #", { 1, 2, 3 } },
105 		{ 0, "lsls", "# = # << #", { 1, 2, 3 } },
106 		{ 0, "lsr", "# = # >> #", { 1, 2, 3 } },
107 		{ 0, "lsl", "# = # << #", { 1, 2, 3 } },
108 		{ 2, "str", "# = #", { 2, 1 } },
109 		{ 2, "strb", "# = (byte) #", { 2, 1 } },
110 		{ 2, "strh", "# = (half) #", { 2, 1 } },
111 		{ 2, "strh.w", "# = (half) #", { 2, 1 } },
112 		{ 3, "str", "# + # = #", { 2, 3, 1 } },
113 		{ 3, "strb", "# + # = (byte) #", { 2, 3, 1 } },
114 		{ 3, "strh", "# + # = (half) #", { 2, 3, 1 } },
115 		{ 3, "strh.w", "# + # = (half) #", { 2, 3, 1 } },
116 		{ 3, "sub", "# = # - #", { 1, 2, 3 } },
117 		{ 3, "subs", "# = # - #", { 1, 2, 3 } },
118 		{ 3, "fsub", "# = # - #", { 1, 2, 3 } },
119 		{ 2, "sub", "# -= #", { 1, 2 } }, // THUMB
120 		{ 2, "subs", "# -= #", { 1, 2 } }, // THUMB
121 		{ 0, "swp", "swap(#, 2)", { 1 } },
122 		/* arm thumb */
123 		{ 0, "movs", "# = #", { 1, 2 } },
124 		{ 0, "movw", "# = #", { 1, 2 } },
125 		{ 0, "movt", "# |= # << 16", { 1, 2 } },
126 		{ 0, "vmov", "# = (float) # . #", { 1, 2, 3 } },
127 		{ 0, "vdiv.f64", "# = (float) # / #", { 1, 2, 3 } },
128 		{ 0, "addw", "# = # + #", { 1, 2, 3 } },
129 		{ 0, "sub.w", "# = # - #", { 1, 2, 3 } },
130 		{ 0, "tst.w", "if ((# & #) == 0)", { 1, 2 } },
131 		{ 0, "lsr.w", "# = # >> #", { 1, 2, 3 } },
132 		{ 0, "lsl.w", "# = # << #", { 1, 2, 3 } },
133 		{ 0, "pop.w", "pop #", { 1 } },
134 		{ 0, "vpop", "pop #", { 1 } },
135 		{ 0, "vpush", "push #", { 1 } },
136 		{ 0, "push.w", "push #", { 1 } },
137 		{ 0, NULL }
138 	};
139 	if (!newstr) {
140 		return false;
141 	}
142 
143 	for (i = 0; ops[i].op; i++) {
144 		if (ops[i].narg) {
145 			if (argc - 1 != ops[i].narg) {
146 				continue;
147 			}
148 		}
149 		if (!strcmp (ops[i].op, argv[0])) {
150 			if (newstr) {
151 				d = 0;
152 				j = 0;
153 				ch = ops[i].str[j];
154 				for (j = 0, k = 0; ch != '\0'; j++, k++) {
155 					ch = ops[i].str[j];
156 					if (ch == '#') {
157 						if (d >= MAXPSEUDOOPS) {
158 							// XXX Shouldn't ever happen...
159 							continue;
160 						}
161 						int idx = ops[i].args[d];
162 						d++;
163 						if (idx <= 0) {
164 							// XXX Shouldn't ever happen...
165 							continue;
166 						}
167 						const char *w = argv[idx];
168 						if (w) {
169 							strcpy (newstr + k, w);
170 							k += strlen (w) - 1;
171 						}
172 					} else {
173 						newstr[k] = ch;
174 					}
175 				}
176 				newstr[k] = '\0';
177 			}
178 
179 			r_str_replace_char (newstr, '{', '(');
180 			r_str_replace_char (newstr, '}', ')');
181 			return true;
182 		}
183 	}
184 
185 	/* TODO: this is slow */
186 	newstr[0] = '\0';
187 	for (i = 0; i < argc; i++) {
188 		strcat (newstr, argv[i]);
189 		strcat (newstr, (!i || i == argc - 1)? " " : ",");
190 	}
191 	r_str_replace_char (newstr, '{', '(');
192 	r_str_replace_char (newstr, '}', ')');
193 	return false;
194 }
195 
parse(RParse * p,const char * data,char * str)196 static int parse(RParse *p, const char *data, char *str) {
197 	char w0[256], w1[256], w2[256], w3[256];
198 	int i, len = strlen (data);
199 	char *buf, *ptr, *optr;
200 
201 	if (len >= sizeof (w0)) {
202 		return false;
203 	}
204 	// malloc can be slow here :?
205 	if (!(buf = malloc (len + 1))) {
206 		return false;
207 	}
208 	memcpy (buf, data, len + 1);
209 	if (*buf) {
210 		*w0 = *w1 = *w2 = *w3 = '\0';
211 		ptr = strchr (buf, ' ');
212 		if (!ptr) {
213 			ptr = strchr (buf, '\t');
214 		}
215 		if (ptr) {
216 			*ptr = '\0';
217 			for (++ptr; *ptr == ' '; ptr++) {
218 				;
219 			}
220 			strncpy (w0, buf, sizeof (w0) - 1);
221 			strncpy (w1, ptr, sizeof (w1) - 1);
222 
223 			optr = ptr;
224 			if (*ptr == '(') {
225 				ptr = strchr (ptr+1, ')');
226 			}
227 			if (ptr && *ptr == '[') {
228 				ptr = strchr (ptr+1, ']');
229 			}
230 			if (ptr && *ptr == '{') {
231 				ptr = strchr (ptr+1, '}');
232 			}
233 			if (!ptr) {
234 				eprintf ("Unbalanced bracket\n");
235 				free(buf);
236 				return false;
237 			}
238 			ptr = strchr (ptr, ',');
239 			if (ptr) {
240 				*ptr = '\0';
241 				for (++ptr; *ptr == ' '; ptr++) {
242 					;
243 				}
244 				strncpy (w1, optr, sizeof (w1) - 1);
245 				strncpy (w2, ptr, sizeof (w2) - 1);
246 				optr = ptr;
247 				ptr = strchr (ptr, ',');
248 				if (ptr) {
249 					*ptr = '\0';
250 					for (++ptr; *ptr == ' '; ptr++) {
251 						;
252 					}
253 					strncpy (w2, optr, sizeof (w2) - 1);
254 					strncpy (w3, ptr, sizeof (w3) - 1);
255 				}
256 			}
257 		}
258 		{
259 			const char *wa[] = { w0, w1, w2, w3 };
260 			int nw = 0;
261 			for (i = 0; i < 4; i++) {
262 				if (wa[i][0]) {
263 					nw++;
264 				}
265 			}
266 			replace (nw, wa, str);
267 		}
268 	}
269 	{
270 		char *s = strdup (str);
271 		s = r_str_replace (s, "+ -", "- ", 1);
272 		s = r_str_replace (s, "- -", "+ ", 1);
273 		strcpy (str, s);
274 		free (s);
275 	}
276 	free (buf);
277 	return true;
278 }
279 
subs_var_string(RParse * p,RAnalVarField * var,char * tstr,const char * oldstr,const char * reg,int delta)280 static char *subs_var_string(RParse *p, RAnalVarField *var, char *tstr, const char *oldstr, const char *reg, int delta) {
281 	char *newstr = p->localvar_only
282 		? r_str_newf ("%s", var->name)
283 		: r_str_newf ("%s %c %s", reg, delta > 0 ? '+' : '-', var->name);
284 	if (IS_UPPER (*tstr)) {
285 		char *space = strrchr (newstr, ' ');
286 		if (space) {
287 			*space = 0;
288 			r_str_case (newstr, true);
289 			*space = ' ';
290 		}
291 	}
292 	char *ret = r_str_replace (tstr, oldstr, newstr, 1);
293 	free (newstr);
294 	return ret;
295 }
296 
mount_oldstr(RParse * p,const char * reg,st64 delta,bool ucase)297 static char *mount_oldstr(RParse* p, const char *reg, st64 delta, bool ucase) {
298 	const char *tmplt;
299 	char *oldstr;
300 	if (delta > -10 && delta < 10) {
301 		if (p->pseudo) {
302 			char sign = '+';
303 			if (delta < 0) {
304 				sign = '-';
305 			}
306 			oldstr = r_str_newf ("%s %c %" PFMT64d, reg, sign, R_ABS (delta));
307 		} else {
308 			oldstr = r_str_newf ("%s, %" PFMT64d, reg, delta);
309 		}
310 	} else if (delta > 0) {
311 		tmplt = p->pseudo ? "%s + 0x%x" : (ucase ? "%s, 0x%X" : "%s, 0x%x");
312 		oldstr = r_str_newf (tmplt, reg, delta);
313 	} else {
314 		tmplt = p->pseudo ? "%s - 0x%x" : (ucase ? "%s, -0x%X" : "%s, -0x%x");
315 		oldstr = r_str_newf (tmplt, reg, -delta);
316 	}
317 	if (ucase) {
318 		char *comma = strchr (oldstr, ',');
319 		if (comma) {
320 			*comma = 0;
321 			r_str_case (oldstr, true);
322 			*comma = ',';
323 		}
324 	}
325 	return oldstr;
326 }
327 
subvar(RParse * p,RAnalFunction * f,ut64 addr,int oplen,char * data,char * str,int len)328 static bool subvar(RParse *p, RAnalFunction *f, ut64 addr, int oplen, char *data, char *str, int len) {
329 	RList *spargs = NULL;
330 	RList *bpargs = NULL;
331 	RListIter *iter;
332 	RAnal *anal = p->analb.anal;
333 	char *oldstr;
334 	char *tstr = strdup (data);
335 	if (!tstr) {
336 		return false;
337 	}
338 
339 	if (!p->varlist) {
340 		free (tstr);
341 		return false;
342 	}
343 	if (p->subrel) {
344 		char *rip;
345 		if (p->pseudo) {
346 			rip = (char *)r_str_casestr (tstr, "[pc +");
347 			if (!rip) {
348 				rip = (char *)r_str_casestr (tstr, "[pc -");
349 			}
350 		} else {
351 			rip = (char *)r_str_casestr (tstr, "[pc, ");
352 		}
353 
354 		if (rip && !strchr (rip + 4, ',')) {
355 			rip += 4;
356 			char *tstr_new, *ripend = strchr (rip, ']');
357 			const char *neg = strchr (rip, '-');
358 			ut64 off = (oplen == 2 || strstr (tstr, ".w") || strstr(tstr, ".W")) ? 4 : 8;
359 			ut64 repl_num = (addr + off) & ~3;
360 			if (!ripend) {
361 				ripend = "]";
362 			}
363 			if (neg) {
364 				repl_num -= r_num_get (NULL, neg + 1);
365 			} else {
366 				repl_num += r_num_get (NULL, rip);
367 			}
368 			rip -= 3;
369 			*rip = 0;
370 			tstr_new = r_str_newf ("%s0x%08"PFMT64x"%s", tstr, repl_num, ripend);
371 			free (tstr);
372 			tstr = tstr_new;
373 		}
374 	}
375 
376 	bpargs = p->varlist (f, 'b');
377 	spargs = p->varlist (f, 's');
378 	bool ucase = IS_UPPER (*tstr);
379 	RAnalVarField *var;
380 	r_list_foreach (bpargs, iter, var) {
381 		st64 delta = p->get_ptr_at
382 			? p->get_ptr_at (f, var->delta, addr)
383 			: ST64_MAX;
384 		if (delta == ST64_MAX && var->field) {
385 			delta = var->delta + f->bp_off;
386 		} else if (delta == ST64_MAX) {
387 			continue;
388 		}
389 		const char *reg = NULL;
390 		if (p->get_reg_at) {
391 			reg = p->get_reg_at (f, var->delta, addr);
392 		}
393 		if (!reg) {
394 			reg = anal->reg->name[R_REG_NAME_BP];
395 		}
396 		oldstr = mount_oldstr (p, reg, delta, ucase);
397 		if (strstr (tstr, oldstr)) {
398 			tstr = subs_var_string (p, var, tstr, oldstr, reg, delta);
399 			free (oldstr);
400 			break;
401 		}
402 		free (oldstr);
403 	}
404 	r_list_foreach (spargs, iter, var) {
405 		st64 delta = p->get_ptr_at
406 			? p->get_ptr_at (f, var->delta, addr)
407 			: ST64_MAX;
408 		if (delta == ST64_MAX && var->field) {
409 			delta = var->delta;
410 		} else if (delta == ST64_MAX) {
411 			continue;
412 		}
413 		const char *reg = NULL;
414 		if (p->get_reg_at) {
415 			reg = p->get_reg_at (f, var->delta, addr);
416 		}
417 		if (!reg) {
418 			reg = anal->reg->name[R_REG_NAME_SP];
419 		}
420 		oldstr = mount_oldstr (p, reg, delta, ucase);
421 		if (strstr (tstr, oldstr)) {
422 			tstr = subs_var_string (p, var, tstr, oldstr, reg, delta);
423 			free (oldstr);
424 			break;
425 		}
426 		free (oldstr);
427 	}
428 	r_list_free (bpargs);
429 	r_list_free (spargs);
430 	if (len > strlen (tstr)) {
431 		strcpy  (str, tstr);
432 	} else {
433 		// TOO BIG STRING CANNOT REPLACE HERE
434 		free (tstr);
435 		return false;
436 	}
437 	free (tstr);
438 	return true;
439 }
440 
441 RParsePlugin r_parse_plugin_arm_pseudo = {
442 	.name = "arm.pseudo",
443 	.desc = "ARM/ARM64 pseudo syntax",
444 	.parse = parse,
445 	.subvar = &subvar,
446 };
447 
448 #ifndef R2_PLUGIN_INCORE
449 R_API RLibStruct radare_plugin = {
450 	.type = R_LIB_TYPE_PARSE,
451 	.data = &r_parse_plugin_arm_pseudo,
452 	.version = R2_VERSION
453 };
454 #endif
455