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