Merge branch 'master' of https://github.com/aquynh/capstone
diff --git a/.travis.yml b/.travis.yml
index aa8f5a1..8bcb54b 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -2,15 +2,32 @@
 sudo: false
 before_install:
         - export LD_LIBRARY_PATH=`pwd`/tests/:$LD_LIBRARY_PATH
+before_script:
+        - wget https://github.com/groundx/capstonefuzz/raw/master/corpus/corpus-libFuzzer-capstone_fuzz_disasmnext-latest.zip
+        - unzip corpus-libFuzzer-capstone_fuzz_disasmnext-latest.zip -d suite/fuzz
 script:
         - ./make.sh
         - make check
         - if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then cp libcapstone.so.* bindings/python/libcapstone.so; fi
         - if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then cp libcapstone.*.dylib bindings/python/libcapstone.dylib; fi
-        - cd bindings/python && make check
+        - if [[ "$NOPYTEST" != "true" ]]; then cd bindings/python && make check; fi
 compiler:
         - clang
         - gcc
 os:
         - linux
         - osx
+matrix:
+    include:
+        - name: fuzza
+          env: ASAN_OPTIONS=detect_leaks=0 CXXFLAGS="-DFUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION -fsanitize=address" CFLAGS="-DFUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION -fsanitize=address" LDFLAGS="-fsanitize=address" NOPYTEST=true
+          compiler: clang
+          os: linux
+        - name: fuzzm
+          env: CXXFLAGS="-DFUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION -fsanitize=memory" CFLAGS="-DFUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION -fsanitize=memory" LDFLAGS="-fsanitize=memory" NOPYTEST=true
+          compiler: clang
+          os: linux
+        - name: fuzzu
+          env: CXXFLAGS="-DFUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION -fsanitize=undefined" CFLAGS="-DFUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION -fsanitize=undefined -fno-sanitize-recover=undefined,integer" LDFLAGS="-fsanitize=undefined" NOPYTEST=true
+          compiler: clang
+          os: linux
diff --git a/HACK.TXT b/HACK.TXT
index e641c68..e593c30 100644
--- a/HACK.TXT
+++ b/HACK.TXT
@@ -5,12 +5,14 @@
 ├── arch            <- code handling disasm engine for each arch
 │   ├── AArch64     <- ARM64 (aka ARMv8) engine
 │   ├── ARM         <- ARM engine
+│   ├── EVM         <- Ethereum engine
 │   ├── M680X       <- M680X engine
 │   ├── M68K        <- M68K engine
 │   ├── Mips        <- Mips engine
 │   ├── PowerPC     <- PowerPC engine
 │   ├── Sparc       <- Sparc engine
 │   ├── SystemZ     <- SystemZ engine
+│   ├── TMS320C64x  <- TMS320C64x engine
 │   ├── X86         <- X86 engine
 │   └── XCore       <- XCore engine
 ├── bindings        <- all bindings are under this dir
diff --git a/Makefile b/Makefile
index a77247d..060b813 100644
--- a/Makefile
+++ b/Makefile
@@ -349,8 +349,10 @@
 	@V=$(V) CC=$(CC) $(MAKE) -C cstool
 ifndef BUILDDIR
 	$(MAKE) -C tests
+	$(MAKE) -C suite/fuzz
 else
 	$(MAKE) -C tests BUILDDIR=$(BLDIR)
+	$(MAKE) -C suite/fuzz BUILDDIR=$(BLDIR)
 endif
 	$(call install-library,$(BLDIR)/tests/)
 endif
@@ -426,6 +428,7 @@
 
 ifeq (,$(findstring yes,$(CAPSTONE_BUILD_CORE_ONLY)))
 	$(MAKE) -C tests clean
+	$(MAKE) -C suite/fuzz clean
 	rm -f $(BLDIR)/tests/lib$(LIBNAME).$(EXT)
 endif
 
@@ -458,10 +461,18 @@
 TESTS += test_m68k.static test_mips.static test_ppc.static test_sparc.static
 TESTS += test_systemz.static test_x86.static test_xcore.static test_m680x.static
 TESTS += test_skipdata test_skipdata.static test_iter.static test_evm.static
-check: $(TESTS)
+check: $(TESTS) fuzztest fuzzallcorp
 test_%:
 	./tests/$@ > /dev/null && echo OK || echo FAILED
 
+FUZZ_INPUTS = $(shell find suite/MC -type f -name '*.cs')
+
+fuzztest:
+	./suite/fuzz/fuzz_disasm $(FUZZ_INPUTS)
+
+fuzzallcorp:
+	./suite/fuzz/fuzz_bindisasm suite/fuzz/corpus-libFuzzer-capstone_fuzz_disasmnext-latest/
+
 $(OBJDIR)/%.o: %.c
 	@mkdir -p $(@D)
 ifeq ($(V),0)
diff --git a/arch/PowerPC/PPCInstPrinter.c b/arch/PowerPC/PPCInstPrinter.c
index df15aef..c46d067 100644
--- a/arch/PowerPC/PPCInstPrinter.c
+++ b/arch/PowerPC/PPCInstPrinter.c
@@ -460,18 +460,11 @@
 static void printS16ImmOperand(MCInst *MI, unsigned OpNo, SStream *O)
 {
 	if (MCOperand_isImm(MCInst_getOperand(MI, OpNo))) {
-		short Imm = (short)MCOperand_getImm(MCInst_getOperand(MI, OpNo));
-		if (Imm >= 0) {
-			if (Imm > HEX_THRESHOLD)
-				SStream_concat(O, "0x%x", Imm);
-			else
-				SStream_concat(O, "%u", Imm);
-		} else {
-			if (Imm < -HEX_THRESHOLD)
-				SStream_concat(O, "-0x%x", -Imm);
-			else
-				SStream_concat(O, "-%u", -Imm);
-		}
+		unsigned short Imm = (unsigned short)MCOperand_getImm(MCInst_getOperand(MI, OpNo));
+        if (Imm > HEX_THRESHOLD)
+            SStream_concat(O, "0x%x", Imm);
+        else
+            SStream_concat(O, "%u", Imm);
 
 		if (MI->csh->detail) {
 			MI->flat_insn->detail->ppc.operands[MI->flat_insn->detail->ppc.op_count].type = PPC_OP_IMM;
diff --git a/suite/fuzz/Makefile b/suite/fuzz/Makefile
index d890783..3370df3 100644
--- a/suite/fuzz/Makefile
+++ b/suite/fuzz/Makefile
@@ -1,10 +1,85 @@
+# Capstone Disassembler Engine
+# By Philippe Antoine <contact@catenacyber.fr>, 2018
+
+include ../../config.mk
+include ../../functions.mk
+
+ifneq ($(CAPSTONE_STATIC),yes)
+$(error Needs static capstone.)
+endif
+
+# Verbose output?
+V ?= 0
+
+INCDIR = ../../include
+ifndef BUILDDIR
+TESTDIR = .
+OBJDIR = .
+LIBDIR = ../..
+else
+TESTDIR = $(BUILDDIR)/tests
+OBJDIR = $(BUILDDIR)/obj/tests
+LIBDIR = $(BUILDDIR)
+endif
+
+CFLAGS += -Wall -I$(INCDIR)
+LDFLAGS += -L$(LIBDIR)
+
+CFLAGS += $(foreach arch,$(LIBARCHS),-arch $(arch))
+LDFLAGS += $(foreach arch,$(LIBARCHS),-arch $(arch))
+
 LIBNAME = capstone
 
+BIN_EXT =
+AR_EXT = a
+
+
+ARCHIVE = $(LIBDIR)/lib$(LIBNAME).$(AR_EXT)
+
+.PHONY: all clean
+
+SOURCES = fuzz_disasm.c drivermc.c fuzz_harness.c driverbin.c
+OBJS = $(addprefix $(OBJDIR)/,$(SOURCES:.c=.o))
+BINARY = $(addprefix $(TESTDIR)/,fuzz_disasm$(BIN_EXT))
+BINARYBIN = $(addprefix $(TESTDIR)/,fuzz_bindisasm$(BIN_EXT))
+
+all: $(BINARY) $(BINARYBIN)
+
+clean:
+	rm -rf fuzz_harness $(OBJS) $(BINARY) $(BINARYBIN) $(OBJDIR)/lib$(LIBNAME).* $(OBJDIR)/$(LIBNAME).*
+
+$(BINARY): fuzz_disasm.o drivermc.o
+	@mkdir -p $(@D)
+ifeq ($(V),0)
+	$(call log,LINK,$(notdir $@))
+	@$(link-static)
+else
+	$(link-static)
+endif
+
+$(BINARYBIN): fuzz_disasm.o driverbin.o
+	@mkdir -p $(@D)
+ifeq ($(V),0)
+	$(call log,LINK,$(notdir $@))
+	@$(link-static)
+else
+	$(link-static)
+endif
+
+$(OBJDIR)/%.o: %.c
+	@mkdir -p $(@D)
+ifeq ($(V),0)
+	$(call log,CC,$(@:$(OBJDIR)/%=%))
+	@$(compile)
+else
+	$(compile)
+endif
+
+
+
+define link-static
+	$(CC) $(LDFLAGS) $^ $(ARCHIVE) -o $@
+endef
+
 fuzz_harness: fuzz_harness.o
 	${CC} $< -O3 -Wall -l$(LIBNAME) -o $@
-
-%.o: %.c
-	${CC} -c -I../../include/capstone $< -o $@
-
-clean:
-	rm -rf *.o fuzz_harness
diff --git a/suite/fuzz/driverbin.c b/suite/fuzz/driverbin.c
new file mode 100644
index 0000000..57eea2c
--- /dev/null
+++ b/suite/fuzz/driverbin.c
@@ -0,0 +1,76 @@
+#include <stdint.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <dirent.h>
+#include <unistd.h>
+
+int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size);
+
+int main(int argc, char** argv)
+{
+    FILE * fp;
+    uint8_t Data[0x1000];
+    size_t Size;
+    DIR *d;
+    struct dirent *dir;
+    int r = 0;
+
+    if (argc != 2) {
+        return 1;
+    }
+
+    d = opendir(argv[1]);
+    if (d == NULL) {
+        printf("Invalid directory\n");
+        return 2;
+    }
+    if (chdir(argv[1]) != 0) {
+        closedir(d);
+        printf("Invalid directory\n");
+        return 2;
+    }
+
+    while((dir = readdir(d)) != NULL) {
+        //opens the file, get its size, and reads it into a buffer
+        if (dir->d_type != DT_REG) {
+            continue;
+        }
+        //printf("Running %s\n", dir->d_name);
+        fp = fopen(dir->d_name, "rb");
+        if (fp == NULL) {
+            r = 3;
+            break;
+        }
+        if (fseek(fp, 0L, SEEK_END) != 0) {
+            fclose(fp);
+            r = 4;
+            break;
+        }
+        Size = ftell(fp);
+        if (Size == (size_t) -1) {
+            fclose(fp);
+            r = 5;
+            break;
+        } else if (Size > 0x1000) {
+            fclose(fp);
+            continue;
+        }
+        if (fseek(fp, 0L, SEEK_SET) != 0) {
+            fclose(fp);
+            r = 7;
+            break;
+        }
+        if (fread(Data, Size, 1, fp) != 1) {
+            fclose(fp);
+            r = 8;
+            break;
+        }
+
+        //lauch fuzzer
+        LLVMFuzzerTestOneInput(Data, Size);
+        fclose(fp);
+    }
+    closedir(d);
+    return r;
+}
+
diff --git a/suite/fuzz/drivermc.c b/suite/fuzz/drivermc.c
new file mode 100644
index 0000000..a6a0163
--- /dev/null
+++ b/suite/fuzz/drivermc.c
@@ -0,0 +1,130 @@
+#include <stdint.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size);
+
+#define MAX_INSTR_SIZE 64
+#define MAX_LINE_SIZE 128
+
+int main(int argc, char** argv)
+{
+    FILE * fp;
+    uint8_t Data[MAX_INSTR_SIZE];
+    char line[MAX_LINE_SIZE];
+    size_t Size;
+    char arch[MAX_LINE_SIZE];
+    char mode[MAX_LINE_SIZE];
+    unsigned int value;
+    int i;
+
+    if (argc < 2) {
+        return 1;
+    }
+    for (i = 1; i < argc; i++) {
+        //opens the file, get its size, and reads it into a buffer
+        fp = fopen(argv[i], "rb");
+        if (fp == NULL) {
+            return 2;
+        }
+        printf("Trying %s\n", argv[i]);
+        if (fgets(line, MAX_LINE_SIZE, fp) == NULL) {
+            break;
+        }
+        if (line[0] == '#') {
+            if (sscanf(line, "# %[^,], %[^,]", arch, mode) != 2) {
+                printf("Wrong mode %s\n", line);
+                return 1;
+            }
+            if (strcmp(arch, "CS_ARCH_X86") == 0 && strcmp(mode, "CS_MODE_32") == 0) {
+                Data[0] = 0;
+            } else if (strcmp(arch, "CS_ARCH_X86") == 0 && strcmp(mode, "CS_MODE_64") == 0) {
+                Data[0] = 1;
+            } else if (strcmp(arch, "CS_ARCH_ARM") == 0 && strcmp(mode, "CS_MODE_ARM") == 0) {
+                Data[0] = 2;
+            } else if (strcmp(arch, "CS_ARCH_ARM") == 0 && strcmp(mode, "CS_MODE_THUMB") == 0) {
+                Data[0] = 3;
+            } else if (strcmp(arch, "CS_ARCH_ARM") == 0 && strcmp(mode, "CS_MODE_ARM+CS_MODE_V8") == 0) {
+                Data[0] = 4;
+            } else if (strcmp(arch, "CS_ARCH_ARM") == 0 && strcmp(mode, "CS_MODE_THUMB+CS_MODE_V8") == 0) {
+                Data[0] = 5;
+            } else if (strcmp(arch, "CS_ARCH_ARM") == 0 && strcmp(mode, "CS_MODE_THUMB+CS_MODE_MCLASS") == 0) {
+                Data[0] = 6;
+            } else if (strcmp(arch, "CS_ARCH_ARM64") == 0 && strcmp(mode, "0") == 0) {
+                Data[0] = 7;
+            } else if (strcmp(arch, "CS_ARCH_MIPS") == 0 && strcmp(mode, "CS_MODE_MIPS32+CS_MODE_BIG_ENDIAN") == 0) {
+                Data[0] = 8;
+            } else if (strcmp(arch, "CS_ARCH_MIPS") == 0 && strcmp(mode, "CS_MODE_MIPS32+CS_MODE_MICRO") == 0) {
+                Data[0] = 9;
+            } else if (strcmp(arch, "CS_ARCH_MIPS") == 0 && strcmp(mode, "CS_MODE_MIPS64") == 0) {
+                Data[0] = 10;
+            } else if (strcmp(arch, "CS_ARCH_MIPS") == 0 && strcmp(mode, "CS_MODE_MIPS32") == 0) {
+                Data[0] = 11;
+            } else if (strcmp(arch, "CS_ARCH_MIPS") == 0 && strcmp(mode, "CS_MODE_MIPS64+CS_MODE_BIG_ENDIAN") == 0) {
+                Data[0] = 12;
+            } else if (strcmp(arch, "CS_ARCH_MIPS") == 0 && strcmp(mode, "CS_MODE_MIPS32+CS_MODE_MICRO+CS_MODE_BIG_ENDIAN") == 0) {
+                Data[0] = 13;
+            } else if (strcmp(arch, "CS_ARCH_MIPS") == 0 && strcmp(mode, "CS_MODE_MIPS32+CS_MODE_BIG_ENDIAN+CS_MODE_MICRO") == 0) {
+                Data[0] = 13;
+            } else if (strcmp(arch, "CS_ARCH_PPC") == 0 && strcmp(mode, "CS_MODE_BIG_ENDIAN") == 0) {
+                Data[0] = 14;
+            } else if (strcmp(arch, "CS_ARCH_SPARC") == 0 && strcmp(mode, "CS_MODE_BIG_ENDIAN") == 0) {
+                Data[0] = 15;
+            } else if (strcmp(arch, "CS_ARCH_SPARC") == 0 && strcmp(mode, "CS_MODE_BIG_ENDIAN + CS_MODE_V9") == 0) {
+                Data[0] = 16;
+            } else if (strcmp(arch, "CS_ARCH_SYSZ") == 0 && strcmp(mode, "0") == 0) {
+                Data[0] = 17;
+            } else if (strcmp(arch, "CS_ARCH_XCORE") == 0 && strcmp(mode, "0") == 0) {
+                Data[0] = 18;
+            } else if (strcmp(arch, "CS_ARCH_MIPS") == 0 && strcmp(mode, "CS_MODE_MIPS32R6+CS_MODE_BIG_ENDIAN") == 0) {
+                Data[0] = 19;
+            } else if (strcmp(arch, "CS_ARCH_MIPS") == 0 && strcmp(mode, "CS_MODE_MIPS32R6+CS_MODE_MICRO+CS_MODE_BIG_ENDIAN") == 0) {
+                Data[0] = 20;
+            } else if (strcmp(arch, "CS_ARCH_MIPS") == 0 && strcmp(mode, "CS_MODE_MIPS32R6") == 0) {
+                Data[0] = 21;
+            } else if (strcmp(arch, "CS_ARCH_MIPS") == 0 && strcmp(mode, "CS_MODE_MIPS32R6+CS_MODE_MICRO") == 0) {
+                Data[0] = 22;
+            } else if (strcmp(arch, "CS_ARCH_M68K") == 0 && strcmp(mode, "0") == 0) {
+                Data[0] = 23;
+            } else if (strcmp(arch, "CS_ARCH_M680X") == 0 && strcmp(mode, "CS_MODE_M680X_6809") == 0) {
+                Data[0] = 24;
+            } else if (strcmp(arch, "CS_ARCH_EVM") == 0 && strcmp(mode, "0") == 0) {
+                Data[0] = 25;
+            } else {
+                printf("Unknown mode\n");
+                //fail instead of continue
+                return 1;
+            }
+        } else {
+            printf("No mode\n");
+            //fail instead of continue
+            return 1;
+        }
+
+        while(1) {
+            if (fgets(line, MAX_LINE_SIZE, fp) == NULL) {
+                break;
+            }
+            Size = 1;
+            // we start line at offset 0 and Data buffer at offset 1
+            // since Data[0] is option : arch + mode
+            while (sscanf(line+(Size-1)*5, "0x%02x", &value) == 1) {
+                Data[Size] = value;
+                Size++;
+                if (line[(Size-1)*5-1] != ',') {
+                    //end of pattern
+                    break;
+                } else if (MAX_LINE_SIZE < (Size-1)*5) {
+                    printf("Line overflow\n");
+                    return 1;
+                }
+            }
+            //lauch fuzzer
+            LLVMFuzzerTestOneInput(Data, Size);
+        }
+        fclose(fp);
+    }
+    return 0;
+}
+
diff --git a/suite/fuzz/fuzz_diff.c b/suite/fuzz/fuzz_diff.c
new file mode 100644
index 0000000..f0f39fd
--- /dev/null
+++ b/suite/fuzz/fuzz_diff.c
@@ -0,0 +1,237 @@
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <inttypes.h>
+#include <assert.h>
+
+#include <capstone/capstone.h>
+
+
+struct platform {
+    cs_arch arch;
+    cs_mode mode;
+    char *comment;
+};
+
+FILE * outfile = NULL;
+
+struct platform platforms[] = {
+    {
+        // item 0
+        CS_ARCH_X86,
+        CS_MODE_32,
+        "X86 32 (Intel syntax)"
+    },
+    {
+        // item 1
+        CS_ARCH_X86,
+        CS_MODE_64,
+        "X86 64 (Intel syntax)"
+    },
+    {
+        // item 2
+        CS_ARCH_ARM,
+        CS_MODE_ARM,
+        "ARM"
+    },
+    {
+        // item 3
+        CS_ARCH_ARM,
+        CS_MODE_THUMB,
+        "THUMB"
+    },
+    {
+        // item 4
+        CS_ARCH_ARM,
+        (cs_mode)(CS_MODE_ARM + CS_MODE_V8),
+        "Arm-V8"
+    },
+    {
+        // item 5
+        CS_ARCH_ARM,
+        (cs_mode)(CS_MODE_THUMB+CS_MODE_V8),
+        "THUMB+V8"
+    },
+    {
+        // item 6
+        CS_ARCH_ARM,
+        (cs_mode)(CS_MODE_THUMB + CS_MODE_MCLASS),
+        "Thumb-MClass"
+    },
+    {
+        // item 7
+        CS_ARCH_ARM64,
+        (cs_mode)0,
+        "ARM-64"
+    },
+    {
+        // item 8
+        CS_ARCH_MIPS,
+        (cs_mode)(CS_MODE_MIPS32 + CS_MODE_BIG_ENDIAN),
+        "MIPS-32 (Big-endian)"
+    },
+    {
+        // item 9
+        CS_ARCH_MIPS,
+        (cs_mode)(CS_MODE_MIPS32 + CS_MODE_MICRO),
+        "MIPS-32 (micro)"
+    },
+    {
+        //item 10
+        CS_ARCH_MIPS,
+        CS_MODE_MIPS64,
+        "MIPS-64-EL (Little-endian)"
+    },
+    {
+        //item 11
+        CS_ARCH_MIPS,
+        CS_MODE_MIPS32,
+        "MIPS-32-EL (Little-endian)"
+    },
+    {
+        //item 12
+        CS_ARCH_MIPS,
+        (cs_mode)(CS_MODE_MIPS64 + CS_MODE_BIG_ENDIAN),
+        "MIPS-64 (Big-endian)"
+    },
+    {
+        //item 13
+        CS_ARCH_MIPS,
+        (cs_mode)(CS_MODE_MIPS32 + CS_MODE_MICRO + CS_MODE_BIG_ENDIAN),
+        "MIPS-32 | Micro (Big-endian)"
+    },
+    {
+        //item 14
+        CS_ARCH_PPC,
+        CS_MODE_BIG_ENDIAN,
+        "PPC-64"
+    },
+    {
+        //item 15
+        CS_ARCH_SPARC,
+        CS_MODE_BIG_ENDIAN,
+        "Sparc"
+    },
+    {
+        //item 16
+        CS_ARCH_SPARC,
+        (cs_mode)(CS_MODE_BIG_ENDIAN + CS_MODE_V9),
+        "SparcV9"
+    },
+    {
+        //item 17
+        CS_ARCH_SYSZ,
+        (cs_mode)0,
+        "SystemZ"
+    },
+    {
+        //item 18
+        CS_ARCH_XCORE,
+        (cs_mode)0,
+        "XCore"
+    },
+    {
+        //item 19
+        CS_ARCH_MIPS,
+        (cs_mode)(CS_MODE_MIPS32R6 + CS_MODE_BIG_ENDIAN),
+        "MIPS-32R6 (Big-endian)"
+    },
+    {
+        //item 20
+        CS_ARCH_MIPS,
+        (cs_mode)(CS_MODE_MIPS32R6 + CS_MODE_MICRO + CS_MODE_BIG_ENDIAN),
+        "MIPS-32R6 (Micro+Big-endian)"
+    },
+    {
+        //item 21
+        CS_ARCH_MIPS,
+        CS_MODE_MIPS32R6,
+        "MIPS-32R6 (Little-endian)"
+    },
+    {
+        //item 22
+        CS_ARCH_MIPS,
+        (cs_mode)(CS_MODE_MIPS32R6 + CS_MODE_MICRO),
+        "MIPS-32R6 (Micro+Little-endian)"
+    },
+    {
+        //item 23
+        CS_ARCH_M68K,
+        (cs_mode)0,
+        "M68K"
+    },
+    {
+        //item 24
+        CS_ARCH_M680X,
+        (cs_mode)CS_MODE_M680X_6809,
+        "M680X_M6809"
+    },
+    {
+        //item 25
+        CS_ARCH_EVM,
+        (cs_mode)0,
+        "EVM"
+    },
+};
+
+void LLVMFuzzerInit();
+int LLVMFuzzerReturnOneInput(const uint8_t *Data, size_t Size, char * AssemblyText);
+
+int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) {
+    csh handle;
+    cs_insn *insn;
+    cs_err err;
+    const uint8_t **Datap = &Data;
+    size_t * Sizep = &Size;
+    uint64_t address = 0x1000;
+    char LLVMAssemblyText[80];
+    char CapstoneAssemblyText[80];
+
+    if (Size < 1) {
+        // 1 byte for arch choice
+        return 0;
+    } else if (Size > 0x1000) {
+        //limit input to 4kb
+        Size = 0x1000;
+    }
+    if (outfile == NULL) {
+        // we compute the output
+        outfile = fopen("/dev/null", "w");
+        if (outfile == NULL) {
+            return 0;
+        }
+        LLVMFuzzerInit();
+    }
+
+    if (Data[0] >= sizeof(platforms)/sizeof(platforms[0])) {
+        return 0;
+    }
+
+    if (LLVMFuzzerReturnOneInput(Data, Size, LLVMAssemblyText) == 1) {
+        return 0;
+    }
+
+    err = cs_open(platforms[Data[0]].arch, platforms[Data[0]].mode, &handle);
+    if (err) {
+        return 0;
+    }
+
+    insn = cs_malloc(handle);
+    Data++;
+    Size--;
+    assert(insn);
+        if (cs_disasm_iter(handle, Datap, Sizep, &address, insn)) {
+            snprintf(CapstoneAssemblyText, 80, "\t%s\t%s", insn->mnemonic, insn->op_str);
+            if (strcmp(CapstoneAssemblyText, LLVMAssemblyText) != 0) {
+                printf("capstone %s != llvm %s", CapstoneAssemblyText, LLVMAssemblyText);
+                abort();
+            }
+        } else {
+            printf("capstone failed with llvm %s", LLVMAssemblyText);
+            abort();
+        }
+    cs_free(insn, 1);
+    cs_close(&handle);
+
+    return 0;
+}
diff --git a/suite/fuzz/fuzz_llvm.cpp b/suite/fuzz/fuzz_llvm.cpp
new file mode 100644
index 0000000..7e713cb
--- /dev/null
+++ b/suite/fuzz/fuzz_llvm.cpp
@@ -0,0 +1,41 @@
+#include "llvm-c/Disassembler.h"
+#include "llvm-c/Target.h"
+#include "llvm/MC/SubtargetFeature.h"
+#include "llvm/Support/CommandLine.h"
+#include "llvm/Support/raw_ostream.h"
+
+using namespace llvm;
+
+extern "C" void LLVMFuzzerInit() {
+    LLVMInitializeAllTargetInfos();
+    LLVMInitializeAllTargetMCs();
+    LLVMInitializeAllDisassemblers();
+}
+
+
+extern "C" int LLVMFuzzerReturnOneInput(const uint8_t *Data, size_t Size, char * AssemblyText) {
+    LLVMDisasmContextRef Ctx;
+    std::vector<uint8_t> DataCopy(Data, Data + Size);
+    uint8_t *p = DataCopy.data();
+    int r = 1;
+
+    switch(Data[0]) {
+        case 0:
+            Ctx = LLVMCreateDisasmCPUFeatures("i386", "", "", nullptr, 0, nullptr, nullptr);
+            if (LLVMSetDisasmOptions(Ctx, LLVMDisassembler_Option_AsmPrinterVariant) == 0) {
+                abort();
+            }
+            break;
+            //TODO other cases
+        default:
+            return 1;
+    }
+    assert(Ctx);
+
+    if (LLVMDisasmInstruction(Ctx, p+1, Size-1, 0, AssemblyText, 80) > 0) {
+        r = 0;
+    }
+    LLVMDisasmDispose(Ctx);
+
+    return r;
+}