Merge branch 'next' of https://github.com/aquynh/capstone into next
diff --git a/.gitignore b/.gitignore
index 26b340a..a22e9bb 100644
--- a/.gitignore
+++ b/.gitignore
@@ -101,3 +101,5 @@
 
 
 *.s
+
+cstool/cstool
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 36e7061..8cb2013 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -449,3 +449,10 @@
             LIBRARY DESTINATION lib
             ARCHIVE DESTINATION lib)
 endif ()
+
+if (CAPSTONE_BUILD_SHARED)
+add_executable(cstool "cstool/cstool.c")
+target_link_libraries(cstool ${default-target})
+
+install(TARGETS cstool DESTINATION bin)
+endif ()
diff --git a/HACK.TXT b/HACK.TXT
index 8651410..522b360 100644
--- a/HACK.TXT
+++ b/HACK.TXT
@@ -17,6 +17,7 @@
 │   ├── ocaml       <- Ocaml bindings + test code
 │   └── python      <- Python bindings + test code
 ├── contrib         <- Code contributed by community to help Capstone integration
+├── cstool          <- Cstool
 ├── docs            <- Documentation
 ├── include         <- API headers in C language (*.h)
 ├── msvc            <- Microsoft Visual Studio support (for Windows compile)
@@ -35,6 +36,10 @@
 	$ ./make.sh
 	$ sudo ./make.sh install
 
+Then test Capstone with cstool, for example:
+
+	$ cstool x32 "90 91"
+
 At the same time, for Java/Ocaml/Python bindings, be sure to always use
 the bindings coming with the core to avoid potential incompatibility issue
 with older versions.
diff --git a/Makefile b/Makefile
index e709d50..95ac7c5 100644
--- a/Makefile
+++ b/Makefile
@@ -74,6 +74,7 @@
 # Or better, pass 'LIBDIRARCH=lib64' to 'make install/uninstall' via 'make.sh'.
 #LIBDIRARCH ?= lib64
 LIBDIR ?= $(PREFIX)/$(LIBDIRARCH)
+BINDIR = $(PREFIX)/bin
 
 LIBDATADIR ?= $(LIBDIR)
 
@@ -355,6 +356,7 @@
 
 all: $(LIBRARY) $(ARCHIVE) $(PKGCFGF)
 ifeq (,$(findstring yes,$(CAPSTONE_BUILD_CORE_ONLY)))
+	@V=$(V) $(MAKE) -C cstool
 ifndef BUILDDIR
 	cd tests && $(MAKE)
 else
@@ -405,25 +407,28 @@
 endif
 
 install: $(PKGCFGF) $(ARCHIVE) $(LIBRARY)
-	mkdir -p $(DESTDIR)/$(LIBDIR)
-	$(call install-library,$(DESTDIR)/$(LIBDIR))
+	mkdir -p $(DESTDIR)$(LIBDIR)
+	$(call install-library,$(DESTDIR)$(LIBDIR))
 ifeq ($(CAPSTONE_STATIC),yes)
-	$(INSTALL_DATA) $(ARCHIVE) $(DESTDIR)/$(LIBDIR)
+	$(INSTALL_DATA) $(ARCHIVE) $(DESTDIR)$(LIBDIR)
 endif
-	mkdir -p $(DESTDIR)/$(INCDIR)/$(LIBNAME)
-	$(INSTALL_DATA) include/capstone/*.h $(DESTDIR)/$(INCDIR)/$(LIBNAME)
-	mkdir -p $(DESTDIR)/$(PKGCFGDIR)
-	$(INSTALL_DATA) $(PKGCFGF) $(DESTDIR)/$(PKGCFGDIR)
+	mkdir -p $(DESTDIR)$(INCDIR)/$(LIBNAME)
+	$(INSTALL_DATA) include/capstone/*.h $(DESTDIR)$(INCDIR)/$(LIBNAME)
+	mkdir -p $(DESTDIR)$(PKGCFGDIR)
+	$(INSTALL_DATA) $(PKGCFGF) $(DESTDIR)$(PKGCFGDIR)
+	$(INSTALL_LIB) cstool/cstool $(DESTDIR)$(BINDIR)
 
 uninstall:
-	rm -rf $(DESTDIR)/$(INCDIR)/$(LIBNAME)
-	rm -f $(DESTDIR)/$(LIBDIR)/lib$(LIBNAME).*
-	rm -f $(DESTDIR)/$(PKGCFGDIR)/$(LIBNAME).pc
+	rm -rf $(DESTDIR)$(INCDIR)/$(LIBNAME)
+	rm -f $(DESTDIR)$(LIBDIR)/lib$(LIBNAME).*
+	rm -f $(DESTDIR)$(PKGCFGDIR)/$(LIBNAME).pc
+	rm -f $(DESTDIR)$(BINDIR)/cstool
 
 clean:
 	rm -f $(LIBOBJ)
 	rm -f $(BLDIR)/lib$(LIBNAME).* $(BLDIR)/$(LIBNAME).*
 	rm -f $(PKGCFGF)
+	$(MAKE) -C cstool clean
 
 ifeq (,$(findstring yes,$(CAPSTONE_BUILD_CORE_ONLY)))
 	cd tests && $(MAKE) clean
diff --git a/arch/X86/X86Mapping.c b/arch/X86/X86Mapping.c
index 1ce5f47..6de2bcf 100644
--- a/arch/X86/X86Mapping.c
+++ b/arch/X86/X86Mapping.c
@@ -2616,6 +2616,25 @@
 							break;
 					}
 					break;
+
+				case X86_INS_RET:
+					switch(h->mode) {
+						case CS_MODE_16:
+							insn->detail->regs_write[0] = X86_REG_SP;
+							insn->detail->regs_read[0] = X86_REG_SP;
+							break;
+						case CS_MODE_32:
+							insn->detail->regs_write[0] = X86_REG_ESP;
+							insn->detail->regs_read[0] = X86_REG_ESP;
+							break;
+						default:	// 64-bit
+							insn->detail->regs_write[0] = X86_REG_RSP;
+							insn->detail->regs_read[0] = X86_REG_RSP;
+							break;
+					}
+					insn->detail->regs_write_count = 1;
+					insn->detail->regs_read_count = 1;
+					break;
 			}
 
 			memcpy(insn->detail->groups, insns[i].groups, sizeof(insns[i].groups));
@@ -2667,10 +2686,20 @@
 	{ X86_INSW, X86_REG_DX },
 	{ X86_INSL, X86_REG_DX },
 
-	{ X86_MOV64o64a, X86_REG_RAX },
-	{ X86_MOV32o32a, X86_REG_EAX },
-	{ X86_MOV64o32a, X86_REG_EAX },
+	{ X86_MOV8o16a, X86_REG_AL },
+	{ X86_MOV8o32a, X86_REG_AL },
+	{ X86_MOV8o64a, X86_REG_AL },
+
 	{ X86_MOV16o16a, X86_REG_AX },
+	{ X86_MOV16o32a, X86_REG_AX },
+	{ X86_MOV16o64a, X86_REG_AX },
+
+	{ X86_MOV32o16a, X86_REG_EAX },
+	{ X86_MOV32o32a, X86_REG_EAX },
+	{ X86_MOV32o64a, X86_REG_EAX },
+
+	{ X86_MOV64o32a, X86_REG_RAX },
+	{ X86_MOV64o64a, X86_REG_RAX },
 
 	{ X86_PUSHCS32, X86_REG_CS },
 	{ X86_PUSHDS32, X86_REG_DS },
diff --git a/bindings/python/capstone/__init__.py b/bindings/python/capstone/__init__.py
index 27e663f..a0f56d6 100644
--- a/bindings/python/capstone/__init__.py
+++ b/bindings/python/capstone/__init__.py
@@ -503,7 +503,7 @@
         if self._cs._detail and self._raw.id != 0:
             # save detail
             self._raw.detail = ctypes.pointer(all_info.detail._type_())
-            ctypes.pointer(self._raw.detail[0])[0] = all_info.detail[0]
+            ctypes.memmove(ctypes.byref(self._raw.detail[0]), ctypes.byref(all_info.detail[0]), ctypes.sizeof(type(all_info.detail[0])))
 
     # return instruction's ID.
     @property
@@ -976,6 +976,10 @@
             print(code)
             code = code.encode()
             print(code)'''
+        # Hack, unicorn's memory accessors give you back bytearrays, but they
+        # cause TypeErrors when you hand them into Capstone.
+        if isinstance(code, bytearray):
+            code = bytes(code)
         res = _cs.cs_disasm(self.csh, code, len(code), offset, count, ctypes.byref(all_insn))
         if res > 0:
             try:
diff --git a/cstool/Makefile b/cstool/Makefile
new file mode 100644
index 0000000..adde165
--- /dev/null
+++ b/cstool/Makefile
@@ -0,0 +1,29 @@
+# Makefile for Cstool of Capstone Disassembly Engine
+
+include ../functions.mk
+
+.PHONY: clean
+
+LIBNAME = capstone
+
+CFLAGS = -I../include
+LDFLAGS = -O3 -Wall -L.. -l$(LIBNAME)
+
+cstool: cstool.o
+ifeq ($(V),0)
+	$(call log,LINK,$@)
+	@${CC} $< $(LDFLAGS) -o $@
+else
+	${CC} $< $(LDFLAGS) -o $@
+endif
+
+clean:
+	${RM} -rf *.o cstool
+
+%.o: %.c
+ifeq ($(V),0)
+	$(call log,CC,$@)
+	@${CC} $(CFLAGS) -c $< -o $@
+else
+	${CC} $(CFLAGS) -c $< -o $@
+endif
diff --git a/cstool/README b/cstool/README
new file mode 100644
index 0000000..65479cb
--- /dev/null
+++ b/cstool/README
@@ -0,0 +1,26 @@
+This directory contains cstool of Capstone Engine.
+
+Cstool is a command-line tool to disassemble assembly hex-string.
+For example, to decode a hexcode string for Intel 32bit, run:
+
+	$ cstool x32 "90 91"
+
+	0	90	nop
+	1	91	xchg	eax, ecx
+
+Cstool disassembles the input and prints out the assembly instructions.
+On each line, the first column is the instruction offset, the second
+column is opcodes, and the rest is the instruction itself.
+
+Cstool is flexible enough to accept all kind of hexcode format. The following
+inputs have the same output with the example above.
+
+	$ cstool x32 "0x90 0x91"
+	$ cstool x32 "\x90\x91"
+	$ cstool x32 "90,91"
+	$ cstool x32 "90;91"
+	$ cstool x32 "90+91"
+	$ cstool x32 "90:91"
+
+To see all the supported options, run ./cstool
+
diff --git a/cstool/cstool.c b/cstool/cstool.c
new file mode 100644
index 0000000..a03ec57
--- /dev/null
+++ b/cstool/cstool.c
@@ -0,0 +1,280 @@
+/* Tang Yuhang <1648200150@qq.com> 2016 */
+#include <stdio.h>
+#include <inttypes.h>
+#include <string.h>
+#include <ctype.h>
+#include <errno.h>
+
+#include <capstone/capstone.h>
+
+#define VERSION "1.0"
+
+// 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;
+
+	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 v%s for Capstone Disassembler Engine (www.capstone-engine.org)\n\n", VERSION);
+	printf("Syntax: %s <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-att\n");
+		printf("        x32att:    32-bit mode (X86) syntax-att\n");
+		printf("        x64att:    64-bit mode (X86) syntax-att\n");
+	}
+
+	if (cs_support(CS_ARCH_ARM)) {
+		printf("        arm:       arm\n");
+		printf("        armb:      arm + big endian\n");
+		printf("        arml:      arm + little endian\n");
+		printf("        thumb:     thumb mode\n");
+		printf("        thumbbe:   thumb + big endian\n");
+		printf("        thumble:   thumb + billtle endian\n");
+	}
+
+	if (cs_support(CS_ARCH_ARM64)) {
+		printf("        arm64:     aarch64 mode\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("        ppc64:     ppc64 + little endian\n");
+		printf("        ppc64be:   ppc64 + 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");
+	}
+
+	printf("\n");
+}
+
+int main(int argc, char **argv)
+{
+	csh handle;
+	char *mode;
+	uint8_t *assembly;
+	size_t count, size;
+	uint64_t address = 0;
+	cs_insn *insn;
+	cs_err err;
+	bool x86_arch = false;
+
+	if (argc != 3 && argc != 4) {
+		usage(argv[0]);
+		return -1;
+	}
+
+	mode = argv[1];
+	assembly = preprocess(argv[2], &size);
+	if (assembly == NULL) {
+		printf("ERROR: invalid assembler-string argument, quit!\n");
+		return -3;
+	}
+
+	if (argc == 4) {
+		// cstool <arch> <assembly> <address>
+		char *temp;
+		address = strtoull(argv[3], &temp, 16);
+		if (temp == argv[3] || *temp != '\0' || errno == ERANGE) {
+			printf("ERROR: invalid address argument, quit!\n");
+			return -2;
+		}
+	}
+
+	if (!strcmp(mode, "arm")) {
+		err = cs_open(CS_ARCH_ARM, CS_MODE_ARM, &handle);
+	}
+
+	if (!strcmp(mode, "armb")) {
+		err = cs_open(CS_ARCH_ARM, CS_MODE_ARM + CS_MODE_BIG_ENDIAN, &handle);
+	}
+
+	if (!strcmp(mode, "arml")) {
+		err = cs_open(CS_ARCH_ARM, CS_MODE_ARM + CS_MODE_LITTLE_ENDIAN, &handle);
+	}
+
+	if (!strcmp(mode, "thumb")) {
+		err = cs_open(CS_ARCH_ARM, CS_MODE_THUMB + CS_MODE_LITTLE_ENDIAN, &handle);
+	}
+
+	if (!strcmp(mode, "thumbbe")) {
+		err = cs_open(CS_ARCH_ARM, CS_MODE_THUMB + CS_MODE_BIG_ENDIAN, &handle);
+	}
+
+	if (!strcmp(mode, "thumble")) {
+		err = cs_open(CS_ARCH_ARM, CS_MODE_ARM + CS_MODE_LITTLE_ENDIAN, &handle);
+	}
+
+	if (!strcmp(mode, "arm64")) {
+		err = cs_open(CS_ARCH_ARM64, CS_MODE_LITTLE_ENDIAN, &handle);
+	}
+
+	if (!strcmp(mode, "mips")) {
+		err = cs_open(CS_ARCH_MIPS, CS_MODE_MIPS32 + CS_MODE_LITTLE_ENDIAN, &handle);
+	}
+
+	if (!strcmp(mode, "mipsbe")) {
+		err = cs_open(CS_ARCH_MIPS, CS_MODE_MIPS32 + CS_MODE_BIG_ENDIAN, &handle);
+	}
+
+	if (!strcmp(mode, "mips64")) {
+		err = cs_open(CS_ARCH_MIPS, CS_MODE_MIPS64 + CS_MODE_BIG_ENDIAN, &handle);
+	}
+
+	if (!strcmp(mode, "mips64be")) {
+		err = cs_open(CS_ARCH_MIPS, CS_MODE_MIPS64 + CS_MODE_BIG_ENDIAN, &handle);
+	}
+
+	if (!strcmp(mode, "x16")) {
+		x86_arch = true;
+		err = cs_open(CS_ARCH_X86, CS_MODE_16, &handle);
+	}
+
+	if (!strcmp(mode, "x32")) {
+		x86_arch = true;
+		err = cs_open(CS_ARCH_X86, CS_MODE_32, &handle);
+	}
+
+	if (!strcmp(mode, "x64")) {
+		x86_arch = true;
+		err = cs_open(CS_ARCH_X86, CS_MODE_64, &handle);
+	}
+
+	if (!strcmp(mode, "x16att")) {
+		x86_arch = true;
+		err = cs_open(CS_ARCH_X86, CS_MODE_16, &handle);
+		if (!err) {
+			cs_option(handle, CS_OPT_SYNTAX, CS_OPT_SYNTAX_ATT);
+		}
+	}
+
+	if (!strcmp(mode,"x32att")) {
+		x86_arch = true;
+		err = cs_open(CS_ARCH_X86, CS_MODE_32, &handle);
+		if (!err) {
+			cs_option(handle, CS_OPT_SYNTAX, CS_OPT_SYNTAX_ATT);
+		}
+	}
+
+	if (!strcmp(mode,"x64att")) {
+		x86_arch = true;
+		err = cs_open(CS_ARCH_X86, CS_MODE_64, &handle);
+		if (!err) {
+			cs_option(handle, CS_OPT_SYNTAX, CS_OPT_SYNTAX_ATT);
+		}
+	}
+
+	if (!strcmp(mode,"ppc64")) {
+		err = cs_open(CS_ARCH_PPC, CS_MODE_64+CS_MODE_LITTLE_ENDIAN, &handle);
+	}
+
+	if (!strcmp(mode,"ppc64be")) {
+		err = cs_open(CS_ARCH_PPC,CS_MODE_64+CS_MODE_BIG_ENDIAN, &handle);
+	}
+
+	if (!strcmp(mode,"sparc")) {
+		err = cs_open(CS_ARCH_SPARC, CS_MODE_BIG_ENDIAN, &handle);
+	}
+
+	if (!strcmp(mode, "systemz") || !strcmp(mode, "sysz") || !strcmp(mode, "s390x")) {
+		err = cs_open(CS_ARCH_SYSZ, CS_MODE_BIG_ENDIAN, &handle);
+	}
+
+	if (!strcmp(mode,"xcore")) {
+		err = cs_open(CS_ARCH_XCORE, CS_MODE_BIG_ENDIAN, &handle);
+	}
+
+	if (err) {
+		printf("ERROR: Failed on cs_open(), quit!\n");
+		usage(argv[0]);
+		return -1;
+	}
+
+	count = cs_disasm(handle, assembly, size, address, 0, &insn);
+	if (count > 0) {
+		size_t i;
+
+		for (i = 0; i < count; i++) {
+			int j;
+			printf("%"PRIx64"  ", insn[i].address);
+			for (j = 0; j < insn[i].size; j++) {
+				printf("%02x", insn[i].bytes[j]);
+			}
+			// X86 instruction size is variable.
+			// align assembly instruction after the opcode
+			if (x86_arch) {
+				for (; j < 16; j++) {
+					printf("  ");
+				}
+			}
+			printf("  %s\t%s\n", insn[i].mnemonic, insn[i].op_str);
+		}
+		cs_free(insn, count);
+	} else {
+		printf("ERROR: invalid assembly code\n");
+		return(-4);
+	}
+
+	cs_close(&handle);
+
+	return 0;
+}
+
+