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