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