diff --git a/.gitignore b/.gitignore
index 1d328b0922..e9f057cbd0 100644
--- a/.gitignore
+++ b/.gitignore
@@ -124,3 +124,6 @@ capstone_get_setup
*.s
cstool/cstool
+
+# android
+android-ndk-*
diff --git a/.travis.yml b/.travis.yml
index a3e0733a7a..65a32951a9 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -8,6 +8,7 @@ before_script:
# TODO remove built in cmocka compile and use system cmocka (including brewfile) once xenial is default
- git clone https://git.cryptomilk.org/projects/cmocka.git suite/cstest/cmocka
- chmod +x suite/cstest/build_cstest.sh
+ - if [[ ${TRAVIS_OS_NAME} = linux ]]; then export PATH="/usr/lib/llvm-9/bin:${PATH}"; fi
script:
- ./make.sh
- make check
@@ -18,6 +19,7 @@ script:
- if [[ "$NOPYTEST" != "true" ]]; then cd suite/cstest && ./build_cstest.sh; fi
- if [[ "$NOPYTEST" != "true" ]]; then python cstest_report.py -D -t build/cstest -d ../MC; fi
- if [[ "$NOPYTEST" != "true" ]]; then python cstest_report.py -D -t build/cstest -f issues.cs; fi
+ - if [ -n "$QA_FUZZIT" ]; then suite/fuzz/fuzzit.sh; fi
compiler:
- clang
- gcc
@@ -43,14 +45,22 @@ matrix:
packages:
- libcmocka-dev
- 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
+ env: ASAN_OPTIONS=detect_leaks=0 CXXFLAGS="-DFUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION -fsanitize=address -fsanitize=fuzzer-no-link" CFLAGS="-DFUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION -fsanitize=address -fsanitize=fuzzer-no-link" LDFLAGS="-fsanitize=address" NOPYTEST=true QA_FUZZIT=asan
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
+ env: CXXFLAGS="-DFUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION -fsanitize=memory -fsanitize=fuzzer-no-link" CFLAGS="-DFUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION -fsanitize=memory -fsanitize=fuzzer-no-link" LDFLAGS="-fsanitize=memory" NOPYTEST=true QA_FUZZIT=msan
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
+ env: CXXFLAGS="-DFUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION -fsanitize=undefined -fsanitize=fuzzer-no-link" CFLAGS="-DFUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION -fsanitize=undefined -fno-sanitize-recover=undefined,integer -fsanitize=fuzzer-no-link" LDFLAGS="-fsanitize=undefined" NOPYTEST=true QA_FUZZIT=ubsan
compiler: clang
os: linux
+
+addons:
+ apt:
+ sources:
+ - llvm-toolchain-trusty
+ - ubuntu-toolchain-r-test
+ packages:
+ - clang-9
diff --git a/Makefile b/Makefile
index ff240cf78d..7a51140aea 100644
--- a/Makefile
+++ b/Makefile
@@ -22,6 +22,11 @@ endif
ifeq ($(CROSS),)
RANLIB ?= ranlib
+else ifeq ($(ANDROID), 1)
+CC = $(CROSS)/../../bin/clang
+AR = $(CROSS)/ar
+RANLIB = $(CROSS)/ranlib
+STRIP = $(CROSS)/strip
else
CC = $(CROSS)gcc
AR = $(CROSS)ar
@@ -406,7 +411,7 @@ else
endif
endif
-$(LIBOBJ): config.mk *.h include/capstone/*.h
+$(LIBOBJ): config.mk
$(LIBOBJ_ARM): $(DEP_ARM)
$(LIBOBJ_ARM64): $(DEP_ARM64)
@@ -444,6 +449,12 @@ else
$(generate-pkgcfg)
endif
+# create a list of auto dependencies
+AUTODEPS:= $(patsubst %.o,%.d, $(LIBOBJ))
+
+# include by auto dependencies
+-include $(AUTODEPS)
+
install: $(PKGCFGF) $(ARCHIVE) $(LIBRARY)
mkdir -p $(LIBDIR)
$(call install-library,$(LIBDIR))
@@ -467,6 +478,8 @@ clean:
rm -f $(LIBOBJ)
rm -f $(BLDIR)/lib$(LIBNAME).* $(BLDIR)/$(LIBNAME).pc
rm -f $(PKGCFGF)
+ rm -f $(AUTODEPS)
+ [ "${ANDROID}" = "1" ] && rm -rf android-ndk-* || true
$(MAKE) -C cstool clean
ifeq (,$(findstring yes,$(CAPSTONE_BUILD_CORE_ONLY)))
diff --git a/README.md b/README.md
index b7fa58cd35..8125789774 100644
--- a/README.md
+++ b/README.md
@@ -5,6 +5,7 @@ Capstone Engine
[](https://ci.appveyor.com/project/aquynh/capstone/branch/next)
[](https://pypi.python.org/pypi/capstone)
[](https://pepy.tech/project/capstone)
+[](https://app.fuzzit.dev/admin/ANOh0D48gSLBxNZcDQMI/dashboard)
Capstone is a disassembly framework with the target of becoming the ultimate
disasm engine for binary analysis and reversing in the security community.
@@ -61,6 +62,12 @@ Hack
See HACK.TXT file for the structure of the source code.
+Fuzz
+----
+
+See suite/fuzz/README.md for more information.
+
+
License
-------
diff --git a/arch/SystemZ/SystemZGenAsmWriter.inc b/arch/SystemZ/SystemZGenAsmWriter.inc
index bdc3a5aa68..149d07f363 100644
--- a/arch/SystemZ/SystemZGenAsmWriter.inc
+++ b/arch/SystemZ/SystemZGenAsmWriter.inc
@@ -10645,6 +10645,7 @@ static void printInstruction(MCInst *MI, SStream *O, MCRegisterInfo *MRI)
// Fragment 0 encoded into 5 bits for 18 unique commands.
+ // printf("Fragment 0 = %" PRIu64 "\n", (Bits >> 14) & 31);
switch ((Bits >> 14) & 31) {
default: // llvm_unreachable("Invalid command number.");
case 0:
@@ -10752,6 +10753,7 @@ static void printInstruction(MCInst *MI, SStream *O, MCRegisterInfo *MRI)
// Fragment 1 encoded into 5 bits for 17 unique commands.
+ // printf("Fragment 1 = %" PRIu64 "\n", (Bits >> 19) & 31);
switch ((Bits >> 19) & 31) {
default: // llvm_unreachable("Invalid command number.");
case 0:
@@ -10845,6 +10847,7 @@ static void printInstruction(MCInst *MI, SStream *O, MCRegisterInfo *MRI)
// Fragment 2 encoded into 6 bits for 34 unique commands.
+ // printf("Fragment 2 = %" PRIu64 "\n", (Bits >> 24) & 63);
switch ((Bits >> 24) & 63) {
default: // llvm_unreachable("Invalid command number.");
case 0:
@@ -11011,6 +11014,7 @@ static void printInstruction(MCInst *MI, SStream *O, MCRegisterInfo *MRI)
// Fragment 3 encoded into 5 bits for 20 unique commands.
+ // printf("Fragment 3 = %" PRIu64 "\n", (Bits >> 30) & 31);
switch ((Bits >> 30) & 31) {
default: // llvm_unreachable("Invalid command number.");
case 0:
@@ -11116,6 +11120,7 @@ static void printInstruction(MCInst *MI, SStream *O, MCRegisterInfo *MRI)
// Fragment 4 encoded into 6 bits for 33 unique commands.
+ // printf("Fragment 4 = %" PRIu64 "\n", (Bits >> 35) & 63);
switch ((Bits >> 35) & 63) {
default: // llvm_unreachable("Invalid command number.");
case 0:
@@ -11277,6 +11282,7 @@ static void printInstruction(MCInst *MI, SStream *O, MCRegisterInfo *MRI)
// Fragment 5 encoded into 4 bits for 9 unique commands.
+ // printf("Fragment 5 = %" PRIu64 "\n", (Bits >> 41) & 15);
switch ((Bits >> 41) & 15) {
default: // llvm_unreachable("Invalid command number.");
case 0:
@@ -11329,6 +11335,7 @@ static void printInstruction(MCInst *MI, SStream *O, MCRegisterInfo *MRI)
// Fragment 6 encoded into 4 bits for 11 unique commands.
+ // printf("Fragment 6 = %" PRIu64 "\n", (Bits >> 45) & 15);
switch ((Bits >> 45) & 15) {
default: // llvm_unreachable("Invalid command number.");
case 0:
@@ -11386,6 +11393,7 @@ static void printInstruction(MCInst *MI, SStream *O, MCRegisterInfo *MRI)
// Fragment 7 encoded into 1 bits for 2 unique commands.
+ // printf("Fragment 7 = %" PRIu64 "\n", (Bits >> 49) & 1);
if ((Bits >> 49) & 1) {
// RISBG, RISBG32, RISBGN, RISBHG, RISBLG, RNSBG, ROSBG, RXSBG, VAC, VACC...
SStream_concat0(O, ", ");
@@ -11396,6 +11404,7 @@ static void printInstruction(MCInst *MI, SStream *O, MCRegisterInfo *MRI)
// Fragment 8 encoded into 2 bits for 3 unique commands.
+ // printf("Fragment 8 = %" PRIu64 "\n", (Bits >> 50) & 3);
switch ((Bits >> 50) & 3) {
default: // llvm_unreachable("Invalid command number.");
case 0:
@@ -11416,6 +11425,7 @@ static void printInstruction(MCInst *MI, SStream *O, MCRegisterInfo *MRI)
// Fragment 9 encoded into 1 bits for 2 unique commands.
+ // printf("Fragment 9 = %" PRIu64 "\n", (Bits >> 52) & 1);
if ((Bits >> 52) & 1) {
// VFCE, VFCH, VFCHE, VFMA, VFMAX, VFMIN, VFMS, VFNMA, VFNMS, VMSL, VSTRC
SStream_concat0(O, ", ");
diff --git a/arch/SystemZ/SystemZInstPrinter.c b/arch/SystemZ/SystemZInstPrinter.c
index ee6061614e..b1f1c3360b 100644
--- a/arch/SystemZ/SystemZInstPrinter.c
+++ b/arch/SystemZ/SystemZInstPrinter.c
@@ -297,16 +297,15 @@ static void printU48ImmOperand(MCInst *MI, int OpNum, SStream *O)
static void printPCRelOperand(MCInst *MI, int OpNum, SStream *O)
{
MCOperand *MO = MCInst_getOperand(MI, OpNum);
- int32_t imm;
if (MCOperand_isImm(MO)) {
- imm = (int32_t)MCOperand_getImm(MO);
+ int64_t imm = (int64_t)MCOperand_getImm(MO);
- printInt32(O, imm);
+ printInt64(O, imm);
if (MI->csh->detail) {
MI->flat_insn->detail->sysz.operands[MI->flat_insn->detail->sysz.op_count].type = SYSZ_OP_IMM;
- MI->flat_insn->detail->sysz.operands[MI->flat_insn->detail->sysz.op_count].imm = (int64_t)imm;
+ MI->flat_insn->detail->sysz.operands[MI->flat_insn->detail->sysz.op_count].imm = imm;
MI->flat_insn->detail->sysz.op_count++;
}
}
diff --git a/arch/X86/X86MappingInsnOp.inc b/arch/X86/X86MappingInsnOp.inc
index 1681e0717c..909a98dd61 100644
--- a/arch/X86/X86MappingInsnOp.inc
+++ b/arch/X86/X86MappingInsnOp.inc
@@ -7415,7 +7415,7 @@
{ /* X86_MOVBE16mr, X86_INS_MOVBE: movbe */
0,
- { CS_AC_READ, CS_AC_READ, 0 }
+ { CS_AC_WRITE, CS_AC_READ, 0 }
},
{ /* X86_MOVBE16rm, X86_INS_MOVBE: movbe */
@@ -7425,7 +7425,7 @@
{ /* X86_MOVBE32mr, X86_INS_MOVBE: movbe */
0,
- { CS_AC_READ, CS_AC_READ, 0 }
+ { CS_AC_WRITE, CS_AC_READ, 0 }
},
{ /* X86_MOVBE32rm, X86_INS_MOVBE: movbe */
@@ -7435,7 +7435,7 @@
{ /* X86_MOVBE64mr, X86_INS_MOVBE: movbe */
0,
- { CS_AC_READ, CS_AC_READ, 0 }
+ { CS_AC_WRITE, CS_AC_READ, 0 }
},
{ /* X86_MOVBE64rm, X86_INS_MOVBE: movbe */
diff --git a/arch/X86/X86MappingInsnOp_reduce.inc b/arch/X86/X86MappingInsnOp_reduce.inc
index 5fb4a3d6b7..c7e158e375 100644
--- a/arch/X86/X86MappingInsnOp_reduce.inc
+++ b/arch/X86/X86MappingInsnOp_reduce.inc
@@ -3720,7 +3720,7 @@
{ /* X86_MOVBE16mr, X86_INS_MOVBE: movbe */
0,
- { CS_AC_READ, CS_AC_READ, 0 }
+ { CS_AC_WRITE, CS_AC_READ, 0 }
},
{ /* X86_MOVBE16rm, X86_INS_MOVBE: movbe */
@@ -3730,7 +3730,7 @@
{ /* X86_MOVBE32mr, X86_INS_MOVBE: movbe */
0,
- { CS_AC_READ, CS_AC_READ, 0 }
+ { CS_AC_WRITE, CS_AC_READ, 0 }
},
{ /* X86_MOVBE32rm, X86_INS_MOVBE: movbe */
@@ -3740,7 +3740,7 @@
{ /* X86_MOVBE64mr, X86_INS_MOVBE: movbe */
0,
- { CS_AC_READ, CS_AC_READ, 0 }
+ { CS_AC_WRITE, CS_AC_READ, 0 }
},
{ /* X86_MOVBE64rm, X86_INS_MOVBE: movbe */
diff --git a/bindings/README b/bindings/README
index c0ee8f5d61..8605806259 100644
--- a/bindings/README
+++ b/bindings/README
@@ -3,9 +3,9 @@ See /README for how to compile & install each binding.
More bindings created & maintained by the community are available as followings.
-- Gapstone: Go binding (by Ben Nagy).
+- Gapstone: Go binding (by Scott Knight).
- https://github.com/bnagy/gapstone
+ https://github.com/knightsc/gapstone
- Crabstone: Ruby binding (by Ben Nagy).
diff --git a/bindings/java/capstone/Capstone.java b/bindings/java/capstone/Capstone.java
index 2d59997ff4..040c79e2b4 100644
--- a/bindings/java/capstone/Capstone.java
+++ b/bindings/java/capstone/Capstone.java
@@ -96,7 +96,7 @@ public List getFieldOrder() {
}
public static class CsInsn {
- private NativeLong csh;
+ private Pointer csh;
private CS cs;
private _cs_insn raw;
private int arch;
@@ -121,7 +121,7 @@ public static class CsInsn {
public byte[] groups;
public OpInfo operands;
- public CsInsn (_cs_insn insn, int _arch, NativeLong _csh, CS _cs, boolean diet) {
+ public CsInsn (_cs_insn insn, int _arch, Pointer _csh, CS _cs, boolean diet) {
id = insn.id;
address = insn.address;
size = insn.size;
@@ -294,31 +294,31 @@ private CsInsn[] fromArrayRaw(_cs_insn[] arr_raw) {
}
private interface CS extends Library {
- public int cs_open(int arch, int mode, NativeLongByReference handle);
- public NativeLong cs_disasm(NativeLong handle, byte[] code, NativeLong code_len,
+ public int cs_open(int arch, int mode, PointerByReference handle);
+ public NativeLong cs_disasm(Pointer handle, byte[] code, NativeLong code_len,
long addr, NativeLong count, PointerByReference insn);
public void cs_free(Pointer p, NativeLong count);
- public int cs_close(NativeLongByReference handle);
- public int cs_option(NativeLong handle, int option, NativeLong optionValue);
-
- public String cs_reg_name(NativeLong csh, int id);
- public int cs_op_count(NativeLong csh, Pointer insn, int type);
- public int cs_op_index(NativeLong csh, Pointer insn, int type, int index);
-
- public String cs_insn_name(NativeLong csh, int id);
- public String cs_group_name(NativeLong csh, int id);
- public byte cs_insn_group(NativeLong csh, Pointer insn, int id);
- public byte cs_reg_read(NativeLong csh, Pointer insn, int id);
- public byte cs_reg_write(NativeLong csh, Pointer insn, int id);
- public int cs_errno(NativeLong csh);
+ public int cs_close(PointerByReference handle);
+ public int cs_option(Pointer handle, int option, NativeLong optionValue);
+
+ public String cs_reg_name(Pointer csh, int id);
+ public int cs_op_count(Pointer csh, Pointer insn, int type);
+ public int cs_op_index(Pointer csh, Pointer insn, int type, int index);
+
+ public String cs_insn_name(Pointer csh, int id);
+ public String cs_group_name(Pointer csh, int id);
+ public byte cs_insn_group(Pointer csh, Pointer insn, int id);
+ public byte cs_reg_read(Pointer csh, Pointer insn, int id);
+ public byte cs_reg_write(Pointer csh, Pointer insn, int id);
+ public int cs_errno(Pointer csh);
public int cs_version(IntByReference major, IntByReference minor);
public boolean cs_support(int query);
public String cs_strerror(int code);
- public int cs_regs_access(NativeLong handle, Pointer insn, Pointer regs_read, ByteByReference regs_read_count, Pointer regs_write, ByteByReference regs_write_count);
+ public int cs_regs_access(Pointer handle, Pointer insn, Pointer regs_read, ByteByReference regs_read_count, Pointer regs_write, ByteByReference regs_write_count);
}
// Capstone API version
- public static final int CS_API_MAJOR = 4;
+ public static final int CS_API_MAJOR = 5;
public static final int CS_API_MINOR = 0;
// architectures
@@ -420,8 +420,8 @@ public NativeLong cs_disasm(NativeLong handle, byte[] code, NativeLong code_len,
public static final int CS_SUPPORT_X86_REDUCE = CS_ARCH_ALL+2; // X86 reduce mode
protected class NativeStruct {
- private NativeLong csh;
- private NativeLongByReference handleRef;
+ private Pointer csh;
+ private PointerByReference handleRef;
}
private static final CsInsn[] EMPTY_INSN = new CsInsn[0];
@@ -436,15 +436,17 @@ protected class NativeStruct {
public Capstone(int arch, int mode) {
cs = (CS)Native.loadLibrary("capstone", CS.class);
- int version = cs.cs_version(null, null);
- if (version != (CS_API_MAJOR << 8) + CS_API_MINOR) {
- throw new RuntimeException("Different API version between core & binding (CS_ERR_VERSION)");
+ int coreVersion = cs.cs_version(null, null);
+ int bindingVersion = (CS_API_MAJOR << 8) + CS_API_MINOR;
+ if (coreVersion != bindingVersion) {
+ throw new RuntimeException("Different API version between core " + coreVersion +
+ " & binding " + bindingVersion + " (CS_ERR_VERSION)");
}
this.arch = arch;
this.mode = mode;
ns = new NativeStruct();
- ns.handleRef = new NativeLongByReference();
+ ns.handleRef = new PointerByReference();
if (cs.cs_open(arch, mode, ns.handleRef) != CS_ERR_OK) {
throw new RuntimeException("ERROR: Wrong arch or mode");
}
diff --git a/bindings/ocaml/ocaml.c b/bindings/ocaml/ocaml.c
index c74d5e60d9..8043d231d4 100644
--- a/bindings/ocaml/ocaml.c
+++ b/bindings/ocaml/ocaml.c
@@ -368,15 +368,15 @@ CAMLprim value _cs_disasm(cs_arch arch, csh handle, const uint8_t * code, size_t
for (i = 0; i < lcount; i++) {
switch(insn[j-1].detail->x86.operands[i].type) {
case X86_OP_REG:
- tmp = caml_alloc(5, 1);
+ tmp = caml_alloc(1, 1);
Store_field(tmp, 0, Val_int(insn[j-1].detail->x86.operands[i].reg));
break;
case X86_OP_IMM:
- tmp = caml_alloc(5, 2);
+ tmp = caml_alloc(1, 2);
Store_field(tmp, 0, Val_int(insn[j-1].detail->x86.operands[i].imm));
break;
case X86_OP_MEM:
- tmp = caml_alloc(5, 3);
+ tmp = caml_alloc(1, 3);
tmp2 = caml_alloc(5, 0);
Store_field(tmp2, 0, Val_int(insn[j-1].detail->x86.operands[i].mem.segment));
Store_field(tmp2, 1, Val_int(insn[j-1].detail->x86.operands[i].mem.base));
@@ -387,14 +387,16 @@ CAMLprim value _cs_disasm(cs_arch arch, csh handle, const uint8_t * code, size_t
Store_field(tmp, 0, tmp2);
break;
default:
+ tmp = caml_alloc(1, 0); // X86_OP_INVALID
break;
}
- Store_field(tmp, 1, Val_int(insn[j-1].detail->x86.operands[i].size));
- Store_field(tmp, 2, Val_int(insn[j-1].detail->x86.operands[i].access));
- Store_field(tmp, 3, Val_int(insn[j-1].detail->x86.operands[i].avx_bcast));
- Store_field(tmp, 4, Val_int(insn[j-1].detail->x86.operands[i].avx_zero_opmask));
- tmp2 = caml_alloc(1, 0);
+
+ tmp2 = caml_alloc(5, 0);
Store_field(tmp2, 0, tmp);
+ Store_field(tmp2, 1, Val_int(insn[j-1].detail->x86.operands[i].size));
+ Store_field(tmp2, 2, Val_int(insn[j-1].detail->x86.operands[i].access));
+ Store_field(tmp2, 3, Val_int(insn[j-1].detail->x86.operands[i].avx_bcast));
+ Store_field(tmp2, 4, Val_int(insn[j-1].detail->x86.operands[i].avx_zero_opmask));
Store_field(array, i, tmp2);
}
} else // empty array
diff --git a/bindings/ocaml/test_x86.ml b/bindings/ocaml/test_x86.ml
index ce343e49ee..d35bf0f01b 100644
--- a/bindings/ocaml/test_x86.ml
+++ b/bindings/ocaml/test_x86.ml
@@ -30,9 +30,9 @@ let all_tests = [
let print_op handle i op =
( match op.value with
| X86_OP_INVALID _ -> (); (* this would never happens *)
- | X86_OP_REG reg -> printf "\t\top[%d]: REG = %s\n" i (cs_reg_name handle reg);
- | X86_OP_IMM imm -> printf "\t\top[%d]: IMM = 0x%x\n" i imm;
- | X86_OP_MEM mem -> ( printf "\t\top[%d]: MEM\n" i;
+ | X86_OP_REG reg -> printf "\t\top[%d]: REG = %s [sz=%d]\n" i (cs_reg_name handle reg) op.size;
+ | X86_OP_IMM imm -> printf "\t\top[%d]: IMM = 0x%x [sz=%d]\n" i imm op.size;
+ | X86_OP_MEM mem -> ( printf "\t\top[%d]: MEM [sz=%d]\n" i op.size;
if mem.base != 0 then
printf "\t\t\toperands[%u].mem.base: REG = %s\n" i (cs_reg_name handle mem.base);
if mem.index != 0 then
diff --git a/cs.c b/cs.c
index a4672ba985..6c540bdfb7 100644
--- a/cs.c
+++ b/cs.c
@@ -514,6 +514,23 @@ cs_err CAPSTONE_API cs_close(csh *handle)
return CS_ERR_OK;
}
+// replace str1 in target with str2; target starts with str1
+// output is put into result (which is array of char with size CS_MNEMONIC_SIZE)
+// return 0 on success, -1 on failure
+static int str_replace(char *result, char *target, const char *str1, char *str2)
+{
+ // only perform replacement if the output fits into result
+ if (strlen(target) - strlen(str1) + strlen(str2) < CS_MNEMONIC_SIZE - 1) {
+ // copy str2 to begining of result
+ strcpy(result, str2);
+ // skip str1 - already replaced by str2
+ strcat(result, target + strlen(str1));
+
+ return 0;
+ } else
+ return -1;
+}
+
// fill insn with mnemonic & operands info
static void fill_insn(struct cs_struct *handle, cs_insn *insn, char *buffer, MCInst *mci,
PostPrinter_t postprinter, const uint8_t *code)
@@ -557,9 +574,14 @@ static void fill_insn(struct cs_struct *handle, cs_insn *insn, char *buffer, MCI
struct insn_mnem *tmp = handle->mnem_list;
while(tmp) {
if (tmp->insn.id == insn->id) {
- // found this instruction, so copy its mnemonic
- (void)strncpy(insn->mnemonic, tmp->insn.mnemonic, sizeof(insn->mnemonic) - 1);
- insn->mnemonic[sizeof(insn->mnemonic) - 1] = '\0';
+ char str[CS_MNEMONIC_SIZE];
+
+ if (!str_replace(str, insn->mnemonic, cs_insn_name((csh)handle, insn->id), tmp->insn.mnemonic)) {
+ // copy result to mnemonic
+ (void)strncpy(insn->mnemonic, str, sizeof(insn->mnemonic) - 1);
+ insn->mnemonic[sizeof(insn->mnemonic) - 1] = '\0';
+ }
+
break;
}
tmp = tmp->next;
diff --git a/cstool/Makefile b/cstool/Makefile
index 9b28e43232..f709d3a79c 100644
--- a/cstool/Makefile
+++ b/cstool/Makefile
@@ -37,6 +37,7 @@ endif
clean:
${RM} -rf *.o $(TARGET)
+ ${RM} -f *.d
%.o: %.c
ifeq ($(V), 0)
diff --git a/docs/README b/docs/README
index 15bbeb3cbe..ec7c3aaa91 100644
--- a/docs/README
+++ b/docs/README
@@ -60,3 +60,7 @@ Documentation of Capstone disassembly framework.
* Sample application on how to embed Capstone into Mac OSX Kext (kernel).
https://github.com/aquynh/CapstoneTest
+
+* A Micro Capstone-Engine API Documentation in Chinese
+
+ https://github.com/kabeor/Micro-Capstone-Engine-API-Documentation/blob/master/Micro%20Capstone-Engine%20API%20Documentation.md
diff --git a/functions.mk b/functions.mk
index d946cd34e6..d734ce5d51 100644
--- a/functions.mk
+++ b/functions.mk
@@ -2,6 +2,7 @@
# Common functions used by Makefile & tests/Makefile
define compile
+ @$(CC) -MM -MP -MT $@ -MT $(@:.o=.d) $(CFLAGS) $< > $(@:.o=.d)
${CC} ${CFLAGS} -c $< -o $@
endef
diff --git a/make.sh b/make.sh
index ddc1791cff..6c29abb033 100755
--- a/make.sh
+++ b/make.sh
@@ -13,6 +13,7 @@ build_android() {
echo "ERROR! Please set \$NDK to point at your Android NDK directory."
exit 1
fi
+
HOSTOS=$(uname -s | tr 'LD' 'ld')
HOSTARCH=$(uname -m)
@@ -22,13 +23,11 @@ build_android() {
case "$TARGARCH" in
arm)
[ -n "$APILEVEL" ] || APILEVEL="android-14" # default to ICS
- [ -n "$GCCVER" ] || GCCVER="4.8"
- CROSS=arm-linux-androideabi-
+ CROSS=arm-linux-androideabi
;;
arm64)
[ -n "$APILEVEL" ] || APILEVEL="android-21" # first with arm64
- [ -n "$GCCVER" ] || GCCVER="4.9"
- CROSS=aarch64-linux-android-
+ CROSS=aarch64-linux-android
;;
*)
@@ -37,10 +36,16 @@ build_android() {
;;
esac
- TOOLCHAIN="$NDK/toolchains/$CROSS$GCCVER/prebuilt/$HOSTOS-$HOSTARCH"
- PLATFORM="$NDK/platforms/$APILEVEL/arch-$TARGARCH"
+ STANDALONE=`realpath android-ndk-${TARGARCH}-${APILEVEL}`
+
+ [ -d $STANDALONE ] || {
+ python ${NDK}/build/tools/make_standalone_toolchain.py \
+ --arch ${TARGARCH} \
+ --api ${APILEVEL##*-} \
+ --install-dir ${STANDALONE}
+ }
- CROSS="$TOOLCHAIN/bin/$CROSS" CFLAGS="--sysroot=$PLATFORM" LDFLAGS="--sysroot=$PLATFORM" ${MAKE} $*
+ ANDROID=1 CROSS="${STANDALONE}/${CROSS}/bin" CFLAGS="--sysroot=${STANDALONE}/sysroot" ${MAKE} $*
}
# build iOS lib for all iDevices, or only specific device
diff --git a/suite/fuzz/Makefile b/suite/fuzz/Makefile
index dc45644d23..e0c0ef2b8a 100644
--- a/suite/fuzz/Makefile
+++ b/suite/fuzz/Makefile
@@ -27,6 +27,7 @@ LDFLAGS += -L$(LIBDIR)
CFLAGS += $(foreach arch,$(LIBARCHS),-arch $(arch))
LDFLAGS += $(foreach arch,$(LIBARCHS),-arch $(arch))
+FUZZLDFLAGS =
LIBNAME = capstone
@@ -40,16 +41,21 @@ ARCHIVE = $(LIBDIR)/lib$(LIBNAME).$(AR_EXT)
SOURCES = fuzz_disasm.c drivermc.c fuzz_harness.c driverbin.c platform.c
OBJS = $(addprefix $(OBJDIR)/,$(SOURCES:.c=.o))
-BINARY = $(addprefix $(TESTDIR)/,fuzz_disasm$(BIN_EXT))
-BINARYBIN = $(addprefix $(TESTDIR)/,fuzz_bindisasm$(BIN_EXT))
+# reproducer using MC file as input
+REPRODUCERMC = $(addprefix $(TESTDIR)/,fuzz_disasm$(BIN_EXT))
+# reproducer using raw binary file as input (as produced by fuzzer)
+REPRODUCERBIN = $(addprefix $(TESTDIR)/,fuzz_bindisasm$(BIN_EXT))
+# fuzzer
+FUZZERBIN = $(addprefix $(TESTDIR)/,fuzz_bindisasm2$(BIN_EXT))
PLATFORMDECODE = $(addprefix $(TESTDIR)/,fuzz_decode_platform$(BIN_EXT))
-all: $(BINARY) $(BINARYBIN) $(PLATFORMDECODE)
+all: $(REPRODUCERMC) $(REPRODUCERBIN) $(FUZZERBIN) $(PLATFORMDECODE)
clean:
- rm -rf fuzz_harness $(OBJS) $(PLATFORMDECODE) $(BINARY) $(BINARYBIN) $(OBJDIR)/lib$(LIBNAME).* $(OBJDIR)/$(LIBNAME).*
+ rm -rf fuzz_harness $(OBJS) $(PLATFORMDECODE) $(REPRODUCERMC) $(REPRODUCERBIN) $(FUZZERBIN) $(OBJDIR)/lib$(LIBNAME).* $(OBJDIR)/$(LIBNAME).*
+ rm -f *.d $(OBJDIR)/*.d
-$(BINARY): fuzz_disasm.o drivermc.o platform.o
+$(REPRODUCERMC): fuzz_disasm.o drivermc.o platform.o
@mkdir -p $(@D)
ifeq ($(V),0)
$(call log,LINK,$(notdir $@))
@@ -58,7 +64,7 @@ else
$(link-static)
endif
-$(BINARYBIN): fuzz_disasm.o driverbin.o platform.o
+$(REPRODUCERBIN): fuzz_disasm.o driverbin.o platform.o
@mkdir -p $(@D)
ifeq ($(V),0)
$(call log,LINK,$(notdir $@))
@@ -67,6 +73,17 @@ else
$(link-static)
endif
+$(FUZZERBIN): FUZZLDFLAGS="-fsanitize=fuzzer"
+
+$(FUZZERBIN): fuzz_disasm.o platform.o
+ @mkdir -p $(@D)
+ifeq ($(V),0)
+ $(call log,LINK,$(notdir $@))
+ @$(link-static) || touch $(FUZZERBIN)
+else
+ $(link-static) || touch $(FUZZERBIN)
+endif
+
$(PLATFORMDECODE): fuzz_decode_platform.o platform.o
@mkdir -p $(@D)
ifeq ($(V),0)
@@ -88,7 +105,7 @@ endif
define link-static
- $(CC) $(LDFLAGS) $^ $(ARCHIVE) -o $@
+ $(CC) $(LDFLAGS) $(FUZZLDFLAGS) $^ $(ARCHIVE) -o $@
endef
fuzz_harness: fuzz_harness.o
diff --git a/suite/fuzz/README.md b/suite/fuzz/README.md
new file mode 100644
index 0000000000..27c1c0c36c
--- /dev/null
+++ b/suite/fuzz/README.md
@@ -0,0 +1,34 @@
+Fuzzing
+===============
+
+
+Build the fuzz target
+-------
+
+To build the fuzz target, you can simply run `make` with appropriate flags set :
+```
+ASAN_OPTIONS=detect_leaks=0 CXXFLAGS="-DFUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION -fsanitize=address -fsanitize=fuzzer-no-link" CFLAGS="-DFUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION -fsanitize=address -fsanitize=fuzzer-no-link" LDFLAGS="-fsanitize=address" make
+```
+You can replace `address` with another sanitizer : `memory` or `undefined`
+The fuzz target is then `suite/fuzz/fuzz_bindisasm2`
+
+You can find this in travis configuration `.travis.yml`
+
+Another way is to use oss-fuzz, see https://github.com/google/oss-fuzz/blob/master/projects/capstone/build.sh
+
+Fuzz drivers
+------
+
+There are custom drivers :
+- driverbin.c : prints cstool command before running one input
+- drivermc.c : converts MC test data to raw binary data before running as many inputs as there are lines in a file
+- onefile.c : simple one file driver
+
+For libfuzzer, the preferred main function is now to use linker option `-fsanitize=fuzzer`
+
+Fuzzit integration
+------
+
+Travis will build the fuzz target with the different sanitizers.
+Then, Travis will launch sanity fuzzit jobs as part of continuous integration (for each of the sanitizers)
+The fuzzit target ids are stored in a configuration file fuzzitid.txt and used by fuzzit.sh
diff --git a/suite/fuzz/fuzzit.sh b/suite/fuzz/fuzzit.sh
new file mode 100755
index 0000000000..b962b773e5
--- /dev/null
+++ b/suite/fuzz/fuzzit.sh
@@ -0,0 +1,27 @@
+FUZZIT_API_KEY=f10b19a56d96b29dfdfe459d41b3d82e475e49c737095c74c99d65a032d5c2ab84d44dad510886bc824f101a860b1754
+
+[ -s ./suite/fuzz/fuzz_bindisasm2 ] || exit 0
+
+if [ ${TRAVIS_EVENT_TYPE} -eq 'cron' ]; then
+ FUZZING_TYPE=fuzzing
+else
+ FUZZING_TYPE=sanity
+fi
+if [ "$TRAVIS_PULL_REQUEST" = "false" ]; then
+ FUZZIT_BRANCH="${TRAVIS_BRANCH}"
+else
+ FUZZIT_BRANCH="PR-${TRAVIS_PULL_REQUEST}"
+fi
+
+FUZZIT_ARGS="--type ${FUZZING_TYPE} --branch ${FUZZIT_BRANCH} --revision ${TRAVIS_COMMIT}"
+if [ -n "$UBSAN_OPTIONS" ]; then
+ FUZZIT_ARGS+=" --ubsan_options ${UBSAN_OPTIONS}"
+fi
+wget -O fuzzit https://github.com/fuzzitdev/fuzzit/releases/download/v1.2.5/fuzzit_1.2.5_Linux_x86_64
+chmod +x fuzzit
+./fuzzit auth ${FUZZIT_API_KEY}
+set -x
+grep "$QA_FUZZIT" suite/fuzz/fuzzitid.txt | cut -d" " -f2 | while read i; do
+ ./fuzzit c job ${FUZZIT_ARGS} ${i} ./suite/fuzz/fuzz_bindisasm2
+done
+set +x
diff --git a/suite/fuzz/fuzzitid.txt b/suite/fuzz/fuzzitid.txt
new file mode 100644
index 0000000000..57bbe73ca5
--- /dev/null
+++ b/suite/fuzz/fuzzitid.txt
@@ -0,0 +1,3 @@
+asan A1NqPndmOVrguCNj95LZ
+msan JchjH3j58fOnB8ZXGyWl
+ubsan JqHqVabfDEqitOusrPFx
\ No newline at end of file
diff --git a/suite/synctools/tablegen/PPC/PPCInstrHTM.td b/suite/synctools/tablegen/PPC/PPCInstrHTM.td
index 6c4e212908..f9c4f42bdf 100644
--- a/suite/synctools/tablegen/PPC/PPCInstrHTM.td
+++ b/suite/synctools/tablegen/PPC/PPCInstrHTM.td
@@ -21,55 +21,53 @@ def HTM_get_imm : SDNodeXForm;
let hasSideEffects = 1, usesCustomInserter = 1 in {
-def TCHECK_RET : Pseudo<(outs crrc:$out), (ins), "#TCHECK_RET", []>;
+def TCHECK_RET : Pseudo<(outs gprc:$out), (ins), "#TCHECK_RET", []>;
+def TBEGIN_RET : PPCCustomInserterPseudo<(outs gprc:$out), (ins u1imm:$R), "#TBEGIN_RET", []>;
}
let Predicates = [HasHTM] in {
+let Defs = [CR0] in {
def TBEGIN : XForm_htm0 <31, 654,
- (outs crrc0:$ret), (ins u1imm:$R), "tbegin. $R", IIC_SprMTSPR, []>;
+ (outs), (ins u1imm:$R), "tbegin. $R", IIC_SprMTSPR, []>;
def TEND : XForm_htm1 <31, 686,
- (outs crrc0:$ret), (ins u1imm:$A), "tend. $A", IIC_SprMTSPR, []>;
+ (outs), (ins u1imm:$A), "tend. $A", IIC_SprMTSPR, []>;
def TABORT : XForm_base_r3xo <31, 910,
- (outs crrc0:$ret), (ins gprc:$A), "tabort. $A", IIC_SprMTSPR,
+ (outs), (ins gprc:$A), "tabort. $A", IIC_SprMTSPR,
[]>, isDOT {
let RST = 0;
let B = 0;
}
def TABORTWC : XForm_base_r3xo <31, 782,
- (outs crrc0:$ret), (ins u5imm:$RTS, gprc:$A, gprc:$B),
+ (outs), (ins u5imm:$RTS, gprc:$A, gprc:$B),
"tabortwc. $RTS, $A, $B", IIC_SprMTSPR, []>,
isDOT;
def TABORTWCI : XForm_base_r3xo <31, 846,
- (outs crrc0:$ret), (ins u5imm:$RTS, gprc:$A, u5imm:$B),
+ (outs), (ins u5imm:$RTS, gprc:$A, u5imm:$B),
"tabortwci. $RTS, $A, $B", IIC_SprMTSPR, []>,
isDOT;
def TABORTDC : XForm_base_r3xo <31, 814,
- (outs crrc0:$ret), (ins u5imm:$RTS, gprc:$A, gprc:$B),
+ (outs), (ins u5imm:$RTS, gprc:$A, gprc:$B),
"tabortdc. $RTS, $A, $B", IIC_SprMTSPR, []>,
isDOT;
def TABORTDCI : XForm_base_r3xo <31, 878,
- (outs crrc0:$ret), (ins u5imm:$RTS, gprc:$A, u5imm:$B),
+ (outs), (ins u5imm:$RTS, gprc:$A, u5imm:$B),
"tabortdci. $RTS, $A, $B", IIC_SprMTSPR, []>,
isDOT;
def TSR : XForm_htm2 <31, 750,
- (outs crrc0:$ret), (ins u1imm:$L), "tsr. $L", IIC_SprMTSPR, []>,
+ (outs), (ins u1imm:$L), "tsr. $L", IIC_SprMTSPR, []>,
isDOT;
-def TCHECK : XForm_htm3 <31, 718,
- (outs), (ins crrc:$BF), "tcheck $BF", IIC_SprMTSPR, []>;
-
-
def TRECLAIM : XForm_base_r3xo <31, 942,
- (outs crrc:$ret), (ins gprc:$A), "treclaim. $A",
+ (outs), (ins gprc:$A), "treclaim. $A",
IIC_SprMTSPR, []>,
isDOT {
let RST = 0;
@@ -77,13 +75,17 @@ def TRECLAIM : XForm_base_r3xo <31, 942,
}
def TRECHKPT : XForm_base_r3xo <31, 1006,
- (outs crrc:$ret), (ins), "trechkpt.", IIC_SprMTSPR, []>,
+ (outs), (ins), "trechkpt.", IIC_SprMTSPR, []>,
isDOT {
let RST = 0;
let A = 0;
let B = 0;
}
+}//Defs = [CR0]
+
+def TCHECK : XForm_htm3 <31, 718,
+ (outs crrc:$BF), (ins), "tcheck $BF", IIC_SprMTSPR, []>;
// Builtins
// All HTM instructions, with the exception of tcheck, set CR0 with the
@@ -94,15 +96,11 @@ def TRECHKPT : XForm_base_r3xo <31, 1006,
// tbegin builtin API which defines a return value of 1 as success.
def : Pat<(int_ppc_tbegin i32:$R),
- (XORI
- (EXTRACT_SUBREG (
- TBEGIN (HTM_get_imm imm:$R)), sub_eq),
- 1)>;
+ (XORI (TBEGIN_RET(HTM_get_imm imm:$R)), 1)>;
def : Pat<(int_ppc_tend i32:$R),
(TEND (HTM_get_imm imm:$R))>;
-
def : Pat<(int_ppc_tabort i32:$R),
(TABORT $R)>;
diff --git a/suite/synctools/tablegen/PPC/PPCInstrInfo.td b/suite/synctools/tablegen/PPC/PPCInstrInfo.td
index 1a43037e4a..863e13ed9a 100644
--- a/suite/synctools/tablegen/PPC/PPCInstrInfo.td
+++ b/suite/synctools/tablegen/PPC/PPCInstrInfo.td
@@ -540,10 +540,6 @@ def PPCRegCRRCAsmOperand : AsmOperandClass {
def crrc : RegisterOperand {
let ParserMatchClass = PPCRegCRRCAsmOperand;
}
-def crrc0 : RegisterOperand {
- let ParserMatchClass = PPCRegCRRCAsmOperand;
-}
-
def PPCRegSPERCAsmOperand : AsmOperandClass {
let Name = "RegSPERC"; let PredicateMethod = "isRegNumber";
}
diff --git a/suite/synctools/tablegen/PPC/PPCRegisterInfo.td b/suite/synctools/tablegen/PPC/PPCRegisterInfo.td
index 825e9eb8db..e88590f6b9 100644
--- a/suite/synctools/tablegen/PPC/PPCRegisterInfo.td
+++ b/suite/synctools/tablegen/PPC/PPCRegisterInfo.td
@@ -369,8 +369,6 @@ def CRBITRC : RegisterClass<"PPC", [i1], 32,
def CRRC : RegisterClass<"PPC", [i32], 32, (add CR0, CR1, CR5, CR6,
CR7, CR2, CR3, CR4)>;
-def CRRC0 : RegisterClass<"PPC", [i32], 32, (add CR0)>;
-
// The CTR registers are not allocatable because they're used by the
// decrement-and-branch instructions, and thus need to stay live across
// multiple basic blocks.
diff --git a/tests/Makefile b/tests/Makefile
index e514c273ea..86a08e604f 100644
--- a/tests/Makefile
+++ b/tests/Makefile
@@ -137,6 +137,7 @@ all: $(BINARY)
clean:
rm -rf $(OBJS) $(BINARY) $(TESTDIR)/*.exe $(TESTDIR)/*.static $(OBJDIR)/lib$(LIBNAME).* $(OBJDIR)/$(LIBNAME).*
+ rm -f *.d $(TESTDIR)/*.d $(OBJDIR)/*.d
# remove orphan files due to renaming from test.c to test_basic.c
rm -rf $(TESTDIR)/test.o $(TESTDIR)/test.exe $(TESTDIR)/test.static $(TESTDIR)/test
diff --git a/tests/test_detail.c b/tests/test_detail.c
index ed81e0c40b..ea7d1fdd18 100644
--- a/tests/test_detail.c
+++ b/tests/test_detail.c
@@ -83,7 +83,7 @@ static void test()
CS_ARCH_X86,
CS_MODE_16,
(unsigned char *)X86_CODE16,
- sizeof(X86_CODE32) - 1,
+ sizeof(X86_CODE16) - 1,
"X86 16bit (Intel syntax)"
},
{