aboutsummaryrefslogtreecommitdiffstats
path: root/capstone/cstool/cstool.c
diff options
context:
space:
mode:
Diffstat (limited to 'capstone/cstool/cstool.c')
-rw-r--r--capstone/cstool/cstool.c566
1 files changed, 566 insertions, 0 deletions
diff --git a/capstone/cstool/cstool.c b/capstone/cstool/cstool.c
new file mode 100644
index 000000000..9bd5543d4
--- /dev/null
+++ b/capstone/cstool/cstool.c
@@ -0,0 +1,566 @@
+/* Tang Yuhang <tyh000011112222@gmail.com> 2016 */
+/* pancake <pancake@nopcode.org> 2017 */
+
+#include <string.h>
+#include <ctype.h>
+#include <errno.h>
+#include "getopt.h"
+
+#include <capstone/capstone.h>
+
+void print_string_hex(const char *comment, unsigned char *str, size_t len);
+
+static struct {
+ const char *name;
+ cs_arch arch;
+ cs_mode mode;
+} all_archs[] = {
+ { "arm", CS_ARCH_ARM, CS_MODE_ARM },
+ { "armb", CS_ARCH_ARM, CS_MODE_ARM | CS_MODE_BIG_ENDIAN },
+ { "armbe", CS_ARCH_ARM, CS_MODE_ARM | CS_MODE_BIG_ENDIAN },
+ { "arml", CS_ARCH_ARM, CS_MODE_ARM | CS_MODE_LITTLE_ENDIAN },
+ { "armle", CS_ARCH_ARM, CS_MODE_ARM | CS_MODE_LITTLE_ENDIAN },
+ { "armv8", CS_ARCH_ARM, CS_MODE_ARM | CS_MODE_V8 },
+ { "thumbv8", CS_ARCH_ARM, CS_MODE_ARM | CS_MODE_THUMB | CS_MODE_V8 },
+ { "armv8be", CS_ARCH_ARM, CS_MODE_ARM | CS_MODE_V8 | CS_MODE_BIG_ENDIAN },
+ { "thumbv8be", CS_ARCH_ARM, CS_MODE_ARM | CS_MODE_THUMB | CS_MODE_V8 | CS_MODE_BIG_ENDIAN },
+ { "cortexm", CS_ARCH_ARM, CS_MODE_ARM | CS_MODE_THUMB | CS_MODE_MCLASS },
+ { "thumb", CS_ARCH_ARM, CS_MODE_ARM | CS_MODE_THUMB },
+ { "thumbbe", CS_ARCH_ARM, CS_MODE_ARM | CS_MODE_THUMB | CS_MODE_BIG_ENDIAN },
+ { "thumble", CS_ARCH_ARM, CS_MODE_ARM | CS_MODE_THUMB | CS_MODE_LITTLE_ENDIAN },
+ { "arm64", CS_ARCH_ARM64, CS_MODE_LITTLE_ENDIAN },
+ { "arm64be", CS_ARCH_ARM64, CS_MODE_BIG_ENDIAN },
+ { "mips", CS_ARCH_MIPS, CS_MODE_MIPS32 | CS_MODE_LITTLE_ENDIAN },
+ { "mipsmicro", CS_ARCH_MIPS, CS_MODE_MIPS32 | CS_MODE_MICRO },
+ { "mipsbemicro", CS_ARCH_MIPS, CS_MODE_MIPS32 | CS_MODE_MICRO | CS_MODE_BIG_ENDIAN },
+ { "mipsbe32r6", CS_ARCH_MIPS, CS_MODE_MIPS32R6 | CS_MODE_BIG_ENDIAN},
+ { "mipsbe32r6micro", CS_ARCH_MIPS, CS_MODE_MIPS32R6 | CS_MODE_BIG_ENDIAN | CS_MODE_MICRO },
+ { "mips32r6", CS_ARCH_MIPS, CS_MODE_MIPS32R6 },
+ { "mips32r6micro", CS_ARCH_MIPS, CS_MODE_MIPS32R6 | CS_MODE_MICRO },
+ { "mipsbe", CS_ARCH_MIPS, CS_MODE_MIPS32 | CS_MODE_BIG_ENDIAN },
+ { "mips64", CS_ARCH_MIPS, CS_MODE_MIPS64 | CS_MODE_LITTLE_ENDIAN },
+ { "mips64be", CS_ARCH_MIPS, CS_MODE_MIPS64 | CS_MODE_BIG_ENDIAN },
+ { "x16", CS_ARCH_X86, CS_MODE_16 }, // CS_MODE_16
+ { "x16att", CS_ARCH_X86, CS_MODE_16 }, // CS_MODE_16 , CS_OPT_SYNTAX_ATT
+ { "x32", CS_ARCH_X86, CS_MODE_32 }, // CS_MODE_32
+ { "x32att", CS_ARCH_X86, CS_MODE_32 }, // CS_MODE_32, CS_OPT_SYNTAX_ATT
+ { "x64", CS_ARCH_X86, CS_MODE_64 }, // CS_MODE_64
+ { "x64att", CS_ARCH_X86, CS_MODE_64 }, // CS_MODE_64, CS_OPT_SYNTAX_ATT
+ { "ppc32", CS_ARCH_PPC, CS_MODE_32 | CS_MODE_LITTLE_ENDIAN },
+ { "ppc32be", CS_ARCH_PPC, CS_MODE_32 | CS_MODE_BIG_ENDIAN },
+ { "ppc32qpx", CS_ARCH_PPC, CS_MODE_32 | CS_MODE_QPX | CS_MODE_LITTLE_ENDIAN },
+ { "ppc32beqpx", CS_ARCH_PPC, CS_MODE_32 | CS_MODE_QPX | CS_MODE_BIG_ENDIAN },
+ { "ppc64", CS_ARCH_PPC, CS_MODE_64 | CS_MODE_LITTLE_ENDIAN },
+ { "ppc64be", CS_ARCH_PPC, CS_MODE_64 | CS_MODE_BIG_ENDIAN },
+ { "ppc64qpx", CS_ARCH_PPC, CS_MODE_64 | CS_MODE_QPX | CS_MODE_LITTLE_ENDIAN },
+ { "ppc64beqpx", CS_ARCH_PPC, CS_MODE_64 | CS_MODE_QPX | CS_MODE_BIG_ENDIAN },
+ { "sparc", CS_ARCH_SPARC, CS_MODE_BIG_ENDIAN },
+ { "sparcv9", CS_ARCH_SPARC, CS_MODE_BIG_ENDIAN | CS_MODE_V9 },
+ { "systemz", CS_ARCH_SYSZ, CS_MODE_BIG_ENDIAN },
+ { "sysz", CS_ARCH_SYSZ, CS_MODE_BIG_ENDIAN },
+ { "s390x", CS_ARCH_SYSZ, CS_MODE_BIG_ENDIAN },
+ { "xcore", CS_ARCH_XCORE, CS_MODE_BIG_ENDIAN },
+ { "m68k", CS_ARCH_M68K, CS_MODE_BIG_ENDIAN },
+ { "m68k40", CS_ARCH_M68K, CS_MODE_M68K_040 },
+ { "tms320c64x", CS_ARCH_TMS320C64X, CS_MODE_BIG_ENDIAN },
+ { "m6800", CS_ARCH_M680X, CS_MODE_M680X_6800 },
+ { "m6801", CS_ARCH_M680X, CS_MODE_M680X_6801 },
+ { "m6805", CS_ARCH_M680X, CS_MODE_M680X_6805 },
+ { "m6808", CS_ARCH_M680X, CS_MODE_M680X_6808 },
+ { "m6809", CS_ARCH_M680X, CS_MODE_M680X_6809 },
+ { "m6811", CS_ARCH_M680X, CS_MODE_M680X_6811 },
+ { "cpu12", CS_ARCH_M680X, CS_MODE_M680X_CPU12 },
+ { "hd6301", CS_ARCH_M680X, CS_MODE_M680X_6301 },
+ { "hd6309", CS_ARCH_M680X, CS_MODE_M680X_6309 },
+ { "hcs08", CS_ARCH_M680X, CS_MODE_M680X_HCS08 },
+ { "evm", CS_ARCH_EVM, 0 },
+ { "wasm", CS_ARCH_WASM, 0 },
+ { "bpf", CS_ARCH_BPF, CS_MODE_LITTLE_ENDIAN | CS_MODE_BPF_CLASSIC },
+ { "bpfbe", CS_ARCH_BPF, CS_MODE_BIG_ENDIAN | CS_MODE_BPF_CLASSIC },
+ { "ebpf", CS_ARCH_BPF, CS_MODE_LITTLE_ENDIAN | CS_MODE_BPF_EXTENDED },
+ { "ebpfbe", CS_ARCH_BPF, CS_MODE_BIG_ENDIAN | CS_MODE_BPF_EXTENDED },
+ { "riscv32", CS_ARCH_RISCV, CS_MODE_RISCV32 },
+ { "riscv64", CS_ARCH_RISCV, CS_MODE_RISCV64 },
+ { "6502", CS_ARCH_MOS65XX, CS_MODE_MOS65XX_6502 },
+ { "65c02", CS_ARCH_MOS65XX, CS_MODE_MOS65XX_65C02 },
+ { "w65c02", CS_ARCH_MOS65XX, CS_MODE_MOS65XX_W65C02 },
+ { "65816", CS_ARCH_MOS65XX, CS_MODE_MOS65XX_65816_LONG_MX },
+ { NULL }
+};
+
+void print_insn_detail_x86(csh ud, cs_mode mode, cs_insn *ins);
+void print_insn_detail_arm(csh handle, cs_insn *ins);
+void print_insn_detail_arm64(csh handle, cs_insn *ins);
+void print_insn_detail_mips(csh handle, cs_insn *ins);
+void print_insn_detail_ppc(csh handle, cs_insn *ins);
+void print_insn_detail_sparc(csh handle, cs_insn *ins);
+void print_insn_detail_sysz(csh handle, cs_insn *ins);
+void print_insn_detail_xcore(csh handle, cs_insn *ins);
+void print_insn_detail_m68k(csh handle, cs_insn *ins);
+void print_insn_detail_tms320c64x(csh handle, cs_insn *ins);
+void print_insn_detail_m680x(csh handle, cs_insn *ins);
+void print_insn_detail_evm(csh handle, cs_insn *ins);
+void print_insn_detail_riscv(csh handle, cs_insn *ins);
+void print_insn_detail_wasm(csh handle, cs_insn *ins);
+void print_insn_detail_mos65xx(csh handle, cs_insn *ins);
+void print_insn_detail_bpf(csh handle, cs_insn *ins);
+
+static void print_details(csh handle, cs_arch arch, cs_mode md, cs_insn *ins);
+
+void print_string_hex(const char *comment, unsigned char *str, size_t len)
+{
+ unsigned char *c;
+
+ printf("%s", comment);
+ for (c = str; c < str + len; c++) {
+ printf("0x%02x ", *c & 0xff);
+ }
+
+ printf("\n");
+}
+
+// convert hexchar to hexnum
+static uint8_t char_to_hexnum(char c)
+{
+ if (c >= '0' && c <= '9') {
+ return (uint8_t)(c - '0');
+ }
+
+ if (c >= 'a' && c <= 'f') {
+ return (uint8_t)(10 + c - 'a');
+ }
+
+ // c >= 'A' && c <= 'F'
+ return (uint8_t)(10 + c - 'A');
+}
+
+// convert user input (char[]) to uint8_t[], each element of which is
+// valid hexadecimal, and return actual length of uint8_t[] in @size.
+static uint8_t *preprocess(char *code, size_t *size)
+{
+ size_t i = 0, j = 0;
+ uint8_t high, low;
+ uint8_t *result;
+
+ if (strlen(code) == 0)
+ return NULL;
+
+ result = (uint8_t *)malloc(strlen(code));
+ if (result != NULL) {
+ while (code[i] != '\0') {
+ if (isxdigit(code[i]) && isxdigit(code[i+1])) {
+ high = 16 * char_to_hexnum(code[i]);
+ low = char_to_hexnum(code[i+1]);
+ result[j] = high + low;
+ i++;
+ j++;
+ }
+ i++;
+ }
+ *size = j;
+ }
+
+ return result;
+}
+
+static void usage(char *prog)
+{
+ printf("Cstool for Capstone Disassembler Engine v%u.%u.%u\n\n", CS_VERSION_MAJOR, CS_VERSION_MINOR, CS_VERSION_EXTRA);
+ printf("Syntax: %s [-d|-s|-u|-v] <arch+mode> <assembly-hexstring> [start-address-in-hex-format]\n", prog);
+ printf("\nThe following <arch+mode> options are supported:\n");
+
+ if (cs_support(CS_ARCH_X86)) {
+ printf(" x16 16-bit mode (X86)\n");
+ printf(" x32 32-bit mode (X86)\n");
+ printf(" x64 64-bit mode (X86)\n");
+ printf(" x16att 16-bit mode (X86), syntax AT&T\n");
+ printf(" x32att 32-bit mode (X86), syntax AT&T\n");
+ printf(" x64att 64-bit mode (X86), syntax AT&T\n");
+ }
+
+ if (cs_support(CS_ARCH_ARM)) {
+ printf(" arm arm\n");
+ printf(" armbe arm + big endian\n");
+ printf(" thumb thumb mode\n");
+ printf(" thumbbe thumb + big endian\n");
+ printf(" cortexm thumb + cortex-m extensions\n");
+ printf(" armv8 arm v8\n");
+ printf(" thumbv8 thumb v8\n");
+ printf(" armv8be arm v8 + big endian\n");
+ printf(" thumbv8be thumb v8 + big endian\n");
+ }
+
+ if (cs_support(CS_ARCH_ARM64)) {
+ printf(" arm64 aarch64 mode\n");
+ printf(" arm64be aarch64 + big endian\n");
+ }
+
+ if (cs_support(CS_ARCH_MIPS)) {
+ printf(" mips mips32 + little endian\n");
+ printf(" mipsbe mips32 + big endian\n");
+ printf(" mips64 mips64 + little endian\n");
+ printf(" mips64be mips64 + big endian\n");
+ }
+
+ if (cs_support(CS_ARCH_PPC)) {
+ printf(" ppc32 ppc32 + little endian\n");
+ printf(" ppc32be ppc32 + big endian\n");
+ printf(" ppc32qpx ppc32 + qpx + little endian\n");
+ printf(" ppc32beqpx ppc32 + qpx + big endian\n");
+ printf(" ppc64 ppc64 + little endian\n");
+ printf(" ppc64be ppc64 + big endian\n");
+ printf(" ppc64qpx ppc64 + qpx + little endian\n");
+ printf(" ppc64beqpx ppc64 + qpx + big endian\n");
+ }
+
+ if (cs_support(CS_ARCH_SPARC)) {
+ printf(" sparc sparc\n");
+ }
+
+ if (cs_support(CS_ARCH_SYSZ)) {
+ printf(" systemz systemz (s390x)\n");
+ }
+
+ if (cs_support(CS_ARCH_XCORE)) {
+ printf(" xcore xcore\n");
+ }
+
+ if (cs_support(CS_ARCH_M68K)) {
+ printf(" m68k m68k + big endian\n");
+ printf(" m68k40 m68k_040\n");
+ }
+
+ if (cs_support(CS_ARCH_TMS320C64X)) {
+ printf(" tms320c64x TMS320C64x\n");
+ }
+
+ if (cs_support(CS_ARCH_M680X)) {
+ printf(" m6800 M6800/2\n");
+ printf(" m6801 M6801/3\n");
+ printf(" m6805 M6805\n");
+ printf(" m6808 M68HC08\n");
+ printf(" m6809 M6809\n");
+ printf(" m6811 M68HC11\n");
+ printf(" cpu12 M68HC12/HCS12\n");
+ printf(" hd6301 HD6301/3\n");
+ printf(" hd6309 HD6309\n");
+ printf(" hcs08 HCS08\n");
+ }
+
+ if (cs_support(CS_ARCH_EVM)) {
+ printf(" evm Ethereum Virtual Machine\n");
+ }
+
+ if (cs_support(CS_ARCH_MOS65XX)) {
+ printf(" 6502 MOS 6502\n");
+ printf(" 65c02 WDC 65c02\n");
+ printf(" w65c02 WDC w65c02\n");
+ printf(" 65816 WDC 65816 (long m/x)\n");
+ }
+
+ if (cs_support(CS_ARCH_WASM)) {
+ printf(" wasm: Web Assembly\n");
+ }
+
+ if (cs_support(CS_ARCH_BPF)) {
+ printf(" bpf Classic BPF\n");
+ printf(" bpfbe Classic BPF + big endian\n");
+ printf(" ebpf Extended BPF\n");
+ printf(" ebpfbe Extended BPF + big endian\n");
+ }
+
+ if (cs_support(CS_ARCH_RISCV)) {
+ printf(" riscv32 riscv32\n");
+ printf(" riscv64 riscv64\n");
+ }
+
+ printf("\nExtra options:\n");
+ printf(" -d show detailed information of the instructions\n");
+ printf(" -s decode in SKIPDATA mode\n");
+ printf(" -u show immediates as unsigned\n");
+ printf(" -v show version & Capstone core build info\n\n");
+}
+
+static void print_details(csh handle, cs_arch arch, cs_mode md, cs_insn *ins)
+{
+ printf("\tID: %u (%s)\n", ins->id, cs_insn_name(handle, ins->id));
+
+ switch(arch) {
+ case CS_ARCH_X86:
+ print_insn_detail_x86(handle, md, ins);
+ break;
+ case CS_ARCH_ARM:
+ print_insn_detail_arm(handle, ins);
+ break;
+ case CS_ARCH_ARM64:
+ print_insn_detail_arm64(handle, ins);
+ break;
+ case CS_ARCH_MIPS:
+ print_insn_detail_mips(handle, ins);
+ break;
+ case CS_ARCH_PPC:
+ print_insn_detail_ppc(handle, ins);
+ break;
+ case CS_ARCH_SPARC:
+ print_insn_detail_sparc(handle, ins);
+ break;
+ case CS_ARCH_SYSZ:
+ print_insn_detail_sysz(handle, ins);
+ break;
+ case CS_ARCH_XCORE:
+ print_insn_detail_xcore(handle, ins);
+ break;
+ case CS_ARCH_M68K:
+ print_insn_detail_m68k(handle, ins);
+ break;
+ case CS_ARCH_TMS320C64X:
+ print_insn_detail_tms320c64x(handle, ins);
+ break;
+ case CS_ARCH_M680X:
+ print_insn_detail_m680x(handle, ins);
+ break;
+ case CS_ARCH_EVM:
+ print_insn_detail_evm(handle, ins);
+ break;
+ case CS_ARCH_WASM:
+ print_insn_detail_wasm(handle, ins);
+ break;
+ case CS_ARCH_MOS65XX:
+ print_insn_detail_mos65xx(handle, ins);
+ break;
+ case CS_ARCH_BPF:
+ print_insn_detail_bpf(handle, ins);
+ break;
+ case CS_ARCH_RISCV:
+ print_insn_detail_riscv(handle, ins);
+ break;
+ default: break;
+ }
+
+ if (ins->detail->groups_count) {
+ int j;
+
+ printf("\tGroups: ");
+ for(j = 0; j < ins->detail->groups_count; j++) {
+ printf("%s ", cs_group_name(handle, ins->detail->groups[j]));
+ }
+ printf("\n");
+ }
+
+ printf("\n");
+}
+
+int main(int argc, char **argv)
+{
+ int i, c;
+ csh handle;
+ char *mode;
+ uint8_t *assembly;
+ size_t count, size;
+ uint64_t address = 0LL;
+ cs_insn *insn;
+ cs_err err;
+ cs_mode md;
+ cs_arch arch = CS_ARCH_ALL;
+ bool detail_flag = false;
+ bool unsigned_flag = false;
+ bool skipdata = false;
+ int args_left;
+
+ while ((c = getopt (argc, argv, "sudhv")) != -1) {
+ switch (c) {
+ case 's':
+ skipdata = true;
+ break;
+ case 'u':
+ unsigned_flag = true;
+ break;
+ case 'd':
+ detail_flag = true;
+ break;
+ case 'v':
+ printf("cstool for Capstone Disassembler, v%u.%u.%u\n", CS_VERSION_MAJOR, CS_VERSION_MINOR, CS_VERSION_EXTRA);
+
+ printf("Capstone build: ");
+ if (cs_support(CS_ARCH_X86)) {
+ printf("x86=1 ");
+ }
+
+ if (cs_support(CS_ARCH_ARM)) {
+ printf("arm=1 ");
+ }
+
+ if (cs_support(CS_ARCH_ARM64)) {
+ printf("arm64=1 ");
+ }
+
+ if (cs_support(CS_ARCH_MIPS)) {
+ printf("mips=1 ");
+ }
+
+ if (cs_support(CS_ARCH_PPC)) {
+ printf("ppc=1 ");
+ }
+
+ if (cs_support(CS_ARCH_SPARC)) {
+ printf("sparc=1 ");
+ }
+
+ if (cs_support(CS_ARCH_SYSZ)) {
+ printf("sysz=1 ");
+ }
+
+ if (cs_support(CS_ARCH_XCORE)) {
+ printf("xcore=1 ");
+ }
+
+ if (cs_support(CS_ARCH_M68K)) {
+ printf("m68k=1 ");
+ }
+
+ if (cs_support(CS_ARCH_TMS320C64X)) {
+ printf("tms320c64x=1 ");
+ }
+
+ if (cs_support(CS_ARCH_M680X)) {
+ printf("m680x=1 ");
+ }
+
+ if (cs_support(CS_ARCH_EVM)) {
+ printf("evm=1 ");
+ }
+
+ if (cs_support(CS_ARCH_WASM)) {
+ printf("wasm=1 ");
+ }
+
+ if (cs_support(CS_ARCH_MOS65XX)) {
+ printf("mos65xx=1 ");
+ }
+
+ if (cs_support(CS_ARCH_BPF)) {
+ printf("bpf=1 ");
+ }
+
+ if (cs_support(CS_ARCH_RISCV)) {
+ printf("riscv=1 ");
+ }
+
+ if (cs_support(CS_SUPPORT_DIET)) {
+ printf("diet=1 ");
+ }
+
+ if (cs_support(CS_SUPPORT_X86_REDUCE)) {
+ printf("x86_reduce=1 ");
+ }
+
+ printf("\n");
+ return 0;
+ case 'h':
+ usage(argv[0]);
+ return 0;
+ default:
+ usage(argv[0]);
+ return -1;
+ }
+ }
+
+ args_left = argc - optind;
+ if (args_left < 2 || args_left > 3) {
+ usage(argv[0]);
+ return -1;
+ }
+
+ mode = argv[optind];
+ assembly = preprocess(argv[optind + 1], &size);
+ if (!assembly) {
+ usage(argv[0]);
+ return -1;
+ }
+
+ if (args_left == 3) {
+ char *temp, *src = argv[optind + 2];
+ address = strtoull(src, &temp, 16);
+ if (temp == src || *temp != '\0' || errno == ERANGE) {
+ printf("ERROR: invalid address argument, quit!\n");
+ return -2;
+ }
+ }
+
+ for (i = 0; all_archs[i].name; i++) {
+ if (!strcmp(all_archs[i].name, mode)) {
+ arch = all_archs[i].arch;
+ err = cs_open(all_archs[i].arch, all_archs[i].mode, &handle);
+ if (!err) {
+ md = all_archs[i].mode;
+ if (strstr (mode, "att")) {
+ cs_option(handle, CS_OPT_SYNTAX, CS_OPT_SYNTAX_ATT);
+ }
+
+ // turn on SKIPDATA mode
+ if (skipdata)
+ cs_option(handle, CS_OPT_SKIPDATA, CS_OPT_ON);
+ }
+ break;
+ }
+ }
+
+ if (arch == CS_ARCH_ALL) {
+ printf("ERROR: Invalid <arch+mode>: \"%s\", quit!\n", mode);
+ usage(argv[0]);
+ return -1;
+ }
+
+ if (err) {
+ printf("ERROR: Failed on cs_open(), quit!\n");
+ usage(argv[0]);
+ return -1;
+ }
+
+ if (detail_flag) {
+ cs_option(handle, CS_OPT_DETAIL, CS_OPT_ON);
+ }
+
+ if (unsigned_flag) {
+ cs_option(handle, CS_OPT_UNSIGNED, CS_OPT_ON);
+ }
+
+ count = cs_disasm(handle, assembly, size, address, 0, &insn);
+ if (count > 0) {
+ size_t i;
+
+ for (i = 0; i < count; i++) {
+ int j;
+
+ printf("%2"PRIx64" ", insn[i].address);
+ for (j = 0; j < insn[i].size; j++) {
+ if (j > 0)
+ putchar(' ');
+ printf("%02x", insn[i].bytes[j]);
+ }
+ // X86 instruction size is variable.
+ // align assembly instruction after the opcode
+ if (arch == CS_ARCH_X86) {
+ for (; j < 16; j++) {
+ printf(" ");
+ }
+ }
+
+ printf(" %s\t%s\n", insn[i].mnemonic, insn[i].op_str);
+
+ if (detail_flag) {
+ print_details(handle, arch, md, &insn[i]);
+ }
+ }
+
+ cs_free(insn, count);
+ } else {
+ printf("ERROR: invalid assembly code\n");
+ return(-4);
+ }
+
+ cs_close(&handle);
+ free(assembly);
+
+ return 0;
+}