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
replace(int argc,const char * argv[],char * newstr)13 static int replace(int argc, const char *argv[], char *newstr) {
14 int i,j,k;
15 struct {
16 char *op;
17 char *str;
18 } ops[] = {
19 { "rsub-int", "1 = 2 - 3"},
20 { "float-to-double", "1 = (double)(float) 2"},
21 { "float-to-long", "1 = (long)(float) 2"},
22 { "float-to-int", "1 = (int)(float) 2"},
23 { "long-to-float", "1 = (float)(long) 2"},
24 { "long-to-int", "1 = (int)(long) 2"},
25 { "long-to-double", "1 = (double) 2"},
26 { "double-to-long", "1 = (long) 2"},
27 { "double-to-int", "1 = (int) 2"},
28 { "int-to-double", "1 = (double) 2"},
29 { "int-to-long", "1 = (long) 2"},
30 { "int-to-byte", "1 = (byte) 2"},
31 { "aget-byte", "1 = (byte) 2[3]"},
32 { "aget-short", "1 = (short) 2[3]"},
33 { "aget-object", "1 = (object) 2[3]"},
34 { "sput-wide", "1 = 2"},
35 { "sput-object", "1 = 2"},
36 { "add-long", "1 = 2 + 3"},
37 { "add-double", "1 = 2 + 3"},
38 { "mul-long", "1 = 2 * 3"},
39 { "const-string/jumbo", "1 = (jumbo-string) 2"},
40 { "const-string", "1 = (string) 2"},
41 { "const-wide", "1 = (wide) 2"},
42 { "const/4", "1 = (wide) 2"},
43 { "cmp-int", "1 = (2 == 3)"},
44 { "cmp-long", "1 = (2 == 3)"},
45 { "cmpl-double", "1 = (double)(2 == 3)"},
46 { "cmpl-float", "1 = (float)(2 == 3)"},
47 { "cmpl-int", "1 = (int)(2 == 3)"},
48 { "cmpg-double", "1 = (2 == 3)"},
49 { "cmpg-float", "1 = (2 == 3)"},
50 { "or-int/2addr", "1 |= 2"},
51 { "or-long", "1 |= 2"},
52 { "and-long/2addr", "1 &= (long) 2"},
53 { "and-int", "1 &= (int) 2"},
54 { "and-byte", "1 &= (byte) 2"},
55 { "sub-float/2addr", "1 -= 2"},
56 { "sub-float", "1 = 2 - 3"},
57 { "sub-int", "1 = (int) 2 - 3"},
58 { "sub-long", "1 = (long) 2 - 3"},
59 { "sub-long/2addr", "1 -= (long) 2"},
60 { "sub-int/2addr", "1 -= 2"},
61 { "move", "1 = 2"},
62 { "move/16", "1 = 2"},
63 { "move-object", "1 = (object) 2"},
64 { "move-object/16", "1 = (object) 2"},
65 { "move-object/from16", "1 = (object) 2"},
66 { "move-wide/from16", "1 = (wide) 2"},
67 { "array-length", "1 = Array.length (2)"},
68 { "new-array", "1 = new array (2, 3)"},
69 { "new-instance", "1 = new 2"},
70 { "shr-long/2addr", "1 >>= 2"},
71 { "shr-long", "1 = (long) 2 >> 3"},
72 { "shr-int", "1 = (int) 2 >> 3"},
73 { "ushr-int", "1 = (int) 2 >>> 3"},
74 { "ushr-int/2addr", "1 >>>= 2"},
75 { "ushr-long", "1 = (long) 2 >>> 3"},
76 { "ushl-int/2addr", "1 <<<= 2"},
77 { "shl-int/2addr", "1 <<<= 2"},
78 { "shl-int", "1 = (int) 2 << 3"},
79 { "shl-long", "1 = (long) 2 << 3"},
80 { "move/from16", "1 = 2"},
81 { "move-exception", "1 = exception"},
82 { "move-result", "1 = result"},
83 { "move-result-wide", "1 = (wide) result"},
84 { "move-result-object", "1 = (object) result"},
85 { "const-wide/high16", "1 = 2"},
86 { "const/16", "1 = 2"},
87 { "const-wide/16", "1 = 2"},
88 { "const-wide/32", "1 = 2"},
89 { "const-class", "1 = (class) 2"},
90 { "const/high16", "1 = 2"},
91 { "const", "1 = 2"},
92 { "rem-long", "1 = (long) 2 % 3"},
93 { "rem-double", "1 = (double) 2 % 3"},
94 { "rem-float", "1 = (float) 2 % 3"},
95 { "rem-long/2addr", "1 %= 2"},
96 { "rem-float/2addr", "1 %= (float) 2"},
97 { "rem-double/2addr", "1 %= (double) 2"},
98 { "instance-of", "1 = insteanceof (2) == 3"},
99 { "aput", "2[3] = 1"},
100 { "aput-byte", "2[3] = (byte) 1"},
101 { "aput-short", "2[3] = (short) 1"},
102 { "aput-object", "2[3] = (object) 1"},
103 { "aput-wide", "2[3] = (wide) 1"},
104 { "aput-char", "2[3] = (char) 1"},
105 { "aput-boolean", "2[3] = (bool) 1"},
106 { "aget", "1 = 2[3]"},
107 { "aget-wide", "1 = (wide) 2[3]"},
108 { "aget-char", "1 = (char) 2[3]"},
109 { "aget-boolean", "1 = (boolean) 2[3]"},
110 { "sget", "1 = 2"},
111 { "sget-char", "1 = (char) 2"},
112 { "sget-short", "1 = (short) 2"},
113 { "sget-boolean", "1 = (bool) 2"},
114 { "sget-object", "1 = (object) 2"},
115 { "iput", "2[3] = 1"},
116 { "iput-object", "2[3] = (object) 1"},
117 { "iput-byte", "2[3] = (byte) 1"},
118 { "iput-char", "2[3] = (char) 1"},
119 { "iput-boolean", "2[3] = (bool) 1"},
120 { "sput-boolean", "2[3] = (bool) 1"},
121 { "sput-char", "2[3] = (char) 1"},
122 { "iput-int", "2[3] = (int) 1"},
123 { "iget", "1 = 2[3]"},
124 { "sget-byte", "1 = (byte) 2 [3]"},
125 { "iget-byte", "1 = (byte) 2 [3]"},
126 { "iget-char", "1 = (char) 2 [3]"},
127 { "iget-short", "1 = (short) 2 [3]"},
128 { "iget-wide", "1 = (wide) 2 [3]"},
129 { "iget-object", "1 = (2) 3"},
130 { "iget-boolean", "1 = (bool) 2 [3]"},
131 { "+iget-wide-volatile", "1 = (wide-volatile) 2 [3]"},
132 { "if-eq", "if (1 == 2) goto 3"},
133 { "if-lt", "if (1 < 2) goto 3"},
134 { "if-ne", "if (1 != 2) goto 3"},
135 { "if-eqz", "if (!1) goto 2"},
136 { "if-ge", "if (1 > zero) goto 2"},
137 { "if-le", "if (1 <= 2) goto 3"},
138 { "if-gtz", "if (1 > 0) goto 2"},
139 { "filled-new-array", "1 = new Array(2)"},
140 { "neg-long", "1 = -2"},
141 { "neg-double", "1 = -2"},
142 { "neg-float", "1 = -2"},
143 { "not-int", "1 = !2"},
144 { "packed-switch", "switch 2"},
145 { "sparse-switch", "switch 2"},
146 { "invoke-direct", "call 2 1"},
147 { "invoke-direct/range", "call 2 1"},
148 { "invoke-interface", "call 2 1"},
149 { "invoke-static", "call 2 1"},
150 { "invoke-super", "call super 2 1"},
151 { "invoke-super/range", "call super 2 1"},
152 { "invoke-polymorphic", "call polymorphic 2 1" },
153 { "invoke-virtual/range", "call 2 1"},
154 { "invoke-virtual", "call 2 1"},
155 { "+invoke-virtual-quick", "call 2 1"},
156 { "+invoke-interface/range", "call 2 1"},
157 { "invoke-interface/range", "call 2 1"},
158 { "div-float/2addr", "1 /= (float) 2"},
159 { "div-double/2addr", "1 /= (double) 2"},
160 { "div-double", "1 = (double) 2 / 3"},
161 { "div-float", "1 = 2 / 3"},
162 { "div-int/lit8", "1 = 2 / 3"},
163 { "div-int/lit16", "1 = 2 / 3"},
164 { "div-int/2addr", "1 /= 2"},
165 { "div-int", "1 = (int)(2 / 3)"},
166 { "goto/16", "goto 1"},
167 { "goto/32", "goto 1"},
168 { "or-int", "1 = (int)(2 | 3)"},
169 { "xor-int", "1 = (int)(2 ^ 3)"},
170 { "xor-int/2addr", "1 ^= 2"},
171 { "xor-byte", "1 = (byte)(2 ^ 3)"},
172 { "xor-short", "1 = (short)(2 ^ 3)"},
173 { "sub-int", "1 = (int)(2 - 3)"},
174 { "if-nez", "if (1) goto 2"},
175 { "if-ltz", "if (1 <=) goto 2"},
176 { "mul-int", "1 = (int)(2 * 3)"},
177 { "mul-int/lit8", "1 = (2 * 3)"},
178 { "check-cast", "if (1 instanceof 2)"},
179 { "add-int", "1 = (int)(2 + 3)"},
180 { "add-int/lit8", "1 = 2 + 3"},
181 { "add-int/lit16", "1 = 2 + 3"},
182 { "add-int/2addr", "1 += 2"},
183 { "add-double", "1 = (double)(2 + 3)"},
184 { "add-double/2addr", "1 += (double)2"},
185 { "mul-float/2addr", "1 *= 2"},
186 { "mul-float", "1 = 2 * 3"},
187 { "xor-long", "1 = (long)(2 ^ 3)"},
188 { "mul-double", "1 = 2 * 3"},
189 { "move-wide", "1 = 2"},
190 { "move-wide/16", "1 = 2"},
191 { "return-wide", "return (wide) 1"},
192 { "return-object", "return (object) 1"},
193 // { "sget", "1 = 2[3]"},
194 { NULL }
195 };
196
197 for (i=0; ops[i].op != NULL; i++) {
198 if (!strcmp (ops[i].op, argv[0])) {
199 if (newstr != NULL) {
200 for (j=k=0;ops[i].str[j]!='\0';j++,k++) {
201 if (ops[i].str[j]>='1' && ops[i].str[j]<='9') {
202 const char *w = argv[ ops[i].str[j]-'0' ];
203 if (w != NULL) {
204 strcpy (newstr+k, w);
205 k += strlen(w)-1;
206 }
207 } else {
208 newstr[k] = ops[i].str[j];
209 }
210 }
211 newstr[k]='\0';
212 }
213 return true;
214 }
215 }
216
217 /* TODO: this is slow */
218 if (newstr != NULL) {
219 newstr[0] = '\0';
220 for (i=0; i<argc; i++) {
221 strcat (newstr, argv[i]);
222 strcat (newstr, (i == 0 || i== argc - 1)?" ":", ");
223 }
224 }
225
226 return false;
227 }
228
parse(RParse * p,const char * data,char * str)229 static int parse(RParse *p, const char *data, char *str) {
230 int i, len = strlen (data);
231 char *buf, *ptr, *optr, *ptr2;
232 char w0[64];
233 char w1[64];
234 char w2[64];
235 char w3[64];
236 char w4[64];
237
238 if (!strcmp (data, "invalid")
239 || !strcmp (data, "nop")
240 || !strcmp (data, "DEPRECATED")) {
241 str[0] = 0;
242 return true;
243 }
244
245 // malloc can be slow here :?
246 if (!(buf = malloc (len + 1))) {
247 return false;
248 }
249 memcpy (buf, data, len + 1);
250
251 r_str_trim (buf);
252
253 if (*buf) {
254 w0[0]='\0';
255 w1[0]='\0';
256 w2[0]='\0';
257 w3[0]='\0';
258 w4[0]='\0';
259 ptr = strchr (buf, ' ');
260 if (!ptr) {
261 ptr = strchr (buf, '\t');
262 }
263 if (ptr) {
264 *ptr = '\0';
265 for (++ptr; *ptr == ' '; ptr++) {
266 ;
267 }
268 strncpy (w0, buf, sizeof (w0) - 1);
269 w0[sizeof(w0)-1] = '\0';
270 strncpy (w1, ptr, sizeof (w1) - 1);
271 w1[sizeof(w1)-1] = '\0';
272
273 optr=ptr;
274 ptr2 = strchr (ptr, '}');
275 if (ptr2) {
276 ptr = ptr2 + 1;
277 }
278 ptr = strchr (ptr, ',');
279 if (ptr) {
280 *ptr = '\0';
281 for (++ptr; *ptr == ' '; ptr++) {
282 ;
283 }
284 strncpy (w1, optr, sizeof (w1) - 1);
285 w1[sizeof(w1)-1] = '\0';
286 strncpy (w2, ptr, sizeof (w2) - 1);
287 w2[sizeof(w2)-1] = '\0';
288 optr=ptr;
289 ptr = strchr (ptr, ',');
290 if (ptr) {
291 *ptr = '\0';
292 for (++ptr; *ptr == ' '; ptr++) {
293 ;
294 }
295 strncpy (w2, optr, sizeof (w2) - 1);
296 w2[sizeof(w2)-1] = '\0';
297 strncpy (w3, ptr, sizeof (w3) - 1);
298 w3[sizeof(w3)-1] = '\0';
299 optr=ptr;
300 // bonus
301 ptr = strchr (ptr, ',');
302 if (ptr) {
303 *ptr = '\0';
304 for (++ptr; *ptr == ' '; ptr++) {
305 ;
306 }
307 strncpy (w3, optr, sizeof (w3) - 1);
308 w3[sizeof(w3)-1] = '\0';
309 strncpy (w4, ptr, sizeof (w4) - 1);
310 w4[sizeof(w4)-1] = '\0';
311 }
312 }
313 }
314 }
315 {
316 const char *wa[] = { w0, w1, w2, w3, w4 };
317 int nw = 0;
318 for (i=0; i<4; i++) {
319 if (wa[i][0] != '\0') {
320 nw++;
321 }
322 }
323 replace (nw, wa, str);
324 {
325 char *p = strdup (str);
326 p = r_str_replace (p, "+ -", "- ", 0);
327 #if EXPERIMENTAL_ZERO
328 p = r_str_replace (p, "zero", "0", 0);
329 if (!memcmp (p, "0 = ", 4)) *p = 0; // nop
330 #endif
331 if (!strcmp (w1, w2)) {
332 char a[32], b[32];
333 #define REPLACE(x,y) do { \
334 int snprintf_len1_ = snprintf (a, 32, x, w1, w1); \
335 int snprintf_len2_ = snprintf (b, 32, y, w1); \
336 if (snprintf_len1_ < 32 && snprintf_len2_ < 32) { \
337 p = r_str_replace (p, a, b, 0); \
338 } \
339 } while (0)
340
341 // TODO: optimize
342 REPLACE ("%s = %s +", "%s +=");
343 REPLACE ("%s = %s -", "%s -=");
344 REPLACE ("%s = %s &", "%s &=");
345 REPLACE ("%s = %s |", "%s |=");
346 REPLACE ("%s = %s ^", "%s ^=");
347 REPLACE ("%s = %s >>", "%s >>=");
348 REPLACE ("%s = %s <<", "%s <<=");
349 }
350 strcpy (str, p);
351 free (p);
352 }
353 }
354 }
355 free (buf);
356 return true;
357 }
358
359 RParsePlugin r_parse_plugin_dalvik_pseudo = {
360 .name = "dalvik.pseudo",
361 .desc = "DALVIK pseudo syntax",
362 .init = NULL,
363 .fini = NULL,
364 .parse = parse,
365 };
366
367 #ifndef R2_PLUGIN_INCORE
368 R_API RLibStruct radare_plugin = {
369 .type = R_LIB_TYPE_PARSE,
370 .data = &r_parse_plugin_dalvik_pseudo,
371 .version = R2_VERSION
372 };
373 #endif
374