1 /* Tang Yuhang <tyh000011112222@gmail.com> 2016 */
2 /* pancake <pancake@nopcode.org> 2017 */
3 
4 #include <string.h>
5 #include <ctype.h>
6 #include <errno.h>
7 #include "getopt.h"
8 
9 #include <capstone/capstone.h>
10 
11 void print_string_hex(const char *comment, unsigned char *str, size_t len);
12 
13 static struct {
14 	const char *name;
15 	cs_arch arch;
16 	cs_mode mode;
17 } all_archs[] = {
18 	{ "arm", CS_ARCH_ARM, CS_MODE_ARM },
19 	{ "armb", CS_ARCH_ARM, CS_MODE_ARM | CS_MODE_BIG_ENDIAN },
20 	{ "armbe", CS_ARCH_ARM, CS_MODE_ARM | CS_MODE_BIG_ENDIAN },
21 	{ "arml", CS_ARCH_ARM, CS_MODE_ARM | CS_MODE_LITTLE_ENDIAN },
22 	{ "armle", CS_ARCH_ARM, CS_MODE_ARM | CS_MODE_LITTLE_ENDIAN },
23 	{ "armv8", CS_ARCH_ARM, CS_MODE_ARM | CS_MODE_V8 },
24 	{ "thumbv8", CS_ARCH_ARM, CS_MODE_ARM | CS_MODE_THUMB | CS_MODE_V8 },
25 	{ "armv8be", CS_ARCH_ARM, CS_MODE_ARM | CS_MODE_V8 | CS_MODE_BIG_ENDIAN },
26 	{ "thumbv8be", CS_ARCH_ARM, CS_MODE_ARM | CS_MODE_THUMB | CS_MODE_V8 | CS_MODE_BIG_ENDIAN },
27 	{ "cortexm", CS_ARCH_ARM, CS_MODE_ARM | CS_MODE_THUMB | CS_MODE_MCLASS },
28 	{ "thumb", CS_ARCH_ARM, CS_MODE_ARM | CS_MODE_THUMB },
29 	{ "thumbbe", CS_ARCH_ARM, CS_MODE_ARM | CS_MODE_THUMB | CS_MODE_BIG_ENDIAN },
30 	{ "thumble", CS_ARCH_ARM, CS_MODE_ARM | CS_MODE_THUMB | CS_MODE_LITTLE_ENDIAN },
31 	{ "arm64", CS_ARCH_ARM64, CS_MODE_LITTLE_ENDIAN },
32 	{ "arm64be", CS_ARCH_ARM64, CS_MODE_BIG_ENDIAN },
33 	{ "mips", CS_ARCH_MIPS, CS_MODE_MIPS32 | CS_MODE_LITTLE_ENDIAN },
34 	{ "mipsmicro", CS_ARCH_MIPS, CS_MODE_MIPS32 | CS_MODE_MICRO },
35 	{ "mipsbemicro", CS_ARCH_MIPS, CS_MODE_MIPS32 | CS_MODE_MICRO | CS_MODE_BIG_ENDIAN },
36 	{ "mipsbe32r6", CS_ARCH_MIPS, CS_MODE_MIPS32R6 | CS_MODE_BIG_ENDIAN},
37 	{ "mipsbe32r6micro", CS_ARCH_MIPS, CS_MODE_MIPS32R6 | CS_MODE_BIG_ENDIAN | CS_MODE_MICRO },
38 	{ "mips32r6", CS_ARCH_MIPS, CS_MODE_MIPS32R6 },
39 	{ "mips32r6micro", CS_ARCH_MIPS, CS_MODE_MIPS32R6 | CS_MODE_MICRO },
40 	{ "mipsbe", CS_ARCH_MIPS, CS_MODE_MIPS32 | CS_MODE_BIG_ENDIAN },
41 	{ "mips64", CS_ARCH_MIPS, CS_MODE_MIPS64 | CS_MODE_LITTLE_ENDIAN },
42 	{ "mips64be", CS_ARCH_MIPS, CS_MODE_MIPS64 | CS_MODE_BIG_ENDIAN },
43 	{ "x16", CS_ARCH_X86, CS_MODE_16 }, // CS_MODE_16
44 	{ "x16att", CS_ARCH_X86, CS_MODE_16 }, // CS_MODE_16 , CS_OPT_SYNTAX_ATT
45 	{ "x32", CS_ARCH_X86, CS_MODE_32 }, // CS_MODE_32
46 	{ "x32att", CS_ARCH_X86, CS_MODE_32 }, // CS_MODE_32, CS_OPT_SYNTAX_ATT
47 	{ "x64", CS_ARCH_X86, CS_MODE_64 }, // CS_MODE_64
48 	{ "x64att", CS_ARCH_X86, CS_MODE_64 }, // CS_MODE_64, CS_OPT_SYNTAX_ATT
49 	{ "ppc32", CS_ARCH_PPC, CS_MODE_32 | CS_MODE_LITTLE_ENDIAN },
50 	{ "ppc32be", CS_ARCH_PPC, CS_MODE_32 | CS_MODE_BIG_ENDIAN },
51 	{ "ppc32qpx", CS_ARCH_PPC, CS_MODE_32 | CS_MODE_QPX | CS_MODE_LITTLE_ENDIAN },
52 	{ "ppc32beqpx", CS_ARCH_PPC, CS_MODE_32 | CS_MODE_QPX | CS_MODE_BIG_ENDIAN },
53 	{ "ppc64", CS_ARCH_PPC, CS_MODE_64 | CS_MODE_LITTLE_ENDIAN },
54 	{ "ppc64be", CS_ARCH_PPC, CS_MODE_64 | CS_MODE_BIG_ENDIAN },
55 	{ "ppc64qpx", CS_ARCH_PPC, CS_MODE_64 | CS_MODE_QPX | CS_MODE_LITTLE_ENDIAN },
56 	{ "ppc64beqpx", CS_ARCH_PPC, CS_MODE_64 | CS_MODE_QPX | CS_MODE_BIG_ENDIAN },
57 	{ "sparc", CS_ARCH_SPARC, CS_MODE_BIG_ENDIAN },
58 	{ "sparcv9", CS_ARCH_SPARC, CS_MODE_BIG_ENDIAN | CS_MODE_V9 },
59 	{ "systemz", CS_ARCH_SYSZ, CS_MODE_BIG_ENDIAN },
60 	{ "sysz", CS_ARCH_SYSZ, CS_MODE_BIG_ENDIAN },
61 	{ "s390x", CS_ARCH_SYSZ, CS_MODE_BIG_ENDIAN },
62 	{ "xcore", CS_ARCH_XCORE, CS_MODE_BIG_ENDIAN },
63 	{ "m68k", CS_ARCH_M68K, CS_MODE_BIG_ENDIAN },
64 	{ "m68k40", CS_ARCH_M68K, CS_MODE_M68K_040 },
65 	{ "tms320c64x", CS_ARCH_TMS320C64X, CS_MODE_BIG_ENDIAN },
66 	{ "m6800", CS_ARCH_M680X, CS_MODE_M680X_6800 },
67 	{ "m6801", CS_ARCH_M680X, CS_MODE_M680X_6801 },
68 	{ "m6805", CS_ARCH_M680X, CS_MODE_M680X_6805 },
69 	{ "m6808", CS_ARCH_M680X, CS_MODE_M680X_6808 },
70 	{ "m6809", CS_ARCH_M680X, CS_MODE_M680X_6809 },
71 	{ "m6811", CS_ARCH_M680X, CS_MODE_M680X_6811 },
72 	{ "cpu12", CS_ARCH_M680X, CS_MODE_M680X_CPU12 },
73 	{ "hd6301", CS_ARCH_M680X, CS_MODE_M680X_6301 },
74 	{ "hd6309", CS_ARCH_M680X, CS_MODE_M680X_6309 },
75 	{ "hcs08", CS_ARCH_M680X, CS_MODE_M680X_HCS08 },
76 	{ "evm", CS_ARCH_EVM, 0 },
77 	{ "wasm", CS_ARCH_WASM, 0 },
78 	{ "bpf", CS_ARCH_BPF, CS_MODE_LITTLE_ENDIAN | CS_MODE_BPF_CLASSIC },
79 	{ "bpfbe", CS_ARCH_BPF, CS_MODE_BIG_ENDIAN | CS_MODE_BPF_CLASSIC },
80 	{ "ebpf", CS_ARCH_BPF, CS_MODE_LITTLE_ENDIAN | CS_MODE_BPF_EXTENDED },
81 	{ "ebpfbe", CS_ARCH_BPF, CS_MODE_BIG_ENDIAN | CS_MODE_BPF_EXTENDED },
82 	{ "riscv32", CS_ARCH_RISCV, CS_MODE_RISCV32 },
83 	{ "riscv64", CS_ARCH_RISCV, CS_MODE_RISCV64 },
84 	{ "6502", CS_ARCH_MOS65XX, CS_MODE_MOS65XX_6502 },
85 	{ "65c02", CS_ARCH_MOS65XX, CS_MODE_MOS65XX_65C02 },
86 	{ "w65c02", CS_ARCH_MOS65XX, CS_MODE_MOS65XX_W65C02 },
87 	{ "65816", CS_ARCH_MOS65XX, CS_MODE_MOS65XX_65816_LONG_MX },
88 	{ NULL }
89 };
90 
91 void print_insn_detail_x86(csh ud, cs_mode mode, cs_insn *ins);
92 void print_insn_detail_arm(csh handle, cs_insn *ins);
93 void print_insn_detail_arm64(csh handle, cs_insn *ins);
94 void print_insn_detail_mips(csh handle, cs_insn *ins);
95 void print_insn_detail_ppc(csh handle, cs_insn *ins);
96 void print_insn_detail_sparc(csh handle, cs_insn *ins);
97 void print_insn_detail_sysz(csh handle, cs_insn *ins);
98 void print_insn_detail_xcore(csh handle, cs_insn *ins);
99 void print_insn_detail_m68k(csh handle, cs_insn *ins);
100 void print_insn_detail_tms320c64x(csh handle, cs_insn *ins);
101 void print_insn_detail_m680x(csh handle, cs_insn *ins);
102 void print_insn_detail_evm(csh handle, cs_insn *ins);
103 void print_insn_detail_riscv(csh handle, cs_insn *ins);
104 void print_insn_detail_wasm(csh handle, cs_insn *ins);
105 void print_insn_detail_mos65xx(csh handle, cs_insn *ins);
106 void print_insn_detail_bpf(csh handle, cs_insn *ins);
107 
108 static void print_details(csh handle, cs_arch arch, cs_mode md, cs_insn *ins);
109 
print_string_hex(const char * comment,unsigned char * str,size_t len)110 void print_string_hex(const char *comment, unsigned char *str, size_t len)
111 {
112 	unsigned char *c;
113 
114 	printf("%s", comment);
115 	for (c = str; c < str + len; c++) {
116 		printf("0x%02x ", *c & 0xff);
117 	}
118 
119 	printf("\n");
120 }
121 
122 // convert hexchar to hexnum
char_to_hexnum(char c)123 static uint8_t char_to_hexnum(char c)
124 {
125 	if (c >= '0' && c <= '9') {
126 		return (uint8_t)(c - '0');
127 	}
128 
129 	if (c >= 'a' && c <= 'f') {
130 		return (uint8_t)(10 + c - 'a');
131 	}
132 
133 	//  c >= 'A' && c <= 'F'
134 	return (uint8_t)(10 + c - 'A');
135 }
136 
137 // convert user input (char[]) to uint8_t[], each element of which is
138 // valid hexadecimal, and return actual length of uint8_t[] in @size.
preprocess(char * code,size_t * size)139 static uint8_t *preprocess(char *code, size_t *size)
140 {
141 	size_t i = 0, j = 0;
142 	uint8_t high, low;
143 	uint8_t *result;
144 
145 	if (strlen(code) == 0)
146 		return NULL;
147 
148 	result = (uint8_t *)malloc(strlen(code));
149 	if (result != NULL) {
150 		while (code[i] != '\0') {
151 			if (isxdigit(code[i]) && isxdigit(code[i+1])) {
152 				high = 16 * char_to_hexnum(code[i]);
153 				low = char_to_hexnum(code[i+1]);
154 				result[j] = high + low;
155 				i++;
156 				j++;
157 			}
158 			i++;
159 		}
160 		*size = j;
161 	}
162 
163 	return result;
164 }
165 
usage(char * prog)166 static void usage(char *prog)
167 {
168 	printf("Cstool for Capstone Disassembler Engine v%u.%u.%u\n\n", CS_VERSION_MAJOR, CS_VERSION_MINOR, CS_VERSION_EXTRA);
169 	printf("Syntax: %s [-d|-s|-u|-v] <arch+mode> <assembly-hexstring> [start-address-in-hex-format]\n", prog);
170 	printf("\nThe following <arch+mode> options are supported:\n");
171 
172 	if (cs_support(CS_ARCH_X86)) {
173 		printf("        x16         16-bit mode (X86)\n");
174 		printf("        x32         32-bit mode (X86)\n");
175 		printf("        x64         64-bit mode (X86)\n");
176 		printf("        x16att      16-bit mode (X86), syntax AT&T\n");
177 		printf("        x32att      32-bit mode (X86), syntax AT&T\n");
178 		printf("        x64att      64-bit mode (X86), syntax AT&T\n");
179 	}
180 
181 	if (cs_support(CS_ARCH_ARM)) {
182 		printf("        arm         arm\n");
183 		printf("        armbe       arm + big endian\n");
184 		printf("        thumb       thumb mode\n");
185 		printf("        thumbbe     thumb + big endian\n");
186 		printf("        cortexm     thumb + cortex-m extensions\n");
187 		printf("        armv8       arm v8\n");
188 		printf("        thumbv8     thumb v8\n");
189 		printf("        armv8be     arm v8 + big endian\n");
190 		printf("        thumbv8be   thumb v8 + big endian\n");
191 	}
192 
193 	if (cs_support(CS_ARCH_ARM64)) {
194 		printf("        arm64       aarch64 mode\n");
195 		printf("        arm64be     aarch64 + big endian\n");
196 	}
197 
198 	if (cs_support(CS_ARCH_MIPS)) {
199 		printf("        mips        mips32 + little endian\n");
200 		printf("        mipsbe      mips32 + big endian\n");
201 		printf("        mips64      mips64 + little endian\n");
202 		printf("        mips64be    mips64 + big endian\n");
203 	}
204 
205 	if (cs_support(CS_ARCH_PPC)) {
206 		printf("        ppc32       ppc32 + little endian\n");
207 		printf("        ppc32be     ppc32 + big endian\n");
208 		printf("        ppc32qpx    ppc32 + qpx + little endian\n");
209 		printf("        ppc32beqpx  ppc32 + qpx + big endian\n");
210 		printf("        ppc64       ppc64 + little endian\n");
211 		printf("        ppc64be     ppc64 + big endian\n");
212 		printf("        ppc64qpx    ppc64 + qpx + little endian\n");
213 		printf("        ppc64beqpx  ppc64 + qpx + big endian\n");
214 	}
215 
216 	if (cs_support(CS_ARCH_SPARC)) {
217 		printf("        sparc       sparc\n");
218 	}
219 
220 	if (cs_support(CS_ARCH_SYSZ)) {
221 		printf("        systemz     systemz (s390x)\n");
222 	}
223 
224 	if (cs_support(CS_ARCH_XCORE)) {
225 		printf("        xcore       xcore\n");
226 	}
227 
228 	if (cs_support(CS_ARCH_M68K)) {
229 		printf("        m68k        m68k + big endian\n");
230 		printf("        m68k40      m68k_040\n");
231 	}
232 
233 	if (cs_support(CS_ARCH_TMS320C64X)) {
234 		printf("        tms320c64x  TMS320C64x\n");
235 	}
236 
237 	if (cs_support(CS_ARCH_M680X)) {
238 		printf("        m6800       M6800/2\n");
239 		printf("        m6801       M6801/3\n");
240 		printf("        m6805       M6805\n");
241 		printf("        m6808       M68HC08\n");
242 		printf("        m6809       M6809\n");
243 		printf("        m6811       M68HC11\n");
244 		printf("        cpu12       M68HC12/HCS12\n");
245 		printf("        hd6301      HD6301/3\n");
246 		printf("        hd6309      HD6309\n");
247 		printf("        hcs08       HCS08\n");
248 	}
249 
250 	if (cs_support(CS_ARCH_EVM)) {
251 		printf("        evm         Ethereum Virtual Machine\n");
252 	}
253 
254 	if (cs_support(CS_ARCH_MOS65XX)) {
255 		printf("        6502        MOS 6502\n");
256 		printf("        65c02       WDC 65c02\n");
257 		printf("        w65c02      WDC w65c02\n");
258 		printf("        65816       WDC 65816 (long m/x)\n");
259 	}
260 
261 	if (cs_support(CS_ARCH_WASM)) {
262 		printf("        wasm:       Web Assembly\n");
263 	}
264 
265 	if (cs_support(CS_ARCH_BPF)) {
266 		printf("        bpf         Classic BPF\n");
267 		printf("        bpfbe       Classic BPF + big endian\n");
268 		printf("        ebpf        Extended BPF\n");
269 		printf("        ebpfbe      Extended BPF + big endian\n");
270 	}
271 
272 	if (cs_support(CS_ARCH_RISCV)) {
273 		printf("        riscv32     riscv32\n");
274 		printf("        riscv64     riscv64\n");
275 	}
276 
277 	printf("\nExtra options:\n");
278 	printf("        -d show detailed information of the instructions\n");
279 	printf("        -s decode in SKIPDATA mode\n");
280 	printf("        -u show immediates as unsigned\n");
281 	printf("        -v show version & Capstone core build info\n\n");
282 }
283 
print_details(csh handle,cs_arch arch,cs_mode md,cs_insn * ins)284 static void print_details(csh handle, cs_arch arch, cs_mode md, cs_insn *ins)
285 {
286 	printf("\tID: %u (%s)\n", ins->id, cs_insn_name(handle, ins->id));
287 
288 	switch(arch) {
289 		case CS_ARCH_X86:
290 			print_insn_detail_x86(handle, md, ins);
291 			break;
292 		case CS_ARCH_ARM:
293 			print_insn_detail_arm(handle, ins);
294 			break;
295 		case CS_ARCH_ARM64:
296 			print_insn_detail_arm64(handle, ins);
297 			break;
298 		case CS_ARCH_MIPS:
299 			print_insn_detail_mips(handle, ins);
300 			break;
301 		case CS_ARCH_PPC:
302 			print_insn_detail_ppc(handle, ins);
303 			break;
304 		case CS_ARCH_SPARC:
305 			print_insn_detail_sparc(handle, ins);
306 			break;
307 		case CS_ARCH_SYSZ:
308 			print_insn_detail_sysz(handle, ins);
309 			break;
310 		case CS_ARCH_XCORE:
311 			print_insn_detail_xcore(handle, ins);
312 			break;
313 		case CS_ARCH_M68K:
314 			print_insn_detail_m68k(handle, ins);
315 			break;
316 		case CS_ARCH_TMS320C64X:
317 			print_insn_detail_tms320c64x(handle, ins);
318 			break;
319 		case CS_ARCH_M680X:
320 			print_insn_detail_m680x(handle, ins);
321 			break;
322 		case CS_ARCH_EVM:
323 			print_insn_detail_evm(handle, ins);
324 			break;
325 		case CS_ARCH_WASM:
326 			print_insn_detail_wasm(handle, ins);
327 			break;
328 		case CS_ARCH_MOS65XX:
329 			print_insn_detail_mos65xx(handle, ins);
330 			break;
331 		case CS_ARCH_BPF:
332 			print_insn_detail_bpf(handle, ins);
333 			break;
334 		case CS_ARCH_RISCV:
335 			print_insn_detail_riscv(handle, ins);
336 			break;
337 		default: break;
338 	}
339 
340 	if (ins->detail->groups_count) {
341 		int j;
342 
343 		printf("\tGroups: ");
344 		for(j = 0; j < ins->detail->groups_count; j++) {
345 			printf("%s ", cs_group_name(handle, ins->detail->groups[j]));
346 		}
347 		printf("\n");
348 	}
349 
350 	printf("\n");
351 }
352 
main(int argc,char ** argv)353 int main(int argc, char **argv)
354 {
355 	int i, c;
356 	csh handle;
357 	char *mode;
358 	uint8_t *assembly;
359 	size_t count, size;
360 	uint64_t address = 0LL;
361 	cs_insn *insn;
362 	cs_err err;
363 	cs_mode md;
364 	cs_arch arch = CS_ARCH_ALL;
365 	bool detail_flag = false;
366 	bool unsigned_flag = false;
367 	bool skipdata = false;
368 	int args_left;
369 
370 	while ((c = getopt (argc, argv, "sudhv")) != -1) {
371 		switch (c) {
372 			case 's':
373 				skipdata = true;
374 				break;
375 			case 'u':
376 				unsigned_flag = true;
377 				break;
378 			case 'd':
379 				detail_flag = true;
380 				break;
381 			case 'v':
382 				printf("cstool for Capstone Disassembler, v%u.%u.%u\n", CS_VERSION_MAJOR, CS_VERSION_MINOR, CS_VERSION_EXTRA);
383 
384 				printf("Capstone build: ");
385 				if (cs_support(CS_ARCH_X86)) {
386 					printf("x86=1 ");
387 				}
388 
389 				if (cs_support(CS_ARCH_ARM)) {
390 					printf("arm=1 ");
391 				}
392 
393 				if (cs_support(CS_ARCH_ARM64)) {
394 					printf("arm64=1 ");
395 				}
396 
397 				if (cs_support(CS_ARCH_MIPS)) {
398 					printf("mips=1 ");
399 				}
400 
401 				if (cs_support(CS_ARCH_PPC)) {
402 					printf("ppc=1 ");
403 				}
404 
405 				if (cs_support(CS_ARCH_SPARC)) {
406 					printf("sparc=1 ");
407 				}
408 
409 				if (cs_support(CS_ARCH_SYSZ)) {
410 					printf("sysz=1 ");
411 				}
412 
413 				if (cs_support(CS_ARCH_XCORE)) {
414 					printf("xcore=1 ");
415 				}
416 
417 				if (cs_support(CS_ARCH_M68K)) {
418 					printf("m68k=1 ");
419 				}
420 
421 				if (cs_support(CS_ARCH_TMS320C64X)) {
422 					printf("tms320c64x=1 ");
423 				}
424 
425 				if (cs_support(CS_ARCH_M680X)) {
426 					printf("m680x=1 ");
427 				}
428 
429 				if (cs_support(CS_ARCH_EVM)) {
430 					printf("evm=1 ");
431 				}
432 
433 				if (cs_support(CS_ARCH_WASM)) {
434 					printf("wasm=1 ");
435 				}
436 
437 				if (cs_support(CS_ARCH_MOS65XX)) {
438 					printf("mos65xx=1 ");
439 				}
440 
441 				if (cs_support(CS_ARCH_BPF)) {
442 					printf("bpf=1 ");
443 				}
444 
445 				if (cs_support(CS_ARCH_RISCV)) {
446 					printf("riscv=1 ");
447 				}
448 
449 				if (cs_support(CS_SUPPORT_DIET)) {
450 					printf("diet=1 ");
451 				}
452 
453 				if (cs_support(CS_SUPPORT_X86_REDUCE)) {
454 					printf("x86_reduce=1 ");
455 				}
456 
457 				printf("\n");
458 				return 0;
459 			case 'h':
460 				usage(argv[0]);
461 				return 0;
462 			default:
463 				usage(argv[0]);
464 				return -1;
465 		}
466 	}
467 
468 	args_left = argc - optind;
469 	if (args_left < 2 || args_left > 3) {
470 		usage(argv[0]);
471 		return -1;
472 	}
473 
474 	mode = argv[optind];
475 	assembly = preprocess(argv[optind + 1], &size);
476 	if (!assembly) {
477 		usage(argv[0]);
478 		return -1;
479 	}
480 
481 	if (args_left == 3) {
482 		char *temp, *src = argv[optind + 2];
483 		address = strtoull(src, &temp, 16);
484 		if (temp == src || *temp != '\0' || errno == ERANGE) {
485 			printf("ERROR: invalid address argument, quit!\n");
486 			return -2;
487 		}
488 	}
489 
490 	for (i = 0; all_archs[i].name; i++) {
491 		if (!strcmp(all_archs[i].name, mode)) {
492 			arch = all_archs[i].arch;
493 			err = cs_open(all_archs[i].arch, all_archs[i].mode, &handle);
494 			if (!err) {
495 				md = all_archs[i].mode;
496 				if (strstr (mode, "att")) {
497 					cs_option(handle, CS_OPT_SYNTAX, CS_OPT_SYNTAX_ATT);
498 				}
499 
500 				// turn on SKIPDATA mode
501 				if (skipdata)
502 					cs_option(handle, CS_OPT_SKIPDATA, CS_OPT_ON);
503 			}
504 			break;
505 		}
506 	}
507 
508 	if (arch == CS_ARCH_ALL) {
509 		printf("ERROR: Invalid <arch+mode>: \"%s\", quit!\n", mode);
510 		usage(argv[0]);
511 		return -1;
512 	}
513 
514 	if (err) {
515 		printf("ERROR: Failed on cs_open(), quit!\n");
516 		usage(argv[0]);
517 		return -1;
518 	}
519 
520 	if (detail_flag) {
521 		cs_option(handle, CS_OPT_DETAIL, CS_OPT_ON);
522 	}
523 
524 	if (unsigned_flag) {
525 		cs_option(handle, CS_OPT_UNSIGNED, CS_OPT_ON);
526 	}
527 
528 	count = cs_disasm(handle, assembly, size, address, 0, &insn);
529 	if (count > 0) {
530 		size_t i;
531 
532 		for (i = 0; i < count; i++) {
533 			int j;
534 
535 			printf("%2"PRIx64"  ", insn[i].address);
536 			for (j = 0; j < insn[i].size; j++) {
537 				if (j > 0)
538 					putchar(' ');
539 				printf("%02x", insn[i].bytes[j]);
540 			}
541 			// X86 instruction size is variable.
542 			// align assembly instruction after the opcode
543 			if (arch == CS_ARCH_X86) {
544 				for (; j < 16; j++) {
545 					printf("   ");
546 				}
547 			}
548 
549 			printf("  %s\t%s\n", insn[i].mnemonic, insn[i].op_str);
550 
551 			if (detail_flag) {
552 				print_details(handle, arch, md, &insn[i]);
553 			}
554 		}
555 
556 		cs_free(insn, count);
557 	} else {
558 		printf("ERROR: invalid assembly code\n");
559 		return(-4);
560 	}
561 
562 	cs_close(&handle);
563 	free(assembly);
564 
565 	return 0;
566 }
567