1 /* Capstone testing regression */
2 /* By Do Minh Tuan <tuanit96@gmail.com>, 02-2019 */
3
4
5 #include "helper.h"
6 #include "capstone_test.h"
7 #include <unistd.h>
8
9 #define ARR_SIZE(a) (sizeof(a)/sizeof(a[0]))
10
11 static single_dict arches[] = {
12 {"CS_ARCH_ARM", CS_ARCH_ARM},
13 {"CS_ARCH_ARM64", CS_ARCH_ARM64},
14 {"CS_ARCH_MIPS", CS_ARCH_MIPS},
15 {"CS_ARCH_PPC", CS_ARCH_PPC},
16 {"CS_ARCH_SPARC", CS_ARCH_SPARC},
17 {"CS_ARCH_SYSZ", CS_ARCH_SYSZ},
18 {"CS_ARCH_X86", CS_ARCH_X86},
19 {"CS_ARCH_XCORE", CS_ARCH_XCORE},
20 {"CS_ARCH_M68K", CS_ARCH_M68K},
21 {"CS_ARCH_BPF", CS_ARCH_BPF},
22 {"CS_ARCH_RISCV", CS_ARCH_RISCV},
23 };
24
25 static single_dict modes[] = {
26 {"CS_MODE_LITTLE_ENDIAN", CS_MODE_LITTLE_ENDIAN},
27 {"CS_MODE_ARM", CS_MODE_ARM},
28 {"CS_MODE_16", CS_MODE_16},
29 {"CS_MODE_32", CS_MODE_32},
30 {"CS_MODE_64", CS_MODE_64},
31 {"CS_MODE_THUMB", CS_MODE_THUMB},
32 {"CS_MODE_MCLASS", CS_MODE_MCLASS},
33 {"CS_MODE_V8", CS_MODE_V8},
34 {"CS_MODE_MICRO", CS_MODE_MICRO},
35 {"CS_MODE_MIPS3", CS_MODE_MIPS3},
36 {"CS_MODE_MIPS32R6", CS_MODE_MIPS32R6},
37 {"CS_MODE_MIPS2", CS_MODE_MIPS2},
38 {"CS_MODE_V9", CS_MODE_V9},
39 {"CS_MODE_QPX", CS_MODE_QPX},
40 {"CS_MODE_M68K_000", CS_MODE_M68K_000},
41 {"CS_MODE_M68K_010", CS_MODE_M68K_010},
42 {"CS_MODE_M68K_020", CS_MODE_M68K_020},
43 {"CS_MODE_M68K_030", CS_MODE_M68K_030},
44 {"CS_MODE_M68K_040", CS_MODE_M68K_040},
45 {"CS_MODE_M68K_060", CS_MODE_M68K_060},
46 {"CS_MODE_BIG_ENDIAN", CS_MODE_BIG_ENDIAN},
47 {"CS_MODE_MIPS32", CS_MODE_MIPS32},
48 {"CS_MODE_MIPS64", CS_MODE_MIPS64},
49 {"CS_MODE_M680X_6301", CS_MODE_M680X_6301},
50 {"CS_MODE_M680X_6309", CS_MODE_M680X_6309},
51 {"CS_MODE_M680X_6800", CS_MODE_M680X_6800},
52 {"CS_MODE_M680X_6801", CS_MODE_M680X_6801},
53 {"CS_MODE_M680X_6805", CS_MODE_M680X_6805},
54 {"CS_MODE_M680X_6808", CS_MODE_M680X_6808},
55 {"CS_MODE_M680X_6809", CS_MODE_M680X_6809},
56 {"CS_MODE_M680X_6811", CS_MODE_M680X_6811},
57 {"CS_MODE_M680X_CPU12", CS_MODE_M680X_CPU12},
58 {"CS_MODE_M680X_HCS08", CS_MODE_M680X_HCS08},
59 {"CS_MODE_BPF_CLASSIC", CS_MODE_BPF_CLASSIC},
60 {"CS_MODE_BPF_EXTENDED", CS_MODE_BPF_EXTENDED},
61 {"CS_MODE_RISCV32", CS_MODE_RISCV32},
62 {"CS_MODE_RISCV64", CS_MODE_RISCV64},
63 };
64
65 static double_dict options[] = {
66 {"CS_OPT_DETAIL", CS_OPT_DETAIL, CS_OPT_ON},
67 {"CS_OPT_SKIPDATA", CS_OPT_SKIPDATA, CS_OPT_ON},
68 {"CS_OPT_SYNTAX_DEFAULT", CS_OPT_SYNTAX, CS_OPT_SYNTAX_DEFAULT},
69 {"CS_OPT_SYNTAX_INTEL", CS_OPT_SYNTAX, CS_OPT_SYNTAX_INTEL},
70 {"CS_OPT_SYNTAX_ATT", CS_OPT_SYNTAX, CS_OPT_SYNTAX_ATT},
71 {"CS_OPT_SYNTAX_NOREGNAME", CS_OPT_SYNTAX, CS_OPT_SYNTAX_NOREGNAME},
72 {"CS_OPT_SYNTAX_MASM", CS_OPT_SYNTAX, CS_OPT_SYNTAX_MASM},
73 {"CS_MODE_LITTLE_ENDIAN", CS_OPT_MODE, CS_MODE_LITTLE_ENDIAN},
74 {"CS_MODE_ARM", CS_OPT_MODE, CS_MODE_ARM},
75 {"CS_MODE_16", CS_OPT_MODE, CS_MODE_16},
76 {"CS_MODE_32", CS_OPT_MODE, CS_MODE_32},
77 {"CS_MODE_64", CS_OPT_MODE, CS_MODE_64},
78 {"CS_MODE_THUMB", CS_OPT_MODE, CS_MODE_THUMB},
79 {"CS_MODE_MCLASS", CS_OPT_MODE, CS_MODE_MCLASS},
80 {"CS_MODE_V8", CS_OPT_MODE, CS_MODE_V8},
81 {"CS_MODE_MICRO", CS_OPT_MODE, CS_MODE_MICRO},
82 {"CS_MODE_MIPS3", CS_OPT_MODE, CS_MODE_MIPS3},
83 {"CS_MODE_MIPS32R6", CS_OPT_MODE, CS_MODE_MIPS32R6},
84 {"CS_MODE_MIPS2", CS_OPT_MODE, CS_MODE_MIPS2},
85 {"CS_MODE_V9", CS_OPT_MODE, CS_MODE_V9},
86 {"CS_MODE_QPX", CS_OPT_MODE, CS_MODE_QPX},
87 {"CS_MODE_M68K_000", CS_OPT_MODE, CS_MODE_M68K_000},
88 {"CS_MODE_M68K_010", CS_OPT_MODE, CS_MODE_M68K_010},
89 {"CS_MODE_M68K_020", CS_OPT_MODE, CS_MODE_M68K_020},
90 {"CS_MODE_M68K_030", CS_OPT_MODE, CS_MODE_M68K_030},
91 {"CS_MODE_M68K_040", CS_OPT_MODE, CS_MODE_M68K_040},
92 {"CS_MODE_M68K_060", CS_OPT_MODE, CS_MODE_M68K_060},
93 {"CS_MODE_BIG_ENDIAN", CS_OPT_MODE, CS_MODE_BIG_ENDIAN},
94 {"CS_MODE_MIPS32", CS_OPT_MODE, CS_MODE_MIPS32},
95 {"CS_MODE_MIPS64", CS_OPT_MODE, CS_MODE_MIPS64},
96 {"CS_MODE_M680X_6301", CS_OPT_MODE, CS_MODE_M680X_6301},
97 {"CS_MODE_M680X_6309", CS_OPT_MODE, CS_MODE_M680X_6309},
98 {"CS_MODE_M680X_6800", CS_OPT_MODE, CS_MODE_M680X_6800},
99 {"CS_MODE_M680X_6801", CS_OPT_MODE, CS_MODE_M680X_6801},
100 {"CS_MODE_M680X_6805", CS_OPT_MODE, CS_MODE_M680X_6805},
101 {"CS_MODE_M680X_6808", CS_OPT_MODE, CS_MODE_M680X_6808},
102 {"CS_MODE_M680X_6809", CS_OPT_MODE, CS_MODE_M680X_6809},
103 {"CS_MODE_M680X_6811", CS_OPT_MODE, CS_MODE_M680X_6811},
104 {"CS_MODE_M680X_CPU12", CS_OPT_MODE, CS_MODE_M680X_CPU12},
105 {"CS_MODE_M680X_HCS08", CS_OPT_MODE, CS_MODE_M680X_HCS08},
106 {"CS_MODE_RISCV32", CS_OPT_MODE, CS_MODE_RISCV32},
107 {"CS_MODE_RISCV64", CS_OPT_MODE, CS_MODE_RISCV64},
108 {"CS_OPT_UNSIGNED", CS_OPT_UNSIGNED, CS_OPT_ON},
109 };
110
111 static int counter;
112 static char **list_lines;
113 static int failed_setup;
114 static int size_lines;
115 static cs_mode issue_mode;
116 static int getDetail;
117 static int mc_mode;
118 static int e_flag;
119
setup_MC(void ** state)120 static int setup_MC(void **state)
121 {
122 csh *handle;
123 char **list_params;
124 int size_params;
125 int arch, mode;
126 int i, index, tmp_counter;
127
128 if (failed_setup) {
129 fprintf(stderr, "[ ERROR ] --- Invalid file to setup\n");
130 return -1;
131 }
132
133 tmp_counter = 0;
134 while (tmp_counter < size_lines && list_lines[tmp_counter][0] != '#')
135 tmp_counter++;
136
137 list_params = split(list_lines[tmp_counter] + 2, ", ", &size_params);
138 if (size_params != 3) {
139 fprintf(stderr, "[ ERROR ] --- Invalid options ( arch, mode, option )\n");
140 failed_setup = 1;
141 return -1;
142 }
143
144 arch = get_value(arches, ARR_SIZE(arches), list_params[0]);
145 if (!strcmp(list_params[0], "CS_ARCH_ARM64"))
146 mc_mode = 2;
147 else
148 mc_mode = 1;
149
150 mode = 0;
151 for (i = 0; i < ARR_SIZE(modes); ++i) {
152 if (strstr(list_params[1], modes[i].str)) {
153 mode += modes[i].value;
154 switch (modes[i].value) {
155 case CS_MODE_16:
156 mc_mode = 0;
157 break;
158 case CS_MODE_64:
159 mc_mode = 2;
160 break;
161 case CS_MODE_THUMB:
162 mc_mode = 1;
163 break;
164 default:
165 break;
166 }
167 }
168 }
169
170 if (arch == -1) {
171 fprintf(stderr, "[ ERROR ] --- Arch is not supported!\n");
172 failed_setup = 1;
173 return -1;
174 }
175
176 handle = (csh *)malloc(sizeof(csh));
177 if(cs_open(arch, mode, handle) != CS_ERR_OK) {
178 fprintf(stderr, "[ ERROR ] --- Cannot initialize capstone\n");
179 failed_setup = 1;
180 return -1;
181 }
182
183 for (i = 0; i < ARR_SIZE(options); ++i) {
184 if (strstr(list_params[2], options[i].str)) {
185 if (cs_option(*handle, options[i].first_value, options[i].second_value) != CS_ERR_OK) {
186 fprintf(stderr, "[ ERROR ] --- Option is not supported for this arch/mode\n");
187 failed_setup = 1;
188 return -1;
189 }
190 }
191 }
192
193 *state = (void *)handle;
194 counter++;
195 if (e_flag == 0)
196 while (counter < size_lines && strncmp(list_lines[counter], "0x", 2))
197 counter++;
198 else
199 while (counter < size_lines && strncmp(list_lines[counter], "// 0x", 5))
200 counter++;
201
202 free_strs(list_params, size_params);
203 return 0;
204 }
205
test_MC(void ** state)206 static void test_MC(void **state)
207 {
208 if (e_flag == 1)
209 test_single_MC((csh *)*state, mc_mode, list_lines[counter] + 3);
210 else
211 test_single_MC((csh *)*state, mc_mode, list_lines[counter]);
212 }
213
teardown_MC(void ** state)214 static int teardown_MC(void **state)
215 {
216 cs_close(*state);
217 free(*state);
218 return 0;
219 }
220
setup_issue(void ** state)221 static int setup_issue(void **state)
222 {
223 csh *handle;
224 char **list_params;
225 int size_params;
226 int arch, mode;
227 int i, index, result;
228 char *(*function)(csh *, cs_mode, cs_insn*);
229
230 getDetail = 0;
231 failed_setup = 0;
232
233 if (e_flag == 0)
234 while (counter < size_lines && strncmp(list_lines[counter], "!# ", 3))
235 counter++; // get issue line
236 else
237 while (counter < size_lines && strncmp(list_lines[counter], "// !# ", 6))
238 counter++;
239
240 counter++;
241 if (e_flag == 0)
242 while (counter < size_lines && strncmp(list_lines[counter], "!#", 2))
243 counter++; // get arch line
244 else
245 while (counter < size_lines && strncmp(list_lines[counter], "// !# ", 6))
246 counter++;
247
248 if (e_flag == 0)
249 list_params = split(list_lines[counter] + 3, ", ", &size_params);
250 else
251 list_params = split(list_lines[counter] + 6, ", ", &size_params);
252
253 arch = get_value(arches, ARR_SIZE(arches), list_params[0]);
254
255 if (!strcmp(list_params[0], "CS_ARCH_ARM64"))
256 mc_mode = 2;
257 else
258 mc_mode = 1;
259
260 mode = 0;
261 for (i = 0; i < ARR_SIZE(modes); ++i) {
262 if (strstr(list_params[1], modes[i].str)) {
263 mode += modes[i].value;
264 switch (modes[i].value) {
265 case CS_MODE_16:
266 mc_mode = 0;
267 break;
268 case CS_MODE_64:
269 mc_mode = 2;
270 break;
271 case CS_MODE_THUMB:
272 mc_mode = 1;
273 break;
274 default:
275 break;
276 }
277 }
278 }
279
280 if (arch == -1) {
281 fprintf(stderr, "[ ERROR ] --- Arch is not supported!\n");
282 failed_setup = 1;
283 return -1;
284 }
285
286 handle = (csh *)calloc(1, sizeof(csh));
287 if(cs_open(arch, mode, handle) != CS_ERR_OK) {
288 fprintf(stderr, "[ ERROR ] --- Cannot initialize capstone\n");
289 failed_setup = 1;
290 return -1;
291 }
292
293 for (i = 0; i < ARR_SIZE(options); ++i) {
294 if (strstr(list_params[2], options[i].str)) {
295 if (cs_option(*handle, options[i].first_value, options[i].second_value) != CS_ERR_OK) {
296 fprintf(stderr, "[ ERROR ] --- Option is not supported for this arch/mode\n");
297 failed_setup = 1;
298 return -1;
299 }
300
301 if (i == 0) {
302 result = set_function(arch);
303 if (result == -1) {
304 fprintf(stderr, "[ ERROR ] --- Cannot get details\n");
305 failed_setup = 1;
306 return -1;
307 }
308
309 getDetail = 1;
310 }
311 }
312 }
313
314 *state = (void *)handle;
315 issue_mode = mode;
316
317 if (e_flag == 0)
318 while (counter < size_lines && strncmp(list_lines[counter], "0x", 2))
319 counter++;
320 else
321 while (counter < size_lines && strncmp(list_lines[counter], "// 0x", 5))
322 counter++;
323
324 free_strs(list_params, size_params);
325 return 0;
326 }
327
test_issue(void ** state)328 static void test_issue(void **state)
329 {
330 if (e_flag == 0)
331 test_single_issue((csh *)*state, issue_mode, list_lines[counter], getDetail);
332 else
333 test_single_issue((csh *)*state, issue_mode, list_lines[counter] + 3, getDetail);
334
335 return;
336 }
337
teardown_issue(void ** state)338 static int teardown_issue(void **state)
339 {
340 if (e_flag == 0)
341 while (counter < size_lines && strncmp(list_lines[counter], "!# ", 3))
342 counter++;
343 else
344 while (counter < size_lines && strncmp(list_lines[counter], "// !# ", 6))
345 counter++;
346
347 cs_close(*state);
348 free(*state);
349 function = NULL;
350 return 0;
351 }
352
test_file(const char * filename)353 static void test_file(const char *filename)
354 {
355 int size, i;
356 char **list_str;
357 char *content, *tmp;
358 struct CMUnitTest *tests;
359 int issue_num, number_of_tests;
360
361 printf("[+] TARGET: %s\n", filename);
362 content = readfile(filename);
363 counter = 0;
364 failed_setup = 0;
365 function = NULL;
366
367 if (strstr(filename, "issue")) {
368 number_of_tests = 0;
369 list_lines = split(content, "\n", &size_lines);
370 tests = NULL;
371 for (i = 0; i < size_lines; ++i) {
372 if ((!strncmp(list_lines[i], "// !# issue", 11) && e_flag == 1) ||
373 (!strncmp(list_lines[i], "!# issue", 8) && e_flag == 0)) {
374 tests = (struct CMUnitTest *)realloc(tests, sizeof(struct CMUnitTest) * (number_of_tests + 1));
375 tests[number_of_tests] = (struct CMUnitTest)cmocka_unit_test_setup_teardown(test_issue, setup_issue, teardown_issue);
376 tests[number_of_tests].name = strdup(list_lines[i]);
377 number_of_tests ++;
378 }
379 }
380
381 _cmocka_run_group_tests("Testing issues", tests, number_of_tests, NULL, NULL);
382 } else {
383 list_lines = split(content, "\n", &size_lines);
384 number_of_tests = 0;
385
386 tests = NULL;
387 for (i = 1; i < size_lines; ++i) {
388 if ((!strncmp(list_lines[i], "// 0x", 5) && e_flag == 1) || (!strncmp(list_lines[i], "0x", 2) && e_flag == 0)) {
389 tmp = (char *)malloc(sizeof(char) * 100);
390 sprintf(tmp, "Line %d", i+1);
391 tests = (struct CMUnitTest *)realloc(tests, sizeof(struct CMUnitTest) * (number_of_tests + 1));
392 tests[number_of_tests] = (struct CMUnitTest)cmocka_unit_test_setup_teardown(test_MC, setup_MC, teardown_MC);
393 tests[number_of_tests].name = tmp;
394 number_of_tests ++;
395 }
396 }
397
398 _cmocka_run_group_tests("Testing MC", tests, number_of_tests, NULL, NULL);
399 }
400
401 printf("[+] DONE: %s\n", filename);
402 printf("[!] Noted:\n[ ERROR ] --- \"<capstone result>\" != \"<user result>\"\n");
403 printf("\n\n");
404 free_strs(list_lines, size_lines);
405 }
406
test_folder(const char * folder)407 static void test_folder(const char *folder)
408 {
409 char **files;
410 int num_files, i;
411
412 files = NULL;
413 num_files = 0;
414 listdir(folder, &files, &num_files);
415 for (i = 0; i < num_files; ++i) {
416 if (strcmp("cs", get_filename_ext(files[i])))
417 continue;
418 test_file(files[i]);
419 }
420 }
421
main(int argc,char * argv[])422 int main(int argc, char *argv[])
423 {
424 int opt, flag;
425
426 flag = 0;
427 e_flag = 0;
428
429 while ((opt = getopt(argc, argv, "ef:d:")) > 0) {
430 switch (opt) {
431 case 'f':
432 test_file(optarg);
433 flag = 1;
434 break;
435 case 'd':
436 test_folder(optarg);
437 flag = 1;
438 break;
439 case 'e':
440 e_flag = 1;
441 break;
442 default:
443 printf("Usage: %s [-e] [-f <file_name.cs>] [-d <directory>]\n", argv[0]);
444 exit(-1);
445 }
446 }
447
448 if (flag == 0) {
449 printf("Usage: %s [-e] [-f <file_name.cs>] [-d <directory>]\n", argv[0]);
450 exit(-1);
451 }
452
453 return 0;
454 }
455