• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 static int counter;
10 static char **list_lines;
11 static int failed_setup;
12 static int size_lines;
13 static cs_mode issue_mode;
14 static int getDetail;
15 static int mc_mode;
16 static int e_flag;
17 
setup_MC(void ** state)18 static int setup_MC(void **state)
19 {
20 	csh *handle;
21 	char **list_params;
22 	int size_params;
23 	int arch, mode;
24 	int i, index, tmp_counter;
25 
26 	if (failed_setup) {
27 		fprintf(stderr, "[  ERROR   ] --- Invalid file to setup\n");
28 		return -1;
29 	}
30 
31 	tmp_counter = 0;
32 	while (tmp_counter < size_lines && list_lines[tmp_counter][0] != '#')
33 		tmp_counter++;
34 
35 	list_params = split(list_lines[tmp_counter] + 2, ", ", &size_params);
36 	if (size_params != 3) {
37 		fprintf(stderr, "[  ERROR   ] --- Invalid options ( arch, mode, option )\n");
38 		failed_setup = 1;
39 		return -1;
40 	}
41 
42 	arch = get_value(arches, NUMARCH, list_params[0]);
43 	if (!strcmp(list_params[0], "CS_ARCH_ARM64"))
44 		mc_mode = 2;
45 	else
46 		mc_mode = 1;
47 
48 	mode = 0;
49 	for (i = 0; i < NUMMODE; ++i) {
50 		if (strstr(list_params[1], modes[i].str)) {
51 			mode += modes[i].value;
52 			switch (modes[i].value) {
53 				case CS_MODE_16:
54 					mc_mode = 0;
55 					break;
56 				case CS_MODE_64:
57 					mc_mode = 2;
58 					break;
59 				case CS_MODE_THUMB:
60 					mc_mode = 1;
61 					break;
62 				default:
63 					break;
64 			}
65 		}
66 	}
67 
68 	if (arch == -1) {
69 		fprintf(stderr, "[  ERROR   ] --- Arch is not supported!\n");
70 		failed_setup = 1;
71 		return -1;
72 	}
73 
74 	handle = (csh *)malloc(sizeof(csh));
75 	if(cs_open(arch, mode, handle) != CS_ERR_OK) {
76 		fprintf(stderr, "[  ERROR   ] --- Cannot initialize capstone\n");
77 		failed_setup = 1;
78 		return -1;
79 	}
80 
81 	for (i = 0; i < NUMOPTION; ++i) {
82 		if (strstr(list_params[2], options[i].str)) {
83 			if (cs_option(*handle, options[i].first_value, options[i].second_value) != CS_ERR_OK) {
84 				fprintf(stderr, "[  ERROR   ] --- Option is not supported for this arch/mode\n");
85 				failed_setup = 1;
86 				return -1;
87 			}
88 		}
89 	}
90 
91 	*state = (void *)handle;
92 	counter++;
93 	if (e_flag == 0)
94 		while (counter < size_lines && strncmp(list_lines[counter], "0x", 2))
95 			counter++;
96 	else
97 		while (counter < size_lines && strncmp(list_lines[counter], "// 0x", 5))
98 			counter++;
99 
100 	free_strs(list_params, size_params);
101 	return 0;
102 }
103 
test_MC(void ** state)104 static void test_MC(void **state)
105 {
106 	if (e_flag == 1)
107 		test_single_MC((csh *)*state, mc_mode, list_lines[counter] + 3);
108 	else
109 		test_single_MC((csh *)*state, mc_mode, list_lines[counter]);
110 }
111 
teardown_MC(void ** state)112 static int teardown_MC(void **state)
113 {
114 	cs_close(*state);
115 	free(*state);
116 	return 0;
117 }
118 
setup_issue(void ** state)119 static int setup_issue(void **state)
120 {
121 	csh *handle;
122 	char **list_params;
123 	int size_params;
124 	int arch, mode;
125 	int i, index, result;
126 	char *(*function)(csh *, cs_mode, cs_insn*);
127 
128 	getDetail = 0;
129 	failed_setup = 0;
130 
131 	if (e_flag == 0)
132 		while (counter < size_lines && strncmp(list_lines[counter], "!# ", 3))
133 			counter++; // get issue line
134 	else
135 		while (counter < size_lines && strncmp(list_lines[counter], "// !# ", 6))
136 			counter++;
137 
138 	counter++;
139 	if (e_flag == 0)
140 		while (counter < size_lines && strncmp(list_lines[counter], "!#", 2))
141 			counter++; // get arch line
142 	else
143 		while (counter < size_lines && strncmp(list_lines[counter], "// !# ", 6))
144 			counter++;
145 
146 	if (e_flag == 0)
147 		list_params = split(list_lines[counter] + 3, ", ", &size_params);
148 	else
149 		list_params = split(list_lines[counter] + 6, ", ", &size_params);
150 
151 	arch = get_value(arches, NUMARCH, list_params[0]);
152 
153 	if (!strcmp(list_params[0], "CS_ARCH_ARM64"))
154 		mc_mode = 2;
155 	else
156 		mc_mode = 1;
157 
158 	mode = 0;
159 	for (i = 0; i < NUMMODE; ++i) {
160 		if (strstr(list_params[1], modes[i].str)) {
161 			mode += modes[i].value;
162 			switch (modes[i].value) {
163 				case CS_MODE_16:
164 					mc_mode = 0;
165 					break;
166 				case CS_MODE_64:
167 					mc_mode = 2;
168 					break;
169 				case CS_MODE_THUMB:
170 					mc_mode = 1;
171 					break;
172 				default:
173 					break;
174 			}
175 		}
176 	}
177 
178 	if (arch == -1) {
179 		fprintf(stderr, "[  ERROR   ] --- Arch is not supported!\n");
180 		failed_setup = 1;
181 		return -1;
182 	}
183 
184 	handle = (csh *)calloc(1, sizeof(csh));
185 	if(cs_open(arch, mode, handle) != CS_ERR_OK) {
186 		fprintf(stderr, "[  ERROR   ] --- Cannot initialize capstone\n");
187 		failed_setup = 1;
188 		return -1;
189 	}
190 
191 	for (i = 0; i < NUMOPTION; ++i) {
192 		if (strstr(list_params[2], options[i].str)) {
193 			if (cs_option(*handle, options[i].first_value, options[i].second_value) != CS_ERR_OK) {
194 				fprintf(stderr, "[  ERROR   ] --- Option is not supported for this arch/mode\n");
195 				failed_setup = 1;
196 				return -1;
197 			}
198 
199 			if (i == 0) {
200 				result = set_function(arch);
201 				if (result == -1) {
202 					fprintf(stderr, "[  ERROR   ] --- Cannot get details\n");
203 					failed_setup = 1;
204 					return -1;
205 				}
206 
207 				getDetail = 1;
208 			}
209 		}
210 	}
211 
212 	*state = (void *)handle;
213 	issue_mode = mode;
214 
215 	if (e_flag == 0)
216 		while (counter < size_lines && strncmp(list_lines[counter], "0x", 2))
217 			counter++;
218 	else
219 		while (counter < size_lines && strncmp(list_lines[counter], "// 0x", 5))
220 			counter++;
221 
222 	free_strs(list_params, size_params);
223 	return 0;
224 }
225 
test_issue(void ** state)226 static void test_issue(void **state)
227 {
228 	if (e_flag == 0)
229 		test_single_issue((csh *)*state, issue_mode, list_lines[counter], getDetail);
230 	else
231 		test_single_issue((csh *)*state, issue_mode, list_lines[counter] + 3, getDetail);
232 
233 	return;
234 }
235 
teardown_issue(void ** state)236 static int teardown_issue(void **state)
237 {
238 	if (e_flag == 0)
239 		while (counter < size_lines && strncmp(list_lines[counter], "!# ", 3))
240 			counter++;
241 	else
242 		while (counter < size_lines && strncmp(list_lines[counter], "// !# ", 6))
243 			counter++;
244 
245 	cs_close(*state);
246 	free(*state);
247 	function = NULL;
248 	return 0;
249 }
250 
test_file(const char * filename)251 static void test_file(const char *filename)
252 {
253 	int size, i;
254 	char **list_str;
255 	char *content, *tmp;
256 	struct CMUnitTest *tests;
257 	int issue_num, number_of_tests;
258 
259 	printf("[+] TARGET: %s\n", filename);
260 	content = readfile(filename);
261 	counter = 0;
262 	failed_setup = 0;
263 	function = NULL;
264 
265 	if (strstr(filename, "issue")) {
266 		number_of_tests = 0;
267 		list_lines = split(content, "\n", &size_lines);
268 		tests = NULL;
269 		for (i = 0; i < size_lines; ++i) {
270 			if ((!strncmp(list_lines[i], "// !# issue", 11) && e_flag == 1) ||
271 					(!strncmp(list_lines[i], "!# issue", 8) && e_flag == 0)) {
272 				tests = (struct CMUnitTest *)realloc(tests, sizeof(struct CMUnitTest) * (number_of_tests + 1));
273 				tests[number_of_tests] = (struct CMUnitTest)cmocka_unit_test_setup_teardown(test_issue, setup_issue, teardown_issue);
274 				tests[number_of_tests].name = strdup(list_lines[i]);
275 				number_of_tests ++;
276 			}
277 		}
278 
279 		_cmocka_run_group_tests("Testing issues", tests, number_of_tests, NULL, NULL);
280 	} else {
281 		list_lines = split(content, "\n", &size_lines);
282 		number_of_tests = 0;
283 
284 		tests = NULL;
285 		for (i = 1; i < size_lines; ++i) {
286 			if ((!strncmp(list_lines[i], "// 0x", 5) && e_flag == 1) || (!strncmp(list_lines[i], "0x", 2) && e_flag == 0)) {
287 				tmp = (char *)malloc(sizeof(char) * 100);
288 				sprintf(tmp, "Line %d", i+1);
289 				tests = (struct CMUnitTest *)realloc(tests, sizeof(struct CMUnitTest) * (number_of_tests + 1));
290 				tests[number_of_tests] = (struct CMUnitTest)cmocka_unit_test_setup_teardown(test_MC, setup_MC, teardown_MC);
291 				tests[number_of_tests].name = tmp;
292 				number_of_tests ++;
293 			}
294 		}
295 
296 		_cmocka_run_group_tests("Testing MC", tests, number_of_tests, NULL, NULL);
297 	}
298 
299 	printf("[+] DONE: %s\n", filename);
300 	printf("[!] Noted:\n[  ERROR   ] --- \"<capstone result>\" != \"<user result>\"\n");
301 	printf("\n\n");
302 	free_strs(list_lines, size_lines);
303 }
304 
test_folder(const char * folder)305 static void test_folder(const char *folder)
306 {
307 	char **files;
308 	int num_files, i;
309 
310 	files = NULL;
311 	num_files = 0;
312 	listdir(folder, &files, &num_files);
313 	for (i = 0; i < num_files; ++i) {
314 		if (strcmp("cs", get_filename_ext(files[i])))
315 			continue;
316 		test_file(files[i]);
317 	}
318 }
319 
main(int argc,char * argv[])320 int main(int argc, char *argv[])
321 {
322 	int opt, flag;
323 
324 	flag = 0;
325 	e_flag = 0;
326 
327 	while ((opt = getopt(argc, argv, "ef:d:")) > 0) {
328 		switch (opt) {
329 			case 'f':
330 				test_file(optarg);
331 				flag = 1;
332 				break;
333 			case 'd':
334 				test_folder(optarg);
335 				flag = 1;
336 				break;
337 			case 'e':
338 				e_flag = 1;
339 				break;
340 			default:
341 				printf("Usage: %s [-e] [-f <file_name.cs>] [-d <directory>]\n", argv[0]);
342 				exit(-1);
343 		}
344 	}
345 
346 	if (flag == 0) {
347 		printf("Usage: %s [-e] [-f <file_name.cs>] [-d <directory>]\n", argv[0]);
348 		exit(-1);
349 	}
350 
351 	return 0;
352 }
353