diff options
Diffstat (limited to 'capstone/tests')
-rw-r--r-- | capstone/tests/Makefile | 186 | ||||
-rw-r--r-- | capstone/tests/README | 31 | ||||
-rw-r--r-- | capstone/tests/test_arm.c | 293 | ||||
-rw-r--r-- | capstone/tests/test_arm64.c | 228 | ||||
-rw-r--r-- | capstone/tests/test_basic.c | 423 | ||||
-rw-r--r-- | capstone/tests/test_bpf.c | 187 | ||||
-rw-r--r-- | capstone/tests/test_customized_mnem.c | 86 | ||||
-rw-r--r-- | capstone/tests/test_detail.c | 374 | ||||
-rw-r--r-- | capstone/tests/test_evm.c | 126 | ||||
-rw-r--r-- | capstone/tests/test_iter.c | 337 | ||||
-rw-r--r-- | capstone/tests/test_m680x.c | 396 | ||||
-rw-r--r-- | capstone/tests/test_m68k.c | 217 | ||||
-rw-r--r-- | capstone/tests/test_mips.c | 175 | ||||
-rw-r--r-- | capstone/tests/test_mos65xx.c | 230 | ||||
-rw-r--r-- | capstone/tests/test_ppc.c | 186 | ||||
-rw-r--r-- | capstone/tests/test_riscv.c | 154 | ||||
-rw-r--r-- | capstone/tests/test_skipdata.c | 184 | ||||
-rw-r--r-- | capstone/tests/test_sparc.c | 152 | ||||
-rw-r--r-- | capstone/tests/test_systemz.c | 145 | ||||
-rw-r--r-- | capstone/tests/test_tms320c64x.c | 193 | ||||
-rw-r--r-- | capstone/tests/test_wasm.c | 149 | ||||
-rw-r--r-- | capstone/tests/test_winkernel.cpp | 172 | ||||
-rw-r--r-- | capstone/tests/test_x86.c | 464 | ||||
-rw-r--r-- | capstone/tests/test_xcore.c | 140 |
24 files changed, 5228 insertions, 0 deletions
diff --git a/capstone/tests/Makefile b/capstone/tests/Makefile new file mode 100644 index 000000000..86a08e604 --- /dev/null +++ b/capstone/tests/Makefile @@ -0,0 +1,186 @@ +# Capstone Disassembler Engine +# By Nguyen Anh Quynh <aquynh@gmail.com>, 2013-2014 + +include ../config.mk +include ../functions.mk + +# Verbose output? +V ?= 0 + +INCDIR = ../include +ifndef BUILDDIR +TESTDIR = . +OBJDIR = . +LIBDIR = .. +else +TESTDIR = $(BUILDDIR)/tests +OBJDIR = $(BUILDDIR)/obj/tests +LIBDIR = $(BUILDDIR) +endif + +ifeq ($(CROSS),) +CC ?= cc +else +CC = $(CROSS)gcc +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 + +# Cygwin? +IS_CYGWIN := $(shell $(CC) -dumpmachine | grep -i cygwin | wc -l) +ifeq ($(IS_CYGWIN),1) +CFLAGS := $(CFLAGS:-fPIC=) +BIN_EXT = .exe +AR_EXT = lib +else +# mingw? +IS_MINGW := $(shell $(CC) --version 2>/dev/null | grep -i "\(mingw\|MSYS\)" | wc -l) +ifeq ($(IS_MINGW),1) +CFLAGS := $(CFLAGS:-fPIC=) +BIN_EXT = .exe +AR_EXT = lib +endif +endif + +ifeq ($(CAPSTONE_STATIC),yes) +ifeq ($(IS_MINGW),1) +ARCHIVE = $(LIBDIR)/$(LIBNAME).$(AR_EXT) +else ifeq ($(IS_CYGWIN),1) +ARCHIVE = $(LIBDIR)/$(LIBNAME).$(AR_EXT) +else +ARCHIVE = $(LIBDIR)/lib$(LIBNAME).$(AR_EXT) +endif +endif + +.PHONY: all clean + +SOURCES = test_basic.c test_detail.c test_skipdata.c test_iter.c test_customized_mnem.c +ifneq (,$(findstring arm,$(CAPSTONE_ARCHS))) +CFLAGS += -DCAPSTONE_HAS_ARM +SOURCES += test_arm.c +endif +ifneq (,$(findstring aarch64,$(CAPSTONE_ARCHS))) +CFLAGS += -DCAPSTONE_HAS_ARM64 +SOURCES += test_arm64.c +endif +ifneq (,$(findstring m68k,$(CAPSTONE_ARCHS))) +CFLAGS += -DCAPSTONE_HAS_M68K +SOURCES += test_m68k.c +endif +ifneq (,$(findstring mips,$(CAPSTONE_ARCHS))) +CFLAGS += -DCAPSTONE_HAS_MIPS +SOURCES += test_mips.c +endif +ifneq (,$(findstring powerpc,$(CAPSTONE_ARCHS))) +CFLAGS += -DCAPSTONE_HAS_POWERPC +SOURCES += test_ppc.c +endif +ifneq (,$(findstring sparc,$(CAPSTONE_ARCHS))) +CFLAGS += -DCAPSTONE_HAS_SPARC +SOURCES += test_sparc.c +endif +ifneq (,$(findstring systemz,$(CAPSTONE_ARCHS))) +CFLAGS += -DCAPSTONE_HAS_SYSZ +SOURCES += test_systemz.c +endif +ifneq (,$(findstring x86,$(CAPSTONE_ARCHS))) +CFLAGS += -DCAPSTONE_HAS_X86 +SOURCES += test_x86.c +endif +ifneq (,$(findstring xcore,$(CAPSTONE_ARCHS))) +CFLAGS += -DCAPSTONE_HAS_XCORE +SOURCES += test_xcore.c +endif +ifneq (,$(findstring tms320c64x,$(CAPSTONE_ARCHS))) +CFLAGS += -DCAPSTONE_HAS_TMS320C64X +SOURCES += test_tms320c64x.c +endif +ifneq (,$(findstring m680x,$(CAPSTONE_ARCHS))) +CFLAGS += -DCAPSTONE_HAS_M680X +SOURCES += test_m680x.c +endif +ifneq (,$(findstring evm,$(CAPSTONE_ARCHS))) +CFLAGS += -DCAPSTONE_HAS_EVM +SOURCES += test_evm.c +endif +ifneq (,$(findstring riscv,$(CAPSTONE_ARCHS))) +CFLAGS += -DCAPSTONE_HAS_RISCV +SOURCES += test_riscv.c +endif +ifneq (,$(findstring wasm,$(CAPSTONE_ARCHS))) +CFLAGS += -DCAPSTONE_HAS_WASM +SOURCES += test_wasm.c +endif +ifneq (,$(findstring evm,$(CAPSTONE_ARCHS))) +CFLAGS += -DCAPSTONE_HAS_MOS65XX +SOURCES += test_mos65xx.c +endif +ifneq (,$(findstring bpf,$(CAPSTONE_ARCHS))) +CFLAGS += -DCAPSTONE_HAS_BPF +SOURCES += test_bpf.c +endif + +OBJS = $(addprefix $(OBJDIR)/,$(SOURCES:.c=.o)) +BINARY = $(addprefix $(TESTDIR)/,$(SOURCES:.c=$(BIN_EXT))) + +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 + +$(BINARY): $(OBJS) + +$(TESTDIR)/%$(BIN_EXT): $(OBJDIR)/%.o + @mkdir -p $(@D) +ifeq ($(V),0) +ifeq ($(CAPSTONE_SHARED),yes) + $(call log,LINK,$(notdir $@)) + @$(link-dynamic) +endif +ifeq ($(CAPSTONE_STATIC),yes) + $(call log,LINK,$(notdir $(call staticname,$@))) + @$(link-static) +endif +else +ifeq ($(CAPSTONE_SHARED),yes) + $(link-dynamic) +endif +ifeq ($(CAPSTONE_STATIC),yes) + $(link-static) +endif +endif + +$(OBJDIR)/%.o: %.c + @mkdir -p $(@D) +ifeq ($(V),0) + $(call log,CC,$(@:$(OBJDIR)/%=%)) + @$(compile) +else + $(compile) +endif + + +define link-dynamic + $(CC) $(LDFLAGS) $< -l$(LIBNAME) -o $@ +endef + + +define link-static + $(CC) $(LDFLAGS) $< $(ARCHIVE) -o $(call staticname,$@) +endef + + +staticname = $(subst $(BIN_EXT),,$(1)).static$(BIN_EXT) diff --git a/capstone/tests/README b/capstone/tests/README new file mode 100644 index 000000000..e5d3efb48 --- /dev/null +++ b/capstone/tests/README @@ -0,0 +1,31 @@ +This directory contains some test code to show how to use Capstone API. + +- test_basic.c + This code shows the most simple form of API where we only want to get basic + information out of disassembled instruction, such as address, mnemonic and + operand string. + +- test_detail.c: + This code shows how to access to architecture-neutral information in disassembled + instructions, such as implicit registers read/written, or groups of instructions + that this instruction belong to. + +- test_skipdata.c: + This code shows how to use SKIPDATA option to skip broken instructions (most likely + some data mixed with instructions) and continue to decode at the next legitimate + instructions. + +- test_iter.c: + This code shows how to use the API cs_disasm_iter() to decode one instruction at + a time inside a loop. + +- test_customized_mnem.c: + This code shows how to use MNEMONIC option to customize instruction mnemonic + at run-time, and then how to reset the engine to use the default mnemonic. + +- test_<arch>.c + These code show how to access architecture-specific information for each + architecture. + +- test_winkernel.cpp + This code shows how to use Capstone from a Windows driver. diff --git a/capstone/tests/test_arm.c b/capstone/tests/test_arm.c new file mode 100644 index 000000000..a5016fafb --- /dev/null +++ b/capstone/tests/test_arm.c @@ -0,0 +1,293 @@ +/* Capstone Disassembler Engine */ +/* By Nguyen Anh Quynh <aquynh@gmail.com>, 2013-2019 */ + +#include <stdio.h> +#include <stdlib.h> + +#include <capstone/platform.h> +#include <capstone/capstone.h> + +static csh handle; + +struct platform { + cs_arch arch; + cs_mode mode; + unsigned char *code; + size_t size; + const char *comment; + int syntax; +}; + +static 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"); +} + +static void print_insn_detail(csh cs_handle, cs_insn *ins) +{ + cs_arm *arm; + int i; + cs_regs regs_read, regs_write; + uint8_t regs_read_count, regs_write_count; + + // detail can be NULL on "data" instruction if SKIPDATA option is turned ON + if (ins->detail == NULL) + return; + + arm = &(ins->detail->arm); + + if (arm->op_count) + printf("\top_count: %u\n", arm->op_count); + + for (i = 0; i < arm->op_count; i++) { + cs_arm_op *op = &(arm->operands[i]); + switch((int)op->type) { + default: + break; + case ARM_OP_REG: + printf("\t\toperands[%u].type: REG = %s\n", i, cs_reg_name(cs_handle, op->reg)); + break; + case ARM_OP_IMM: + printf("\t\toperands[%u].type: IMM = 0x%x\n", i, op->imm); + break; + case ARM_OP_FP: +#if defined(_KERNEL_MODE) + // Issue #681: Windows kernel does not support formatting float point + printf("\t\toperands[%u].type: FP = <float_point_unsupported>\n", i); +#else + printf("\t\toperands[%u].type: FP = %f\n", i, op->fp); +#endif + break; + case ARM_OP_MEM: + printf("\t\toperands[%u].type: MEM\n", i); + if (op->mem.base != ARM_REG_INVALID) + printf("\t\t\toperands[%u].mem.base: REG = %s\n", + i, cs_reg_name(cs_handle, op->mem.base)); + if (op->mem.index != ARM_REG_INVALID) + printf("\t\t\toperands[%u].mem.index: REG = %s\n", + i, cs_reg_name(cs_handle, op->mem.index)); + if (op->mem.scale != 1) + printf("\t\t\toperands[%u].mem.scale: %u\n", i, op->mem.scale); + if (op->mem.disp != 0) + printf("\t\t\toperands[%u].mem.disp: 0x%x\n", i, op->mem.disp); + if (op->mem.lshift != 0) + printf("\t\t\toperands[%u].mem.lshift: 0x%x\n", i, op->mem.lshift); + + break; + case ARM_OP_PIMM: + printf("\t\toperands[%u].type: P-IMM = %u\n", i, op->imm); + break; + case ARM_OP_CIMM: + printf("\t\toperands[%u].type: C-IMM = %u\n", i, op->imm); + break; + case ARM_OP_SETEND: + printf("\t\toperands[%u].type: SETEND = %s\n", i, op->setend == ARM_SETEND_BE? "be" : "le"); + break; + case ARM_OP_SYSREG: + printf("\t\toperands[%u].type: SYSREG = %u\n", i, op->reg); + break; + } + + if (op->neon_lane != -1) { + printf("\t\toperands[%u].neon_lane = %u\n", i, op->neon_lane); + } + + switch(op->access) { + default: + break; + case CS_AC_READ: + printf("\t\toperands[%u].access: READ\n", i); + break; + case CS_AC_WRITE: + printf("\t\toperands[%u].access: WRITE\n", i); + break; + case CS_AC_READ | CS_AC_WRITE: + printf("\t\toperands[%u].access: READ | WRITE\n", i); + break; + } + + if (op->shift.type != ARM_SFT_INVALID && op->shift.value) { + if (op->shift.type < ARM_SFT_ASR_REG) + // shift with constant value + printf("\t\t\tShift: %u = %u\n", op->shift.type, op->shift.value); + else + // shift with register + printf("\t\t\tShift: %u = %s\n", op->shift.type, + cs_reg_name(cs_handle, op->shift.value)); + } + + if (op->vector_index != -1) { + printf("\t\toperands[%u].vector_index = %u\n", i, op->vector_index); + } + + if (op->subtracted) + printf("\t\tSubtracted: True\n"); + } + + if (arm->cc != ARM_CC_AL && arm->cc != ARM_CC_INVALID) + printf("\tCode condition: %u\n", arm->cc); + + if (arm->update_flags) + printf("\tUpdate-flags: True\n"); + + if (arm->writeback) + printf("\tWrite-back: True\n"); + + if (arm->cps_mode) + printf("\tCPSI-mode: %u\n", arm->cps_mode); + + if (arm->cps_flag) + printf("\tCPSI-flag: %u\n", arm->cps_flag); + + if (arm->vector_data) + printf("\tVector-data: %u\n", arm->vector_data); + + if (arm->vector_size) + printf("\tVector-size: %u\n", arm->vector_size); + + if (arm->usermode) + printf("\tUser-mode: True\n"); + + if (arm->mem_barrier) + printf("\tMemory-barrier: %u\n", arm->mem_barrier); + + // Print out all registers accessed by this instruction (either implicit or explicit) + if (!cs_regs_access(cs_handle, ins, + regs_read, ®s_read_count, + regs_write, ®s_write_count)) { + if (regs_read_count) { + printf("\tRegisters read:"); + for(i = 0; i < regs_read_count; i++) { + printf(" %s", cs_reg_name(cs_handle, regs_read[i])); + } + printf("\n"); + } + + if (regs_write_count) { + printf("\tRegisters modified:"); + for(i = 0; i < regs_write_count; i++) { + printf(" %s", cs_reg_name(cs_handle, regs_write[i])); + } + printf("\n"); + } + } + + printf("\n"); +} + +static void test() +{ +#define ARM_CODE "\x86\x48\x60\xf4\x4d\x0f\xe2\xf4\xED\xFF\xFF\xEB\x04\xe0\x2d\xe5\x00\x00\x00\x00\xe0\x83\x22\xe5\xf1\x02\x03\x0e\x00\x00\xa0\xe3\x02\x30\xc1\xe7\x00\x00\x53\xe3\x00\x02\x01\xf1\x05\x40\xd0\xe8\xf4\x80\x00\x00" +#define ARM_CODE2 "\xd1\xe8\x00\xf0\xf0\x24\x04\x07\x1f\x3c\xf2\xc0\x00\x00\x4f\xf0\x00\x01\x46\x6c" +#define THUMB_CODE "\x60\xf9\x1f\x04\xe0\xf9\x4f\x07\x70\x47\x00\xf0\x10\xe8\xeb\x46\x83\xb0\xc9\x68\x1f\xb1\x30\xbf\xaf\xf3\x20\x84\x52\xf8\x23\xf0" +#define THUMB_CODE2 "\x4f\xf0\x00\x01\xbd\xe8\x00\x88\xd1\xe8\x00\xf0\x18\xbf\xad\xbf\xf3\xff\x0b\x0c\x86\xf3\x00\x89\x80\xf3\x00\x8c\x4f\xfa\x99\xf6\xd0\xff\xa2\x01" +#define THUMB_MCLASS "\xef\xf3\x02\x80" +#define ARMV8 "\xe0\x3b\xb2\xee\x42\x00\x01\xe1\x51\xf0\x7f\xf5" + + struct platform platforms[] = { + { + CS_ARCH_ARM, + CS_MODE_ARM, + (unsigned char *)ARM_CODE, + sizeof(ARM_CODE) - 1, + "ARM" + }, + { + CS_ARCH_ARM, + CS_MODE_THUMB, + (unsigned char *)THUMB_CODE, + sizeof(THUMB_CODE) - 1, + "Thumb" + }, + { + CS_ARCH_ARM, + CS_MODE_THUMB, + (unsigned char *)ARM_CODE2, + sizeof(ARM_CODE2) - 1, + "Thumb-mixed" + }, + { + CS_ARCH_ARM, + CS_MODE_THUMB, + (unsigned char *)THUMB_CODE2, + sizeof(THUMB_CODE2) - 1, + "Thumb-2 & register named with numbers", + CS_OPT_SYNTAX_NOREGNAME + }, + { + CS_ARCH_ARM, + (cs_mode)(CS_MODE_THUMB + CS_MODE_MCLASS), + (unsigned char*)THUMB_MCLASS, + sizeof(THUMB_MCLASS) - 1, + "Thumb-MClass" + }, + { + CS_ARCH_ARM, + (cs_mode)(CS_MODE_ARM + CS_MODE_V8), + (unsigned char*)ARMV8, + sizeof(ARMV8) - 1, + "Arm-V8" + }, + }; + + uint64_t address = 0x80001000; + cs_insn *insn; + int i; + size_t count; + + for (i = 0; i < sizeof(platforms)/sizeof(platforms[0]); i++) { + cs_err err = cs_open(platforms[i].arch, platforms[i].mode, &handle); + if (err) { + printf("Failed on cs_open() with error returned: %u\n", err); + abort(); + } + + cs_option(handle, CS_OPT_DETAIL, CS_OPT_ON); + + if (platforms[i].syntax) + cs_option(handle, CS_OPT_SYNTAX, platforms[i].syntax); + + count = cs_disasm(handle, platforms[i].code, platforms[i].size, address, 0, &insn); + if (count) { + size_t j; + printf("****************\n"); + printf("Platform: %s\n", platforms[i].comment); + print_string_hex("Code:", platforms[i].code, platforms[i].size); + printf("Disasm:\n"); + + for (j = 0; j < count; j++) { + printf("0x%" PRIx64 ":\t%s\t%s\n", insn[j].address, insn[j].mnemonic, insn[j].op_str); + print_insn_detail(handle, &insn[j]); + } + printf("0x%" PRIx64 ":\n", insn[j-1].address + insn[j-1].size); + + // free memory allocated by cs_disasm() + cs_free(insn, count); + } else { + printf("****************\n"); + printf("Platform: %s\n", platforms[i].comment); + print_string_hex("Code:", platforms[i].code, platforms[i].size); + printf("ERROR: Failed to disasm given code!\n"); + abort(); + } + + printf("\n"); + + cs_close(&handle); + } +} + +int main() +{ + test(); + + return 0; +} + diff --git a/capstone/tests/test_arm64.c b/capstone/tests/test_arm64.c new file mode 100644 index 000000000..bafb9da21 --- /dev/null +++ b/capstone/tests/test_arm64.c @@ -0,0 +1,228 @@ +/* Capstone Disassembler Engine */ +/* By Nguyen Anh Quynh <aquynh@gmail.com>, 2013-2019 */ + +#include <stdio.h> +#include <stdlib.h> + +#include <capstone/platform.h> +#include <capstone/capstone.h> + +static csh handle; + +struct platform { + cs_arch arch; + cs_mode mode; + unsigned char *code; + size_t size; + const char *comment; +}; + +static 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"); +} + +static void print_insn_detail(cs_insn *ins) +{ + cs_arm64 *arm64; + int i; + cs_regs regs_read, regs_write; + unsigned char regs_read_count, regs_write_count; + unsigned char access; + + // detail can be NULL if SKIPDATA option is turned ON + if (ins->detail == NULL) + return; + + arm64 = &(ins->detail->arm64); + if (arm64->op_count) + printf("\top_count: %u\n", arm64->op_count); + + for (i = 0; i < arm64->op_count; i++) { + cs_arm64_op *op = &(arm64->operands[i]); + switch(op->type) { + default: + break; + case ARM64_OP_REG: + printf("\t\toperands[%u].type: REG = %s\n", i, cs_reg_name(handle, op->reg)); + break; + case ARM64_OP_IMM: + printf("\t\toperands[%u].type: IMM = 0x%" PRIx64 "\n", i, op->imm); + break; + case ARM64_OP_FP: +#if defined(_KERNEL_MODE) + // Issue #681: Windows kernel does not support formatting float point + printf("\t\toperands[%u].type: FP = <float_point_unsupported>\n", i); +#else + printf("\t\toperands[%u].type: FP = %f\n", i, op->fp); +#endif + break; + case ARM64_OP_MEM: + printf("\t\toperands[%u].type: MEM\n", i); + if (op->mem.base != ARM64_REG_INVALID) + printf("\t\t\toperands[%u].mem.base: REG = %s\n", i, cs_reg_name(handle, op->mem.base)); + if (op->mem.index != ARM64_REG_INVALID) + printf("\t\t\toperands[%u].mem.index: REG = %s\n", i, cs_reg_name(handle, op->mem.index)); + if (op->mem.disp != 0) + printf("\t\t\toperands[%u].mem.disp: 0x%x\n", i, op->mem.disp); + + break; + case ARM64_OP_CIMM: + printf("\t\toperands[%u].type: C-IMM = %u\n", i, (int)op->imm); + break; + case ARM64_OP_REG_MRS: + printf("\t\toperands[%u].type: REG_MRS = 0x%x\n", i, op->reg); + break; + case ARM64_OP_REG_MSR: + printf("\t\toperands[%u].type: REG_MSR = 0x%x\n", i, op->reg); + break; + case ARM64_OP_PSTATE: + printf("\t\toperands[%u].type: PSTATE = 0x%x\n", i, op->pstate); + break; + case ARM64_OP_SYS: + printf("\t\toperands[%u].type: SYS = 0x%x\n", i, op->sys); + break; + case ARM64_OP_PREFETCH: + printf("\t\toperands[%u].type: PREFETCH = 0x%x\n", i, op->prefetch); + break; + case ARM64_OP_BARRIER: + printf("\t\toperands[%u].type: BARRIER = 0x%x\n", i, op->barrier); + break; + } + + access = op->access; + switch(access) { + default: + break; + case CS_AC_READ: + printf("\t\toperands[%u].access: READ\n", i); + break; + case CS_AC_WRITE: + printf("\t\toperands[%u].access: WRITE\n", i); + break; + case CS_AC_READ | CS_AC_WRITE: + printf("\t\toperands[%u].access: READ | WRITE\n", i); + break; + } + + if (op->shift.type != ARM64_SFT_INVALID && + op->shift.value) + printf("\t\t\tShift: type = %u, value = %u\n", + op->shift.type, op->shift.value); + + if (op->ext != ARM64_EXT_INVALID) + printf("\t\t\tExt: %u\n", op->ext); + + if (op->vas != ARM64_VAS_INVALID) + printf("\t\t\tVector Arrangement Specifier: 0x%x\n", op->vas); + + if (op->vector_index != -1) + printf("\t\t\tVector Index: %u\n", op->vector_index); + } + + if (arm64->update_flags) + printf("\tUpdate-flags: True\n"); + + if (arm64->writeback) + printf("\tWrite-back: True\n"); + + if (arm64->cc) + printf("\tCode-condition: %u\n", arm64->cc); + + // Print out all registers accessed by this instruction (either implicit or explicit) + if (!cs_regs_access(handle, ins, + regs_read, ®s_read_count, + regs_write, ®s_write_count)) { + if (regs_read_count) { + printf("\tRegisters read:"); + for(i = 0; i < regs_read_count; i++) { + printf(" %s", cs_reg_name(handle, regs_read[i])); + } + printf("\n"); + } + + if (regs_write_count) { + printf("\tRegisters modified:"); + for(i = 0; i < regs_write_count; i++) { + printf(" %s", cs_reg_name(handle, regs_write[i])); + } + printf("\n"); + } + } + + printf("\n"); +} + +static void test() +{ +#define ARM64_CODE "\x09\x00\x38\xd5\xbf\x40\x00\xd5\x0c\x05\x13\xd5\x20\x50\x02\x0e\x20\xe4\x3d\x0f\x00\x18\xa0\x5f\xa2\x00\xae\x9e\x9f\x37\x03\xd5\xbf\x33\x03\xd5\xdf\x3f\x03\xd5\x21\x7c\x02\x9b\x21\x7c\x00\x53\x00\x40\x21\x4b\xe1\x0b\x40\xb9\x20\x04\x81\xda\x20\x08\x02\x8b\x10\x5b\xe8\x3c" + + struct platform platforms[] = { + { + CS_ARCH_ARM64, + CS_MODE_ARM, + (unsigned char *)ARM64_CODE, + sizeof(ARM64_CODE) - 1, + "ARM-64" + }, + }; + + uint64_t address = 0x2c; + cs_insn *insn; + int i; + size_t count; + + for (i = 0; i < sizeof(platforms)/sizeof(platforms[0]); i++) { + cs_err err = cs_open(platforms[i].arch, platforms[i].mode, &handle); + if (err) { + printf("Failed on cs_open() with error returned: %u\n", err); + abort(); + } + + cs_option(handle, CS_OPT_DETAIL, CS_OPT_ON); + + count = cs_disasm(handle, platforms[i].code, platforms[i].size, address, 0, &insn); + if (count) { + size_t j; + + printf("****************\n"); + printf("Platform: %s\n", platforms[i].comment); + print_string_hex("Code: ", platforms[i].code, platforms[i].size); + printf("Disasm:\n"); + + for (j = 0; j < count; j++) { + printf("0x%" PRIx64 ":\t%s\t%s\n", insn[j].address, insn[j].mnemonic, insn[j].op_str); + print_insn_detail(&insn[j]); + } + printf("0x%" PRIx64 ":\n", insn[j-1].address + insn[j-1].size); + + // free memory allocated by cs_disasm() + cs_free(insn, count); + } else { + printf("****************\n"); + printf("Platform: %s\n", platforms[i].comment); + print_string_hex("Code: ", platforms[i].code, platforms[i].size); + printf("ERROR: Failed to disasm given code!\n"); + abort(); + } + + printf("\n"); + + cs_close(&handle); + } +} + +int main() +{ + test(); + + return 0; +} + diff --git a/capstone/tests/test_basic.c b/capstone/tests/test_basic.c new file mode 100644 index 000000000..3a8e1e0b9 --- /dev/null +++ b/capstone/tests/test_basic.c @@ -0,0 +1,423 @@ +/* Capstone Disassembler Engine */ +/* By Nguyen Anh Quynh <aquynh@gmail.com>, 2013-2019 */ + +#include <stdio.h> +#include <stdlib.h> + +#include <capstone/platform.h> +#include <capstone/capstone.h> + +struct platform { + cs_arch arch; + cs_mode mode; + unsigned char *code; + size_t size; + const char *comment; + cs_opt_type opt_type; + cs_opt_value opt_value; +}; + +static void print_string_hex(unsigned char *str, size_t len) +{ + unsigned char *c; + + printf("Code: "); + for (c = str; c < str + len; c++) { + printf("0x%02x ", *c & 0xff); + } + printf("\n"); +} + +static void test() +{ +#ifdef CAPSTONE_HAS_X86 +#define X86_CODE16 "\x8d\x4c\x32\x08\x01\xd8\x81\xc6\x34\x12\x00\x00" +#define X86_CODE32 "\xba\xcd\xab\x00\x00\x8d\x4c\x32\x08\x01\xd8\x81\xc6\x34\x12\x00\x00" +#define X86_CODE64 "\x55\x48\x8b\x05\xb8\x13\x00\x00" +#endif +#ifdef CAPSTONE_HAS_ARM +#define ARM_CODE "\xED\xFF\xFF\xEB\x04\xe0\x2d\xe5\x00\x00\x00\x00\xe0\x83\x22\xe5\xf1\x02\x03\x0e\x00\x00\xa0\xe3\x02\x30\xc1\xe7\x00\x00\x53\xe3" +#define ARM_CODE2 "\x10\xf1\x10\xe7\x11\xf2\x31\xe7\xdc\xa1\x2e\xf3\xe8\x4e\x62\xf3" +#define ARMV8 "\xe0\x3b\xb2\xee\x42\x00\x01\xe1\x51\xf0\x7f\xf5" +#define THUMB_MCLASS "\xef\xf3\x02\x80" +#define THUMB_CODE "\x70\x47\xeb\x46\x83\xb0\xc9\x68" +#define THUMB_CODE2 "\x4f\xf0\x00\x01\xbd\xe8\x00\x88\xd1\xe8\x00\xf0" +#endif +#ifdef CAPSTONE_HAS_MIPS +#define MIPS_CODE "\x0C\x10\x00\x97\x00\x00\x00\x00\x24\x02\x00\x0c\x8f\xa2\x00\x00\x34\x21\x34\x56" +#define MIPS_CODE2 "\x56\x34\x21\x34\xc2\x17\x01\x00" +#define MIPS_32R6M "\x00\x07\x00\x07\x00\x11\x93\x7c\x01\x8c\x8b\x7c\x00\xc7\x48\xd0" +#define MIPS_32R6 "\xec\x80\x00\x19\x7c\x43\x22\xa0" +#endif +#ifdef CAPSTONE_HAS_ARM64 +#define ARM64_CODE "\x21\x7c\x02\x9b\x21\x7c\x00\x53\x00\x40\x21\x4b\xe1\x0b\x40\xb9" +#endif +#ifdef CAPSTONE_HAS_POWERPC +#define PPC_CODE "\x80\x20\x00\x00\x80\x3f\x00\x00\x10\x43\x23\x0e\xd0\x44\x00\x80\x4c\x43\x22\x02\x2d\x03\x00\x80\x7c\x43\x20\x14\x7c\x43\x20\x93\x4f\x20\x00\x21\x4c\xc8\x00\x21" +#define PPC_CODE2 "\x10\x60\x2a\x10\x10\x64\x28\x88\x7c\x4a\x5d\x0f" +#endif +#ifdef CAPSTONE_HAS_SPARC +#define SPARC_CODE "\x80\xa0\x40\x02\x85\xc2\x60\x08\x85\xe8\x20\x01\x81\xe8\x00\x00\x90\x10\x20\x01\xd5\xf6\x10\x16\x21\x00\x00\x0a\x86\x00\x40\x02\x01\x00\x00\x00\x12\xbf\xff\xff\x10\xbf\xff\xff\xa0\x02\x00\x09\x0d\xbf\xff\xff\xd4\x20\x60\x00\xd4\x4e\x00\x16\x2a\xc2\x80\x03" +#define SPARCV9_CODE "\x81\xa8\x0a\x24\x89\xa0\x10\x20\x89\xa0\x1a\x60\x89\xa0\x00\xe0" +#endif +#ifdef CAPSTONE_HAS_SYSZ +#define SYSZ_CODE "\xed\x00\x00\x00\x00\x1a\x5a\x0f\x1f\xff\xc2\x09\x80\x00\x00\x00\x07\xf7\xeb\x2a\xff\xff\x7f\x57\xe3\x01\xff\xff\x7f\x57\xeb\x00\xf0\x00\x00\x24\xb2\x4f\x00\x78" +#endif +#ifdef CAPSTONE_HAS_XCORE +#define XCORE_CODE "\xfe\x0f\xfe\x17\x13\x17\xc6\xfe\xec\x17\x97\xf8\xec\x4f\x1f\xfd\xec\x37\x07\xf2\x45\x5b\xf9\xfa\x02\x06\x1b\x10" +#endif +#ifdef CAPSTONE_HAS_M68K +#define M68K_CODE "\xd4\x40\x87\x5a\x4e\x71\x02\xb4\xc0\xde\xc0\xde\x5c\x00\x1d\x80\x71\x12\x01\x23\xf2\x3c\x44\x22\x40\x49\x0e\x56\x54\xc5\xf2\x3c\x44\x00\x44\x7a\x00\x00\xf2\x00\x0a\x28" +#endif +#ifdef CAPSTONE_HAS_TMS320C64X +#define TMS320C64X_CODE "\x01\xac\x88\x40\x81\xac\x88\x43\x00\x00\x00\x00\x02\x90\x32\x96\x02\x80\x46\x9e\x05\x3c\x83\xe6\x0b\x0c\x8b\x24" +#endif +#ifdef CAPSTONE_HAS_M680X +#define M680X_CODE "\x06\x10\x19\x1a\x55\x1e\x01\x23\xe9\x31\x06\x34\x55\xa6\x81\xa7\x89\x7f\xff\xa6\x9d\x10\x00\xa7\x91\xa6\x9f\x10\x00\x11\xac\x99\x10\x00\x39" +#endif +#ifdef CAPSTONE_HAS_EVM +#define EVM_CODE "\x60\x61" +#endif +#ifdef CAPSTONE_HAS_WASM +#define WASM_CODE "\x20\x00\x20\x01\x41\x20\x10\xc9\x01\x45\x0b" +#endif +#ifdef CAPSTONE_HAS_MOS65XX +#define MOS65XX_CODE "\x0d\x34\x12\x00\x81\x65\x6c\x01\x00\x85\xFF\x10\x00\x19\x42\x42\x00\x49\x42" +#endif +#define EBPF_CODE "\x97\x09\x00\x00\x37\x13\x03\x00\xdc\x02\x00\x00\x20\x00\x00\x00\x30\x00\x00\x00\x00\x00\x00\x00\xdb\x3a\x00\x01\x00\x00\x00\x00\x84\x02\x00\x00\x00\x00\x00\x00\x6d\x33\x17\x02\x00\x00\x00\x00" + +#ifdef CAPSTONE_HAS_RISCV +#define RISCV_CODE32 "\x37\x34\x00\x00\x97\x82\x00\x00\xef\x00\x80\x00\xef\xf0\x1f\xff\xe7\x00\x45\x00\xe7\x00\xc0\xff\x63\x05\x41\x00\xe3\x9d\x61\xfe\x63\xca\x93\x00\x63\x53\xb5\x00\x63\x65\xd6\x00\x63\x76\xf7\x00\x03\x88\x18\x00\x03\x99\x49\x00\x03\xaa\x6a\x00\x03\xcb\x2b\x01\x03\xdc\x8c\x01\x23\x86\xad\x03\x23\x9a\xce\x03\x23\x8f\xef\x01\x93\x00\xe0\x00\x13\xa1\x01\x01\x13\xb2\x02\x7d\x13\xc3\x03\xdd\x13\xe4\xc4\x12\x13\xf5\x85\x0c\x13\x96\xe6\x01\x13\xd7\x97\x01\x13\xd8\xf8\x40\x33\x89\x49\x01\xb3\x0a\x7b\x41\x33\xac\xac\x01\xb3\x3d\xde\x01\x33\xd2\x62\x40\xb3\x43\x94\x00\x33\xe5\xc5\x00\xb3\x76\xf7\x00\xb3\x54\x39\x01\xb3\x50\x31\x00\x33\x9f\x0f\x00" +#define RISCV_CODE64 "\x13\x04\xa8\x7a" // aaa80413 +#endif + + struct platform { + cs_arch arch; + cs_mode mode; + unsigned char *code; + size_t size; + const char *comment; + cs_opt_type opt_type; + cs_opt_value opt_value; + }; + struct platform platforms[] = { +#ifdef CAPSTONE_HAS_X86 + { + CS_ARCH_X86, + CS_MODE_16, + (unsigned char*)X86_CODE16, + sizeof(X86_CODE16) - 1, + "X86 16bit (Intel syntax)" + }, + { + CS_ARCH_X86, + CS_MODE_32, + (unsigned char*)X86_CODE32, + sizeof(X86_CODE32) - 1, + "X86 32bit (ATT syntax)", + CS_OPT_SYNTAX, + CS_OPT_SYNTAX_ATT, + }, + { + CS_ARCH_X86, + CS_MODE_32, + (unsigned char*)X86_CODE32, + sizeof(X86_CODE32) - 1, + "X86 32 (Intel syntax)" + }, + { + CS_ARCH_X86, + CS_MODE_32, + (unsigned char*)X86_CODE32, + sizeof(X86_CODE32) - 1, + "X86 32 (MASM syntax)", + CS_OPT_SYNTAX, + CS_OPT_SYNTAX_MASM, + }, + { + CS_ARCH_X86, + CS_MODE_64, + (unsigned char*)X86_CODE64, + sizeof(X86_CODE64) - 1, + "X86 64 (Intel syntax)" + }, +#endif +#ifdef CAPSTONE_HAS_ARM + { + CS_ARCH_ARM, + CS_MODE_ARM, + (unsigned char*)ARM_CODE, + sizeof(ARM_CODE) - 1, + "ARM" + }, + { + CS_ARCH_ARM, + CS_MODE_THUMB, + (unsigned char*)THUMB_CODE2, + sizeof(THUMB_CODE2) - 1, + "THUMB-2" + }, + { + CS_ARCH_ARM, + CS_MODE_ARM, + (unsigned char*)ARM_CODE2, + sizeof(ARM_CODE2) - 1, + "ARM: Cortex-A15 + NEON" + }, + { + CS_ARCH_ARM, + CS_MODE_THUMB, + (unsigned char*)THUMB_CODE, + sizeof(THUMB_CODE) - 1, + "THUMB" + }, + { + CS_ARCH_ARM, + (cs_mode)(CS_MODE_THUMB + CS_MODE_MCLASS), + (unsigned char*)THUMB_MCLASS, + sizeof(THUMB_MCLASS) - 1, + "Thumb-MClass" + }, + { + CS_ARCH_ARM, + (cs_mode)(CS_MODE_ARM + CS_MODE_V8), + (unsigned char*)ARMV8, + sizeof(ARMV8) - 1, + "Arm-V8" + }, +#endif +#ifdef CAPSTONE_HAS_MIPS + { + CS_ARCH_MIPS, + (cs_mode)(CS_MODE_MIPS32 + CS_MODE_BIG_ENDIAN), + (unsigned char*)MIPS_CODE, + sizeof(MIPS_CODE) - 1, + "MIPS-32 (Big-endian)" + }, + { + CS_ARCH_MIPS, + (cs_mode)(CS_MODE_MIPS64 + CS_MODE_LITTLE_ENDIAN), + (unsigned char*)MIPS_CODE2, + sizeof(MIPS_CODE2) - 1, + "MIPS-64-EL (Little-endian)" + }, + { + CS_ARCH_MIPS, + (cs_mode)(CS_MODE_MIPS32R6 + CS_MODE_MICRO + CS_MODE_BIG_ENDIAN), + (unsigned char*)MIPS_32R6M, + sizeof(MIPS_32R6M) - 1, + "MIPS-32R6 | Micro (Big-endian)" + }, + { + CS_ARCH_MIPS, + (cs_mode)(CS_MODE_MIPS32R6 + CS_MODE_BIG_ENDIAN), + (unsigned char*)MIPS_32R6, + sizeof(MIPS_32R6) - 1, + "MIPS-32R6 (Big-endian)" + }, +#endif +#ifdef CAPSTONE_HAS_ARM64 + { + CS_ARCH_ARM64, + CS_MODE_ARM, + (unsigned char*)ARM64_CODE, + sizeof(ARM64_CODE) - 1, + "ARM-64" + }, +#endif +#ifdef CAPSTONE_HAS_POWERPC + { + CS_ARCH_PPC, + CS_MODE_BIG_ENDIAN, + (unsigned char*)PPC_CODE, + sizeof(PPC_CODE) - 1, + "PPC-64" + }, + { + CS_ARCH_PPC, + CS_MODE_BIG_ENDIAN, + (unsigned char*)PPC_CODE, + sizeof(PPC_CODE) - 1, + "PPC-64, print register with number only", + CS_OPT_SYNTAX, + CS_OPT_SYNTAX_NOREGNAME + }, + { + CS_ARCH_PPC, + CS_MODE_BIG_ENDIAN + CS_MODE_QPX, + (unsigned char*)PPC_CODE2, + sizeof(PPC_CODE2) - 1, + "PPC-64 + QPX", + }, +#endif +#ifdef CAPSTONE_HAS_SPARC + { + CS_ARCH_SPARC, + CS_MODE_BIG_ENDIAN, + (unsigned char*)SPARC_CODE, + sizeof(SPARC_CODE) - 1, + "Sparc" + }, + { + CS_ARCH_SPARC, + (cs_mode)(CS_MODE_BIG_ENDIAN + CS_MODE_V9), + (unsigned char*)SPARCV9_CODE, + sizeof(SPARCV9_CODE) - 1, + "SparcV9" + }, +#endif +#ifdef CAPSTONE_HAS_SYSZ + { + CS_ARCH_SYSZ, + (cs_mode)0, + (unsigned char*)SYSZ_CODE, + sizeof(SYSZ_CODE) - 1, + "SystemZ" + }, +#endif +#ifdef CAPSTONE_HAS_XCORE + { + CS_ARCH_XCORE, + (cs_mode)0, + (unsigned char*)XCORE_CODE, + sizeof(XCORE_CODE) - 1, + "XCore" + }, +#endif +#ifdef CAPSTONE_HAS_M68K + { + CS_ARCH_M68K, + (cs_mode)(CS_MODE_BIG_ENDIAN | CS_MODE_M68K_040), + (unsigned char*)M68K_CODE, + sizeof(M68K_CODE) - 1, + "M68K", + }, +#endif +#ifdef CAPSTONE_HAS_TMS320C64X + { + CS_ARCH_TMS320C64X, + 0, + (unsigned char*)TMS320C64X_CODE, + sizeof(TMS320C64X_CODE) - 1, + "TMS320C64x", + }, +#endif +#ifdef CAPSTONE_HAS_M680X + { + CS_ARCH_M680X, + (cs_mode)(CS_MODE_M680X_6809), + (unsigned char*)M680X_CODE, + sizeof(M680X_CODE) - 1, + "M680X_M6809", + }, +#endif +#ifdef CAPSTONE_HAS_EVM + { + CS_ARCH_EVM, + 0, + (unsigned char*)EVM_CODE, + sizeof(EVM_CODE) - 1, + "EVM", + }, +#endif +#ifdef CAPSTONE_HAS_WASM + { + CS_ARCH_WASM, + 0, + (unsigned char*)WASM_CODE, + sizeof(WASM_CODE) - 1, + "WASM", + }, +#endif +#ifdef CAPSTONE_HAS_MOS65XX + { + CS_ARCH_MOS65XX, + 0, + (unsigned char *)MOS65XX_CODE, + sizeof(MOS65XX_CODE) - 1, + "MOS65XX" + }, +#endif +#ifdef CAPSTONE_HAS_BPF + { + CS_ARCH_BPF, + CS_MODE_LITTLE_ENDIAN | CS_MODE_BPF_EXTENDED, + (unsigned char*) EBPF_CODE, + sizeof(EBPF_CODE) - 1, + "eBPF" + }, +#endif +#ifdef CAPSTONE_HAS_RISCV + { + CS_ARCH_RISCV, + CS_MODE_RISCV32, + (unsigned char *)RISCV_CODE32, + sizeof(RISCV_CODE32) - 1, + "RISCV32" + }, + { + CS_ARCH_RISCV, + CS_MODE_RISCV64, + (unsigned char *)RISCV_CODE64, + sizeof(RISCV_CODE64) - 1, + "RISCV64" + }, +#endif + }; + + csh handle; + uint64_t address = 0x1000; + cs_insn *insn; + int i; + size_t count; + cs_err err; + + for (i = 0; i < sizeof(platforms)/sizeof(platforms[0]); i++) { + printf("****************\n"); + printf("Platform: %s\n", platforms[i].comment); + err = cs_open(platforms[i].arch, platforms[i].mode, &handle); + if (err) { + printf("Failed on cs_open() with error returned: %u\n", err); + abort(); + } + + if (platforms[i].opt_type) + cs_option(handle, platforms[i].opt_type, platforms[i].opt_value); + + count = cs_disasm(handle, platforms[i].code, platforms[i].size, address, 0, &insn); + if (count) { + size_t j; + + print_string_hex(platforms[i].code, platforms[i].size); + printf("Disasm:\n"); + + for (j = 0; j < count; j++) { + printf("0x%" PRIx64 ":\t%s\t\t%s\n", + insn[j].address, insn[j].mnemonic, insn[j].op_str); + } + + // print out the next offset, after the last insn + printf("0x%" PRIx64 ":\n", insn[j-1].address + insn[j-1].size); + + // free memory allocated by cs_disasm() + cs_free(insn, count); + } else { + printf("****************\n"); + printf("Platform: %s\n", platforms[i].comment); + print_string_hex(platforms[i].code, platforms[i].size); + printf("ERROR: Failed to disasm given code!\n"); + abort(); + } + + printf("\n"); + + cs_close(&handle); + } +} + +int main() +{ + test(); + + return 0; +} diff --git a/capstone/tests/test_bpf.c b/capstone/tests/test_bpf.c new file mode 100644 index 000000000..b97e330cb --- /dev/null +++ b/capstone/tests/test_bpf.c @@ -0,0 +1,187 @@ +/* Capstone Disassembly Engine */ +/* By david942j <david942j@gmail.com>, 2019 */ + +#include <capstone/capstone.h> +#include <capstone/platform.h> + +static csh handle; + +struct platform { + cs_arch arch; + cs_mode mode; + const unsigned char *code; + size_t size; + const char *comment; +}; + +static void print_string_hex(const char *comment, const unsigned char *str, size_t len) +{ + const unsigned char *c; + + printf("%s", comment); + for (c = str; c < str + len; c++) { + printf(" 0x%02x", *c & 0xff); + } + + printf("\n"); +} + +static const char * ext_name[] = { + [BPF_EXT_LEN] = "#len", +}; + +static void print_insn_detail(csh cs_handle, cs_insn *ins) +{ + cs_bpf *bpf; + cs_regs regs_read, regs_write; + uint8_t regs_read_count, regs_write_count; + unsigned i; + + // detail can be NULL on "data" instruction if SKIPDATA option is turned ON + if (ins->detail == NULL) + return; + + 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"); + } + + bpf = &(ins->detail->bpf); + + printf("\tOperand count: %u\n", bpf->op_count); + for (i = 0; i < bpf->op_count; i++) { + cs_bpf_op *op = &(bpf->operands[i]); + printf("\t\toperands[%u].type: ", i); + switch (op->type) { + case BPF_OP_INVALID: + printf("INVALID\n"); + break; + case BPF_OP_REG: + printf("REG = %s\n", cs_reg_name(handle, op->reg)); + break; + case BPF_OP_IMM: + printf("IMM = 0x%" PRIx64 "\n", op->imm); + break; + case BPF_OP_OFF: + printf("OFF = +0x%x\n", op->off); + break; + case BPF_OP_MEM: + printf("MEM\n"); + if (op->mem.base != BPF_REG_INVALID) + printf("\t\t\toperands[%u].mem.base: REG = %s\n", + i, cs_reg_name(handle, op->mem.base)); + printf("\t\t\toperands[%u].mem.disp: 0x%x\n", i, op->mem.disp); + break; + case BPF_OP_MMEM: + printf("MMEM = M[0x%x]\n", op->mmem); + break; + case BPF_OP_MSH: + printf("MSH = 4*([0x%x]&0xf)\n", op->msh); + break; + case BPF_OP_EXT: + printf("EXT = %s\n", ext_name[op->ext]); + break; + } + } + + /* print all registers that are involved in this instruction */ + if (!cs_regs_access(cs_handle, ins, + regs_read, ®s_read_count, + regs_write, ®s_write_count)) { + if (regs_read_count) { + printf("\tRegisters read:"); + for(i = 0; i < regs_read_count; i++) + printf(" %s", cs_reg_name(cs_handle, regs_read[i])); + printf("\n"); + } + + if (regs_write_count) { + printf("\tRegisters modified:"); + for(i = 0; i < regs_write_count; i++) + printf(" %s", cs_reg_name(cs_handle, regs_write[i])); + printf("\n"); + } + } + puts(""); +} + +static void test() +{ +#define CBPF_CODE "\x94\x09\x00\x00\x37\x13\x03\x00" \ + "\x87\x00\x00\x00\x00\x00\x00\x00" \ + "\x07\x00\x00\x00\x00\x00\x00\x00" \ + "\x16\x00\x00\x00\x00\x00\x00\x00" \ + "\x80\x00\x00\x00\x00\x00\x00\x00" + +#define EBPF_CODE "\x97\x09\x00\x00\x37\x13\x03\x00" \ + "\xdc\x02\x00\x00\x20\x00\x00\x00" \ + "\x30\x00\x00\x00\x00\x00\x00\x00" \ + "\xdb\x3a\x00\x01\x00\x00\x00\x00" \ + "\x84\x02\x00\x00\x00\x00\x00\x00" \ + "\x6d\x33\x17\x02\x00\x00\x00\x00" + struct platform platforms[] = { + { + CS_ARCH_BPF, + CS_MODE_LITTLE_ENDIAN | CS_MODE_BPF_CLASSIC, + (unsigned char *)CBPF_CODE, + sizeof(CBPF_CODE) - 1, + "cBPF Le" + }, + { + CS_ARCH_BPF, + CS_MODE_LITTLE_ENDIAN | CS_MODE_BPF_EXTENDED, + (unsigned char *)EBPF_CODE, + sizeof(EBPF_CODE) - 1, + "eBPF Le" + }, + }; + uint64_t address = 0x0; + cs_insn *insn; + int i; + size_t count; + + for (i = 0; i < sizeof(platforms)/sizeof(platforms[0]); i++) { + cs_err err = cs_open(platforms[i].arch, platforms[i].mode, &handle); + if (err) { + printf("Failed on cs_open() with error returned: %u\n", err); + abort(); + } + + cs_option(handle, CS_OPT_DETAIL, CS_OPT_ON); + + count = cs_disasm(handle, platforms[i].code, platforms[i].size, address, 0, &insn); + if (count) { + size_t j; + printf("****************\n"); + printf("Platform: %s\n", platforms[i].comment); + print_string_hex("Code:", platforms[i].code, platforms[i].size); + printf("Disasm:\n"); + + for (j = 0; j < count; j++) { + printf("0x%" PRIx64 ":\t%s\t%s\n", insn[j].address, insn[j].mnemonic, insn[j].op_str); + print_insn_detail(handle, &insn[j]); + } + + // free memory allocated by cs_disasm() + cs_free(insn, count); + } else { + printf("****************\n"); + printf("Platform: %s\n", platforms[i].comment); + print_string_hex("Code:", platforms[i].code, platforms[i].size); + printf("ERROR: Failed to disasm given code!\n"); + abort(); + } + + cs_close(&handle); + } +} + +int main() +{ + test(); + return 0; +} diff --git a/capstone/tests/test_customized_mnem.c b/capstone/tests/test_customized_mnem.c new file mode 100644 index 000000000..664cdb1cf --- /dev/null +++ b/capstone/tests/test_customized_mnem.c @@ -0,0 +1,86 @@ +/* Capstone Disassembly Engine */ +/* By Nguyen Anh Quynh <aquynh@gmail.com>, 2015-2019 */ + +// This sample code demonstrates the option CS_OPT_MNEMONIC +// to customize instruction mnemonic. + +#include <stdio.h> +#include <stdlib.h> + +#include <capstone/platform.h> +#include <capstone/capstone.h> + +#define X86_CODE32 "\x75\x01" + +// Print out the input code in hexadecimal format +static void print_string_hex(unsigned char *str, size_t len) +{ + unsigned char *c; + + for (c = str; c < str + len; c++) { + printf("%02x ", *c & 0xff); + } + printf("\t"); +} + +// Print one instruction +static void print_insn(csh handle) +{ + cs_insn *insn; + size_t count; + + count = cs_disasm(handle, (const uint8_t *)X86_CODE32, sizeof(X86_CODE32) - 1, 0x1000, 1, &insn); + if (count) { + print_string_hex((unsigned char *)X86_CODE32, sizeof(X86_CODE32) - 1); + printf("\t%s\t%s\n", insn[0].mnemonic, insn[0].op_str); + // Free memory allocated by cs_disasm() + cs_free(insn, count); + } else { + printf("ERROR: Failed to disasm given code!\n"); + abort(); + } +} + +static void test() +{ + csh handle; + cs_err err; + // Customize mnemonic JNE to "jnz" + cs_opt_mnem my_mnem = { X86_INS_JNE, "jnz" }; + // Set .mnemonic to NULL to reset to default mnemonic + cs_opt_mnem default_mnem = { X86_INS_JNE, NULL }; + + err = cs_open(CS_ARCH_X86, CS_MODE_32, &handle); + if (err) { + printf("Failed on cs_open() with error returned: %u\n", err); + abort(); + } + + // 1. Print out the instruction in default setup. + printf("Disassemble X86 code with default instruction mnemonic\n"); + print_insn(handle); + + // Customized mnemonic JNE to JNZ using CS_OPT_MNEMONIC option + printf("\nNow customize engine to change mnemonic from 'JNE' to 'JNZ'\n"); + cs_option(handle, CS_OPT_MNEMONIC, (size_t)&my_mnem); + + // 2. Now print out the instruction in newly customized setup. + print_insn(handle); + + // Reset engine to use the default mnemonic of JNE + printf("\nReset engine to use the default mnemonic\n"); + cs_option(handle, CS_OPT_MNEMONIC, (size_t)&default_mnem); + + // 3. Now print out the instruction in default setup. + print_insn(handle); + + // Done + cs_close(&handle); +} + +int main() +{ + test(); + + return 0; +} diff --git a/capstone/tests/test_detail.c b/capstone/tests/test_detail.c new file mode 100644 index 000000000..ea7d1fdd1 --- /dev/null +++ b/capstone/tests/test_detail.c @@ -0,0 +1,374 @@ +/* Capstone Disassembler Engine */ +/* By Nguyen Anh Quynh <aquynh@gmail.com>, 2013-2019 */ + +#include <stdio.h> +#include <stdlib.h> + +#include <capstone/platform.h> +#include <capstone/capstone.h> + +struct platform { + cs_arch arch; + cs_mode mode; + unsigned char *code; + size_t size; + const char *comment; + cs_opt_type opt_type; + cs_opt_value opt_value; +}; + +static void print_string_hex(unsigned char *str, size_t len) +{ + unsigned char *c; + + printf("Code: "); + for (c = str; c < str + len; c++) { + printf("0x%02x ", *c & 0xff); + } + printf("\n"); +} + +static void test() +{ +#ifdef CAPSTONE_HAS_X86 +#define X86_CODE16 "\x8d\x4c\x32\x08\x01\xd8\x81\xc6\x34\x12\x00\x00" +#define X86_CODE32 "\x8d\x4c\x32\x08\x01\xd8\x81\xc6\x34\x12\x00\x00" +#define X86_CODE64 "\x55\x48\x8b\x05\xb8\x13\x00\x00" +#endif +#ifdef CAPSTONE_HAS_ARM +#define ARM_CODE "\xED\xFF\xFF\xEB\x04\xe0\x2d\xe5\x00\x00\x00\x00\xe0\x83\x22\xe5\xf1\x02\x03\x0e\x00\x00\xa0\xe3\x02\x30\xc1\xe7\x00\x00\x53\xe3" +#define ARM_CODE2 "\x10\xf1\x10\xe7\x11\xf2\x31\xe7\xdc\xa1\x2e\xf3\xe8\x4e\x62\xf3" +#define THUMB_CODE "\x70\x47\xeb\x46\x83\xb0\xc9\x68" +#define THUMB_CODE2 "\x4f\xf0\x00\x01\xbd\xe8\x00\x88\xd1\xe8\x00\xf0" +#define THUMB_MCLASS "\xef\xf3\x02\x80" +#define ARMV8 "\xe0\x3b\xb2\xee\x42\x00\x01\xe1\x51\xf0\x7f\xf5" +#endif +#ifdef CAPSTONE_HAS_MIPS +#define MIPS_CODE "\x0C\x10\x00\x97\x00\x00\x00\x00\x24\x02\x00\x0c\x8f\xa2\x00\x00\x34\x21\x34\x56\x00\x80\x04\x08" +#define MIPS_CODE2 "\x56\x34\x21\x34\xc2\x17\x01\x00" +#define MIPS_32R6M "\x00\x07\x00\x07\x00\x11\x93\x7c\x01\x8c\x8b\x7c\x00\xc7\x48\xd0" +#define MIPS_32R6 "\xec\x80\x00\x19\x7c\x43\x22\xa0" +#endif +#ifdef CAPSTONE_HAS_ARM64 +#define ARM64_CODE "\x09\x00\x38\xd5\xbf\x40\x00\xd5\x0c\x05\x13\xd5\x20\x50\x02\x0e\x20\xe4\x3d\x0f\x00\x18\xa0\x5f\xa2\x00\xae\x9e\x9f\x37\x03\xd5\xbf\x33\x03\xd5\xdf\x3f\x03\xd5\x21\x7c\x02\x9b\x21\x7c\x00\x53\x00\x40\x21\x4b\xe1\x0b\x40\xb9\x20\x04\x81\xda\x20\x08\x02\x8b\x10\x5b\xe8\x3c" +#endif +#ifdef CAPSTONE_HAS_POWERPC +#define PPC_CODE "\x80\x20\x00\x00\x80\x3f\x00\x00\x10\x43\x23\x0e\xd0\x44\x00\x80\x4c\x43\x22\x02\x2d\x03\x00\x80\x7c\x43\x20\x14\x7c\x43\x20\x93\x4f\x20\x00\x21\x4c\xc8\x00\x21\x40\x82\x00\x14" +#define PPC_CODE2 "\x10\x60\x2a\x10\x10\x64\x28\x88\x7c\x4a\x5d\x0f" +#endif +#ifdef CAPSTONE_HAS_SPARC +#define SPARC_CODE "\x80\xa0\x40\x02\x85\xc2\x60\x08\x85\xe8\x20\x01\x81\xe8\x00\x00\x90\x10\x20\x01\xd5\xf6\x10\x16\x21\x00\x00\x0a\x86\x00\x40\x02\x01\x00\x00\x00\x12\xbf\xff\xff\x10\xbf\xff\xff\xa0\x02\x00\x09\x0d\xbf\xff\xff\xd4\x20\x60\x00\xd4\x4e\x00\x16\x2a\xc2\x80\x03" +#define SPARCV9_CODE "\x81\xa8\x0a\x24\x89\xa0\x10\x20\x89\xa0\x1a\x60\x89\xa0\x00\xe0" +#endif +#ifdef CAPSTONE_HAS_SYSZ +#define SYSZ_CODE "\xed\x00\x00\x00\x00\x1a\x5a\x0f\x1f\xff\xc2\x09\x80\x00\x00\x00\x07\xf7\xeb\x2a\xff\xff\x7f\x57\xe3\x01\xff\xff\x7f\x57\xeb\x00\xf0\x00\x00\x24\xb2\x4f\x00\x78" +#endif +#ifdef CAPSTONE_HAS_XCORE +#define XCORE_CODE "\xfe\x0f\xfe\x17\x13\x17\xc6\xfe\xec\x17\x97\xf8\xec\x4f\x1f\xfd\xec\x37\x07\xf2\x45\x5b\xf9\xfa\x02\x06\x1b\x10" +#endif +#ifdef CAPSTONE_HAS_M68K +#define M68K_CODE "\xd4\x40\x87\x5a\x4e\x71\x02\xb4\xc0\xde\xc0\xde\x5c\x00\x1d\x80\x71\x12\x01\x23\xf2\x3c\x44\x22\x40\x49\x0e\x56\x54\xc5\xf2\x3c\x44\x00\x44\x7a\x00\x00\xf2\x00\x0a\x28" +#endif +#ifdef CAPSTONE_HAS_M680X +#define M680X_CODE "\x06\x10\x19\x1a\x55\x1e\x01\x23\xe9\x31\x06\x34\x55\xa6\x81\xa7\x89\x7f\xff\xa6\x9d\x10\x00\xa7\x91\xa6\x9f\x10\x00\x11\xac\x99\x10\x00\x39" +#endif +#ifdef CAPSTONE_HAS_MOS65XX +#define MOS65XX_CODE "\x0A\x00\xFE\x34\x12\xD0\xFF\xEA\x19\x56\x34\x46\x80" +#endif +#define EBPF_CODE "\x97\x09\x00\x00\x37\x13\x03\x00\xdc\x02\x00\x00\x20\x00\x00\x00\x30\x00\x00\x00\x00\x00\x00\x00\xdb\x3a\x00\x01\x00\x00\x00\x00\x84\x02\x00\x00\x00\x00\x00\x00\x6d\x33\x17\x02\x00\x00\x00\x00" + + struct platform platforms[] = { +#ifdef CAPSTONE_HAS_X86 + { + CS_ARCH_X86, + CS_MODE_16, + (unsigned char *)X86_CODE16, + sizeof(X86_CODE16) - 1, + "X86 16bit (Intel syntax)" + }, + { + CS_ARCH_X86, + CS_MODE_32, + (unsigned char *)X86_CODE32, + sizeof(X86_CODE32) - 1, + "X86 32bit (ATT syntax)", + CS_OPT_SYNTAX, + CS_OPT_SYNTAX_ATT, + }, + { + CS_ARCH_X86, + CS_MODE_32, + (unsigned char *)X86_CODE32, + sizeof(X86_CODE32) - 1, + "X86 32 (Intel syntax)" + }, + { + CS_ARCH_X86, + CS_MODE_64, + (unsigned char *)X86_CODE64, + sizeof(X86_CODE64) - 1, + "X86 64 (Intel syntax)" + }, +#endif +#ifdef CAPSTONE_HAS_ARM + { + CS_ARCH_ARM, + CS_MODE_ARM, + (unsigned char *)ARM_CODE, + sizeof(ARM_CODE) - 1, + "ARM" + }, + { + CS_ARCH_ARM, + CS_MODE_THUMB, + (unsigned char *)THUMB_CODE2, + sizeof(THUMB_CODE2) - 1, + "THUMB-2" + }, + { + CS_ARCH_ARM, + CS_MODE_ARM, + (unsigned char *)ARM_CODE2, + sizeof(ARM_CODE2) - 1, + "ARM: Cortex-A15 + NEON" + }, + { + CS_ARCH_ARM, + CS_MODE_THUMB, + (unsigned char *)THUMB_CODE, + sizeof(THUMB_CODE) - 1, + "THUMB" + }, + { + CS_ARCH_ARM, + (cs_mode)(CS_MODE_THUMB + CS_MODE_MCLASS), + (unsigned char*)THUMB_MCLASS, + sizeof(THUMB_MCLASS) - 1, + "Thumb-MClass" + }, + { + CS_ARCH_ARM, + (cs_mode)(CS_MODE_ARM + CS_MODE_V8), + (unsigned char*)ARMV8, + sizeof(ARMV8) - 1, + "Arm-V8" + }, +#endif +#ifdef CAPSTONE_HAS_MIPS + { + CS_ARCH_MIPS, + (cs_mode)(CS_MODE_MIPS32 + CS_MODE_BIG_ENDIAN), + (unsigned char *)MIPS_CODE, + sizeof(MIPS_CODE) - 1, + "MIPS-32 (Big-endian)" + }, + { + CS_ARCH_MIPS, + (cs_mode)(CS_MODE_MIPS64 + CS_MODE_LITTLE_ENDIAN), + (unsigned char *)MIPS_CODE2, + sizeof(MIPS_CODE2) - 1, + "MIPS-64-EL (Little-endian)" + }, + { + CS_ARCH_MIPS, + (cs_mode)(CS_MODE_MIPS32R6 + CS_MODE_MICRO + CS_MODE_BIG_ENDIAN), + (unsigned char*)MIPS_32R6M, + sizeof(MIPS_32R6M) - 1, + "MIPS-32R6 | Micro (Big-endian)" + }, + { + CS_ARCH_MIPS, + (cs_mode)(CS_MODE_MIPS32R6 + CS_MODE_BIG_ENDIAN), + (unsigned char*)MIPS_32R6, + sizeof(MIPS_32R6) - 1, + "MIPS-32R6 (Big-endian)" + }, +#endif +#ifdef CAPSTONE_HAS_ARM64 + { + CS_ARCH_ARM64, + CS_MODE_ARM, + (unsigned char *)ARM64_CODE, + sizeof(ARM64_CODE) - 1, + "ARM-64" + }, +#endif +#ifdef CAPSTONE_HAS_POWERPC + { + CS_ARCH_PPC, + CS_MODE_BIG_ENDIAN, + (unsigned char*)PPC_CODE, + sizeof(PPC_CODE) - 1, + "PPC-64" + }, + { + CS_ARCH_PPC, + CS_MODE_BIG_ENDIAN + CS_MODE_QPX, + (unsigned char*)PPC_CODE2, + sizeof(PPC_CODE2) - 1, + "PPC-64 + QPX", + }, +#endif +#ifdef CAPSTONE_HAS_SPARC + { + CS_ARCH_SPARC, + CS_MODE_BIG_ENDIAN, + (unsigned char*)SPARC_CODE, + sizeof(SPARC_CODE) - 1, + "Sparc" + }, + { + CS_ARCH_SPARC, + (cs_mode)(CS_MODE_BIG_ENDIAN + CS_MODE_V9), + (unsigned char*)SPARCV9_CODE, + sizeof(SPARCV9_CODE) - 1, + "SparcV9" + }, +#endif +#ifdef CAPSTONE_HAS_SYSZ + { + CS_ARCH_SYSZ, + (cs_mode)0, + (unsigned char*)SYSZ_CODE, + sizeof(SYSZ_CODE) - 1, + "SystemZ" + }, +#endif +#ifdef CAPSTONE_HAS_XCORE + { + CS_ARCH_XCORE, + (cs_mode)0, + (unsigned char*)XCORE_CODE, + sizeof(XCORE_CODE) - 1, + "XCore" + }, +#endif +#ifdef CAPSTONE_HAS_M68K + { + CS_ARCH_M68K, + (cs_mode)(CS_MODE_BIG_ENDIAN | CS_MODE_M68K_040), + (unsigned char*)M68K_CODE, + sizeof(M68K_CODE) - 1, + "M68K", + }, +#endif +#ifdef CAPSTONE_HAS_M680X + { + CS_ARCH_M680X, + (cs_mode)(CS_MODE_M680X_6809), + (unsigned char*)M680X_CODE, + sizeof(M680X_CODE) - 1, + "M680X_M6809", + }, +#endif +#ifdef CAPSTONE_HAS_MOS65XX + { + CS_ARCH_MOS65XX, + (cs_mode)0, + (unsigned char*)MOS65XX_CODE, + sizeof(MOS65XX_CODE) - 1, + "MOS65XX", + }, +#endif +#ifdef CAPSTONE_HAS_BPF + { + CS_ARCH_BPF, + CS_MODE_LITTLE_ENDIAN | CS_MODE_BPF_EXTENDED, + (unsigned char*) EBPF_CODE, + sizeof(EBPF_CODE) - 1, + "eBPF" + }, +#endif + }; + + csh handle; + uint64_t address = 0x1000; + cs_insn *all_insn; + cs_detail *detail; + int i; + size_t count; + cs_err err; + + for (i = 0; i < sizeof(platforms)/sizeof(platforms[0]); i++) { + printf("****************\n"); + printf("Platform: %s\n", platforms[i].comment); + err = cs_open(platforms[i].arch, platforms[i].mode, &handle); + if (err) { + printf("Failed on cs_open() with error returned: %u\n", err); + abort(); + } + + if (platforms[i].opt_type) + cs_option(handle, platforms[i].opt_type, platforms[i].opt_value); + + cs_option(handle, CS_OPT_DETAIL, CS_OPT_ON); + + count = cs_disasm(handle, platforms[i].code, platforms[i].size, address, 0, &all_insn); + if (count) { + size_t j; + int n; + + print_string_hex(platforms[i].code, platforms[i].size); + printf("Disasm:\n"); + + for (j = 0; j < count; j++) { + cs_insn *in = &(all_insn[j]); + printf("0x%" PRIx64 ":\t%s\t\t%s // insn-ID: %u, insn-mnem: %s\n", + in->address, in->mnemonic, in->op_str, + in->id, cs_insn_name(handle, in->id)); + + // print implicit registers used by this instruction + detail = in->detail; + + if (detail->regs_read_count > 0) { + printf("\tImplicit registers read: "); + for (n = 0; n < detail->regs_read_count; n++) { + printf("%s ", cs_reg_name(handle, detail->regs_read[n])); + } + printf("\n"); + } + + // print implicit registers modified by this instruction + if (detail->regs_write_count > 0) { + printf("\tImplicit registers modified: "); + for (n = 0; n < detail->regs_write_count; n++) { + printf("%s ", cs_reg_name(handle, detail->regs_write[n])); + } + printf("\n"); + } + + // print the groups this instruction belong to + if (detail->groups_count > 0) { + printf("\tThis instruction belongs to groups: "); + for (n = 0; n < detail->groups_count; n++) { + printf("%s ", cs_group_name(handle, detail->groups[n])); + } + printf("\n"); + } + } + + // print out the next offset, after the last insn + printf("0x%" PRIx64 ":\n", all_insn[j-1].address + all_insn[j-1].size); + + // free memory allocated by cs_disasm() + cs_free(all_insn, count); + } else { + printf("****************\n"); + printf("Platform: %s\n", platforms[i].comment); + print_string_hex(platforms[i].code, platforms[i].size); + printf("ERROR: Failed to disasm given code!\n"); + abort(); + } + + printf("\n"); + + cs_close(&handle); + } +} + +int main() +{ + test(); + + return 0; +} diff --git a/capstone/tests/test_evm.c b/capstone/tests/test_evm.c new file mode 100644 index 000000000..7fd0aa30f --- /dev/null +++ b/capstone/tests/test_evm.c @@ -0,0 +1,126 @@ +/* Capstone Disassembler Engine */ +/* By Nguyen Anh Quynh <aquynh@gmail.com>, 2018-2019 */ + +#include <stdio.h> +#include <stdlib.h> + +#include <capstone/platform.h> +#include <capstone/capstone.h> + +static csh handle; + +struct platform { + cs_arch arch; + cs_mode mode; + unsigned char *code; + size_t size; + const char *comment; +}; + +static 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"); +} + +static void print_insn_detail(csh cs_handle, cs_insn *ins) +{ + cs_evm *evm; + + // detail can be NULL on "data" instruction if SKIPDATA option is turned ON + if (ins->detail == NULL) + return; + + evm = &(ins->detail->evm); + + if (evm->pop) + printf("\tPop: %u\n", evm->pop); + + if (evm->push) + printf("\tPush: %u\n", evm->push); + + if (evm->fee) + printf("\tGas fee: %u\n", evm->fee); + + 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"); + } +} + +static void test() +{ +#define EVM_CODE "\x60\x61\x50" + + struct platform platforms[] = { + { + CS_ARCH_EVM, + 0, + (unsigned char *)EVM_CODE, + sizeof(EVM_CODE) - 1, + "EVM" + }, + }; + + uint64_t address = 0x80001000; + cs_insn *insn; + int i; + size_t count; + + for (i = 0; i < sizeof(platforms)/sizeof(platforms[0]); i++) { + cs_err err = cs_open(platforms[i].arch, platforms[i].mode, &handle); + if (err) { + printf("Failed on cs_open() with error returned: %u\n", err); + abort(); + } + + cs_option(handle, CS_OPT_DETAIL, CS_OPT_ON); + + count = cs_disasm(handle, platforms[i].code, platforms[i].size, address, 0, &insn); + if (count) { + size_t j; + printf("****************\n"); + printf("Platform: %s\n", platforms[i].comment); + print_string_hex("Code:", platforms[i].code, platforms[i].size); + printf("Disasm:\n"); + + for (j = 0; j < count; j++) { + printf("0x%" PRIx64 ":\t%s\t%s\n", insn[j].address, insn[j].mnemonic, insn[j].op_str); + print_insn_detail(handle, &insn[j]); + } + printf("0x%" PRIx64 ":\n", insn[j-1].address + insn[j-1].size); + + // free memory allocated by cs_disasm() + cs_free(insn, count); + } else { + printf("****************\n"); + printf("Platform: %s\n", platforms[i].comment); + print_string_hex("Code:", platforms[i].code, platforms[i].size); + printf("ERROR: Failed to disasm given code!\n"); + abort(); + } + + printf("\n"); + + cs_close(&handle); + } +} + +int main() +{ + test(); + + return 0; +} + diff --git a/capstone/tests/test_iter.c b/capstone/tests/test_iter.c new file mode 100644 index 000000000..e3edfb0c8 --- /dev/null +++ b/capstone/tests/test_iter.c @@ -0,0 +1,337 @@ +/* Capstone Disassembler Engine */ +/* By Nguyen Anh Quynh <aquynh@gmail.com>, 2013-2019 */ + +// This sample code demonstrates the APIs cs_malloc() & cs_disasm_iter(). +#include <stdio.h> +#include <stdlib.h> + +#include <capstone/platform.h> +#include <capstone/capstone.h> + +struct platform { + cs_arch arch; + cs_mode mode; + unsigned char *code; + size_t size; + const char *comment; + cs_opt_type opt_type; + cs_opt_value opt_value; +}; + +static void print_string_hex(unsigned char *str, size_t len) +{ + unsigned char *c; + + printf("Code: "); + for (c = str; c < str + len; c++) { + printf("0x%02x ", *c & 0xff); + } + printf("\n"); +} + +static void test() +{ +#ifdef CAPSTONE_HAS_X86 +#define X86_CODE16 "\x8d\x4c\x32\x08\x01\xd8\x81\xc6\x34\x12\x00\x00" +#define X86_CODE32 "\x8d\x4c\x32\x08\x01\xd8\x81\xc6\x34\x12\x00\x00" +#define X86_CODE64 "\x55\x48\x8b\x05\xb8\x13\x00\x00" +#endif +#ifdef CAPSTONE_HAS_ARM +#define ARM_CODE "\xED\xFF\xFF\xEB\x04\xe0\x2d\xe5\x00\x00\x00\x00\xe0\x83\x22\xe5\xf1\x02\x03\x0e\x00\x00\xa0\xe3\x02\x30\xc1\xe7\x00\x00\x53\xe3" +#define ARM_CODE2 "\x10\xf1\x10\xe7\x11\xf2\x31\xe7\xdc\xa1\x2e\xf3\xe8\x4e\x62\xf3" +#define THUMB_CODE "\x70\x47\xeb\x46\x83\xb0\xc9\x68" +#define THUMB_CODE2 "\x4f\xf0\x00\x01\xbd\xe8\x00\x88\xd1\xe8\x00\xf0" +#endif +#ifdef CAPSTONE_HAS_MIPS +#define MIPS_CODE "\x0C\x10\x00\x97\x00\x00\x00\x00\x24\x02\x00\x0c\x8f\xa2\x00\x00\x34\x21\x34\x56\x00\x80\x04\x08" +#define MIPS_CODE2 "\x56\x34\x21\x34\xc2\x17\x01\x00" +#endif +#ifdef CAPSTONE_HAS_ARM64 +#define ARM64_CODE "\x09\x00\x38\xd5\xbf\x40\x00\xd5\x0c\x05\x13\xd5\x20\x50\x02\x0e\x20\xe4\x3d\x0f\x00\x18\xa0\x5f\xa2\x00\xae\x9e\x9f\x37\x03\xd5\xbf\x33\x03\xd5\xdf\x3f\x03\xd5\x21\x7c\x02\x9b\x21\x7c\x00\x53\x00\x40\x21\x4b\xe1\x0b\x40\xb9\x20\x04\x81\xda\x20\x08\x02\x8b\x10\x5b\xe8\x3c" +#endif +#ifdef CAPSTONE_HAS_POWERPC +#define PPC_CODE "\x80\x20\x00\x00\x80\x3f\x00\x00\x10\x43\x23\x0e\xd0\x44\x00\x80\x4c\x43\x22\x02\x2d\x03\x00\x80\x7c\x43\x20\x14\x7c\x43\x20\x93\x4f\x20\x00\x21\x4c\xc8\x00\x21\x40\x82\x00\x14" +#endif +#ifdef CAPSTONE_HAS_SPARC +#define SPARC_CODE "\x80\xa0\x40\x02\x85\xc2\x60\x08\x85\xe8\x20\x01\x81\xe8\x00\x00\x90\x10\x20\x01\xd5\xf6\x10\x16\x21\x00\x00\x0a\x86\x00\x40\x02\x01\x00\x00\x00\x12\xbf\xff\xff\x10\xbf\xff\xff\xa0\x02\x00\x09\x0d\xbf\xff\xff\xd4\x20\x60\x00\xd4\x4e\x00\x16\x2a\xc2\x80\x03" +#define SPARCV9_CODE "\x81\xa8\x0a\x24\x89\xa0\x10\x20\x89\xa0\x1a\x60\x89\xa0\x00\xe0" +#endif +#ifdef CAPSTONE_HAS_SYSZ +#define SYSZ_CODE "\xed\x00\x00\x00\x00\x1a\x5a\x0f\x1f\xff\xc2\x09\x80\x00\x00\x00\x07\xf7\xeb\x2a\xff\xff\x7f\x57\xe3\x01\xff\xff\x7f\x57\xeb\x00\xf0\x00\x00\x24\xb2\x4f\x00\x78" +#endif +#ifdef CAPSTONE_HAS_XCORE +#define XCORE_CODE "\xfe\x0f\xfe\x17\x13\x17\xc6\xfe\xec\x17\x97\xf8\xec\x4f\x1f\xfd\xec\x37\x07\xf2\x45\x5b\xf9\xfa\x02\x06\x1b\x10" +#endif +#ifdef CAPSTONE_HAS_M680X +#define M680X_CODE "\x06\x10\x19\x1a\x55\x1e\x01\x23\xe9\x31\x06\x34\x55\xa6\x81\xa7\x89\x7f\xff\xa6\x9d\x10\x00\xa7\x91\xa6\x9f\x10\x00\x11\xac\x99\x10\x00\x39" +#endif +#ifdef CAPSTONE_HAS_MOS65XX +#define MOS65XX_CODE "\x0d\x34\x12\x08\x09\xFF\x10\x80\x20\x00\x00\x98" +#endif +#define EBPF_CODE "\x97\x09\x00\x00\x37\x13\x03\x00\xdc\x02\x00\x00\x20\x00\x00\x00\x30\x00\x00\x00\x00\x00\x00\x00\xdb\x3a\x00\x01\x00\x00\x00\x00\x84\x02\x00\x00\x00\x00\x00\x00\x6d\x33\x17\x02\x00\x00\x00\x00" + +#ifdef CAPSTONE_HAS_RISCV +#define RISCV_CODE32 "\x37\x34\x00\x00\x97\x82\x00\x00\xef\x00\x80\x00\xef\xf0\x1f\xff\xe7\x00\x45\x00\xe7\x00\xc0\xff\x63\x05\x41\x00\xe3\x9d\x61\xfe\x63\xca\x93\x00\x63\x53\xb5\x00\x63\x65\xd6\x00\x63\x76\xf7\x00\x03\x88\x18\x00\x03\x99\x49\x00\x03\xaa\x6a\x00\x03\xcb\x2b\x01\x03\xdc\x8c\x01\x23\x86\xad\x03\x23\x9a\xce\x03\x23\x8f\xef\x01\x93\x00\xe0\x00\x13\xa1\x01\x01\x13\xb2\x02\x7d\x13\xc3\x03\xdd\x13\xe4\xc4\x12\x13\xf5\x85\x0c\x13\x96\xe6\x01\x13\xd7\x97\x01\x13\xd8\xf8\x40\x33\x89\x49\x01\xb3\x0a\x7b\x41\x33\xac\xac\x01\xb3\x3d\xde\x01\x33\xd2\x62\x40\xb3\x43\x94\x00\x33\xe5\xc5\x00\xb3\x76\xf7\x00\xb3\x54\x39\x01\xb3\x50\x31\x00\x33\x9f\x0f\x00" +#define RISCV_CODE64 "\x13\x04\xa8\x7a" // aaa80413 +#endif + +struct platform platforms[] = { +#ifdef CAPSTONE_HAS_X86 + { + CS_ARCH_X86, + CS_MODE_16, + (unsigned char *)X86_CODE16, + sizeof(X86_CODE32) - 1, + "X86 16bit (Intel syntax)" + }, + { + CS_ARCH_X86, + CS_MODE_32, + (unsigned char *)X86_CODE32, + sizeof(X86_CODE32) - 1, + "X86 32bit (ATT syntax)", + CS_OPT_SYNTAX, + CS_OPT_SYNTAX_ATT, + }, + { + CS_ARCH_X86, + CS_MODE_32, + (unsigned char *)X86_CODE32, + sizeof(X86_CODE32) - 1, + "X86 32 (Intel syntax)" + }, + { + CS_ARCH_X86, + CS_MODE_64, + (unsigned char *)X86_CODE64, + sizeof(X86_CODE64) - 1, + "X86 64 (Intel syntax)" + }, +#endif +#ifdef CAPSTONE_HAS_ARM + { + CS_ARCH_ARM, + CS_MODE_ARM, + (unsigned char *)ARM_CODE, + sizeof(ARM_CODE) - 1, + "ARM" + }, + { + CS_ARCH_ARM, + CS_MODE_THUMB, + (unsigned char *)THUMB_CODE2, + sizeof(THUMB_CODE2) - 1, + "THUMB-2" + }, + { + CS_ARCH_ARM, + CS_MODE_ARM, + (unsigned char *)ARM_CODE2, + sizeof(ARM_CODE2) - 1, + "ARM: Cortex-A15 + NEON" + }, + { + CS_ARCH_ARM, + CS_MODE_THUMB, + (unsigned char *)THUMB_CODE, + sizeof(THUMB_CODE) - 1, + "THUMB" + }, +#endif +#ifdef CAPSTONE_HAS_MIPS + { + CS_ARCH_MIPS, + (cs_mode)(CS_MODE_MIPS32 + CS_MODE_BIG_ENDIAN), + (unsigned char *)MIPS_CODE, + sizeof(MIPS_CODE) - 1, + "MIPS-32 (Big-endian)" + }, + { + CS_ARCH_MIPS, + (cs_mode)(CS_MODE_MIPS64 + CS_MODE_LITTLE_ENDIAN), + (unsigned char *)MIPS_CODE2, + sizeof(MIPS_CODE2) - 1, + "MIPS-64-EL (Little-endian)" + }, +#endif +#ifdef CAPSTONE_HAS_ARM64 + { + CS_ARCH_ARM64, + CS_MODE_ARM, + (unsigned char *)ARM64_CODE, + sizeof(ARM64_CODE) - 1, + "ARM-64" + }, +#endif +#ifdef CAPSTONE_HAS_POWERPC + { + CS_ARCH_PPC, + CS_MODE_BIG_ENDIAN, + (unsigned char*)PPC_CODE, + sizeof(PPC_CODE) - 1, + "PPC-64" + }, +#endif +#ifdef CAPSTONE_HAS_SPARC + { + CS_ARCH_SPARC, + CS_MODE_BIG_ENDIAN, + (unsigned char*)SPARC_CODE, + sizeof(SPARC_CODE) - 1, + "Sparc" + }, + { + CS_ARCH_SPARC, + (cs_mode)(CS_MODE_BIG_ENDIAN + CS_MODE_V9), + (unsigned char*)SPARCV9_CODE, + sizeof(SPARCV9_CODE) - 1, + "SparcV9" + }, +#endif +#ifdef CAPSTONE_HAS_SYSZ + { + CS_ARCH_SYSZ, + (cs_mode)0, + (unsigned char*)SYSZ_CODE, + sizeof(SYSZ_CODE) - 1, + "SystemZ" + }, +#endif +#ifdef CAPSTONE_HAS_XCORE + { + CS_ARCH_XCORE, + (cs_mode)0, + (unsigned char*)XCORE_CODE, + sizeof(XCORE_CODE) - 1, + "XCore" + }, +#endif +#ifdef CAPSTONE_HAS_M680X + { + CS_ARCH_M680X, + (cs_mode)CS_MODE_M680X_6809, + (unsigned char*)M680X_CODE, + sizeof(M680X_CODE) - 1, + "M680X_6809" + }, +#endif +#ifdef CAPSTONE_HAS_MOS65XX + { + CS_ARCH_MOS65XX, + (cs_mode)CS_MODE_LITTLE_ENDIAN, + (unsigned char*)MOS65XX_CODE, + sizeof(MOS65XX_CODE) - 1, + "MOS65XX" + }, +#endif +#ifdef CAPSTONE_HAS_BPF + { + CS_ARCH_BPF, + CS_MODE_LITTLE_ENDIAN | CS_MODE_BPF_EXTENDED, + (unsigned char*) EBPF_CODE, + sizeof(EBPF_CODE) - 1, + "eBPF" + }, +#endif +#ifdef CAPSTONE_HAS_RISCV + { + CS_ARCH_RISCV, + CS_MODE_RISCV32, + (unsigned char *)RISCV_CODE32, + sizeof(RISCV_CODE32) - 1, + "RISCV32" + }, + { + CS_ARCH_RISCV, + CS_MODE_RISCV64, + (unsigned char *)RISCV_CODE64, + sizeof(RISCV_CODE64) - 1, + "RISCV64" + }, +#endif + }; + + csh handle; + uint64_t address; + cs_insn *insn; + cs_detail *detail; + int i; + cs_err err; + const uint8_t *code; + size_t size; + + for (i = 0; i < sizeof(platforms)/sizeof(platforms[0]); i++) { + printf("****************\n"); + printf("Platform: %s\n", platforms[i].comment); + err = cs_open(platforms[i].arch, platforms[i].mode, &handle); + if (err) { + printf("Failed on cs_open() with error returned: %u\n", err); + abort(); + } + + if (platforms[i].opt_type) + cs_option(handle, platforms[i].opt_type, platforms[i].opt_value); + + cs_option(handle, CS_OPT_DETAIL, CS_OPT_ON); + + // allocate memory for the cache to be used by cs_disasm_iter() + insn = cs_malloc(handle); + + print_string_hex(platforms[i].code, platforms[i].size); + printf("Disasm:\n"); + + address = 0x1000; + code = platforms[i].code; + size = platforms[i].size; + while(cs_disasm_iter(handle, &code, &size, &address, insn)) { + int n; + + printf("0x%" PRIx64 ":\t%s\t\t%s // insn-ID: %u, insn-mnem: %s\n", + insn->address, insn->mnemonic, insn->op_str, + insn->id, cs_insn_name(handle, insn->id)); + + // print implicit registers used by this instruction + detail = insn->detail; + + if (detail->regs_read_count > 0) { + printf("\tImplicit registers read: "); + for (n = 0; n < detail->regs_read_count; n++) { + printf("%s ", cs_reg_name(handle, detail->regs_read[n])); + } + printf("\n"); + } + + // print implicit registers modified by this instruction + if (detail->regs_write_count > 0) { + printf("\tImplicit registers modified: "); + for (n = 0; n < detail->regs_write_count; n++) { + printf("%s ", cs_reg_name(handle, detail->regs_write[n])); + } + printf("\n"); + } + + // print the groups this instruction belong to + if (detail->groups_count > 0) { + printf("\tThis instruction belongs to groups: "); + for (n = 0; n < detail->groups_count; n++) { + printf("%s ", cs_group_name(handle, detail->groups[n])); + } + printf("\n"); + } + } + + printf("\n"); + + // free memory allocated by cs_malloc() + cs_free(insn, 1); + + cs_close(&handle); + } +} + +int main() +{ + test(); + + return 0; +} diff --git a/capstone/tests/test_m680x.c b/capstone/tests/test_m680x.c new file mode 100644 index 000000000..aa1f57272 --- /dev/null +++ b/capstone/tests/test_m680x.c @@ -0,0 +1,396 @@ +/* Capstone Disassembler Engine */ +/* M680X Backend by Wolfgang Schwotzer <wolfgang.schwotzer@gmx.net> 2017 */ + +#include <stdio.h> +#include <string.h> + +#include <capstone/platform.h> +#include <capstone/capstone.h> + +#define WITH_DETAILS + +struct platform { + cs_arch arch; + cs_mode mode; + unsigned char *code; + size_t size; + const char *comment; +}; + +static 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"); +} + +static void print_string_hex_short(unsigned char *str, size_t len) +{ + unsigned char *c; + + for (c = str; c < str + len; c++) + printf("%02x", *c & 0xff); +} + +static const char *s_access[] = { + "UNCHANGED", "READ", "WRITE", "READ | WRITE", +}; + +static void print_read_write_regs(csh handle, cs_detail *detail) +{ + int i; + + if (detail->regs_read_count > 0) { + printf("\tRegisters read:"); + + for (i = 0; i < detail->regs_read_count; ++i) + printf(" %s", + cs_reg_name(handle, detail->regs_read[i])); + + printf("\n"); + } + + if (detail->regs_write_count > 0) { + printf("\tRegisters modified:"); + + for (i = 0; i < detail->regs_write_count; ++i) + printf(" %s", + cs_reg_name(handle, detail->regs_write[i])); + + printf("\n"); + } +} + +static void print_insn_detail(csh handle, cs_insn *insn) +{ + cs_detail *detail = insn->detail; + cs_m680x *m680x = NULL; + int i; + + // detail can be NULL on "data" instruction if SKIPDATA option is turned ON + if (detail == NULL) + return; + + m680x = &detail->m680x; + + if (m680x->op_count) + printf("\top_count: %u\n", m680x->op_count); + + for (i = 0; i < m680x->op_count; i++) { + cs_m680x_op *op = &(m680x->operands[i]); + const char *comment; + + switch ((int)op->type) { + default: + break; + + case M680X_OP_REGISTER: + comment = ""; + + if ((i == 0 && (m680x->flags & + M680X_FIRST_OP_IN_MNEM)) || + ((i == 1 && (m680x->flags & + M680X_SECOND_OP_IN_MNEM)))) + comment = " (in mnemonic)"; + + printf("\t\toperands[%u].type: REGISTER = %s%s\n", i, + cs_reg_name(handle, op->reg), comment); + break; + + case M680X_OP_CONSTANT: + printf("\t\toperands[%u].type: CONSTANT = %u\n", i, + op->const_val); + break; + + case M680X_OP_IMMEDIATE: + printf("\t\toperands[%u].type: IMMEDIATE = #%d\n", i, + op->imm); + break; + + case M680X_OP_DIRECT: + printf("\t\toperands[%u].type: DIRECT = 0x%02x\n", i, + op->direct_addr); + break; + + case M680X_OP_EXTENDED: + printf("\t\toperands[%u].type: EXTENDED %s = 0x%04x\n", + i, op->ext.indirect ? "INDIRECT" : "", + op->ext.address); + break; + + case M680X_OP_RELATIVE: + printf("\t\toperands[%u].type: RELATIVE = 0x%04x\n", i, + op->rel.address); + break; + + case M680X_OP_INDEXED: + printf("\t\toperands[%u].type: INDEXED%s\n", i, + (op->idx.flags & M680X_IDX_INDIRECT) ? + " INDIRECT" : ""); + + if (op->idx.base_reg != M680X_REG_INVALID) + printf("\t\t\tbase register: %s\n", + cs_reg_name(handle, op->idx.base_reg)); + + if (op->idx.offset_reg != M680X_REG_INVALID) + printf("\t\t\toffset register: %s\n", + cs_reg_name(handle, op->idx.offset_reg)); + + if ((op->idx.offset_bits != 0) && + (op->idx.offset_reg == M680X_REG_INVALID) && + !op->idx.inc_dec) { + printf("\t\t\toffset: %d\n", op->idx.offset); + + if (op->idx.base_reg == M680X_REG_PC) + printf("\t\t\toffset address: 0x%x\n", + op->idx.offset_addr); + + printf("\t\t\toffset bits: %u\n", + op->idx.offset_bits); + } + + if (op->idx.inc_dec) { + const char *post_pre = op->idx.flags & + M680X_IDX_POST_INC_DEC ? "post" : "pre"; + const char *inc_dec = (op->idx.inc_dec > 0) ? + "increment" : "decrement"; + + printf("\t\t\t%s %s: %d\n", post_pre, inc_dec, + abs(op->idx.inc_dec)); + } + + break; + } + + if (op->size != 0) + printf("\t\t\tsize: %u\n", op->size); + + if (op->access != CS_AC_INVALID) + printf("\t\t\taccess: %s\n", s_access[op->access]); + + } + + print_read_write_regs(handle, detail); + + if (detail->groups_count) { + printf("\tgroups_count: %u\n", detail->groups_count); + } + + printf("\n"); +} + +static bool consistency_checks() +{ + return true; +} + +static void test() +{ +#define M6800_CODE \ + "\x01\x09\x36\x64\x7f\x74\x10\x00\x90\x10\xA4\x10\xb6\x10\x00\x39" + +#define M6801_CODE \ + "\x04\x05\x3c\x3d\x38\x93\x10\xec\x10\xed\x10\x39" + +#define M6805_CODE \ + "\x04\x7f\x00\x17\x22\x28\x00\x2e\x00\x40\x42\x5a\x70\x8e\x97\x9c" \ + "\xa0\x15\xad\x00\xc3\x10\x00\xda\x12\x34\xe5\x7f\xfe" + +#define M6808_CODE \ + "\x31\x22\x00\x35\x22\x45\x10\x00\x4b\x00\x51\x10\x52\x5e\x22\x62" \ + "\x65\x12\x34\x72\x84\x85\x86\x87\x8a\x8b\x8c\x94\x95\xa7\x10\xaf\x10" \ + "\x9e\x60\x7f\x9e\x6b\x7f\x00\x9e\xd6\x10\x00\x9e\xe6\x7f" + +#define HCS08_CODE \ + "\x32\x10\x00\x9e\xae\x9e\xce\x7f\x9e\xbe\x10\x00\x9e\xfe\x7f" \ + "\x3e\x10\x00\x9e\xf3\x7f\x96\x10\x00\x9e\xff\x7f\x82" + +#define M6811_CODE \ + "\x02\x03\x12\x7f\x10\x00\x13\x99\x08\x00\x14\x7f\x02\x15\x7f\x01" \ + "\x1e\x7f\x20\x00\x8f\xcf" \ + "\x18\x08\x18\x30\x18\x3c\x18\x67\x18\x8c\x10\x00\x18\x8f" \ + "\x18\xce\x10\x00\x18\xff\x10\x00" \ + "\x1a\xa3\x7f\x1a\xac\x1a\xee\x7f\x1a\xef\x7f\xcd\xac\x7f" + +#define CPU12_CODE \ + "\x00\x04\x01\x00\x0c\x00\x80\x0e\x00\x80\x00\x11\x1e\x10\x00\x80\x00" \ + "\x3b\x4a\x10\x00\x04\x4b\x01\x04\x4f\x7f\x80\x00\x8f\x10\x00\xb7\x52" \ + "\xb7\xb1\xa6\x67\xa6\xfe\xa6\xf7\x18\x02\xe2\x30\x39\xe2\x10\x00" \ + "\x18\x0c\x30\x39\x10\x00\x18\x11\x18\x12\x10\x00\x18\x19\x00\x18\x1e\x00" \ + "\x18\x3e\x18\x3f\x00" + +#define HD6301_CODE \ + "\x6b\x10\x00\x71\x10\x00\x72\x10\x10\x39" + +#define M6809_CODE \ + "\x06\x10\x19\x1a\x55\x1e\x01\x23\xe9\x31\x06\x34\x55\xa6\x81" \ + "\xa7\x89\x7f\xff\xa6\x9d\x10\x00\xa7\x91\xa6\x9f\x10\x00" \ + "\x11\xac\x99\x10\x00\x39" \ + \ + "\xA6\x07\xA6\x27\xA6\x47\xA6\x67\xA6\x0F\xA6\x10" \ + "\xA6\x80\xA6\x81\xA6\x82\xA6\x83\xA6\x84\xA6\x85\xA6\x86" \ + "\xA6\x88\x7F\xA6\x88\x80\xA6\x89\x7F\xFF\xA6\x89\x80\x00" \ + "\xA6\x8B\xA6\x8C\x10\xA6\x8D\x10\x00" \ + \ + "\xA6\x91\xA6\x93\xA6\x94\xA6\x95\xA6\x96" \ + "\xA6\x98\x7F\xA6\x98\x80\xA6\x99\x7F\xFF\xA6\x99\x80\x00" \ + "\xA6\x9B\xA6\x9C\x10\xA6\x9D\x10\x00\xA6\x9F\x10\x00" + +#define HD6309_CODE \ + "\x01\x10\x10\x62\x10\x10\x7b\x10\x10\x00\xcd\x49\x96\x02\xd2" \ + "\x10\x30\x23\x10\x38\x10\x3b\x10\x53\x10\x5d" \ + "\x11\x30\x43\x10\x11\x37\x25\x10\x11\x38\x12\x11\x39\x23\x11\x3b\x34" \ + "\x11\x8e\x10\x00\x11\xaf\x10\x11\xab\x10\x11\xf6\x80\x00" + + struct platform platforms[] = { + { + CS_ARCH_M680X, + (cs_mode)(CS_MODE_M680X_6301), + (unsigned char *)HD6301_CODE, + sizeof(HD6301_CODE) - 1, + "M680X_HD6301", + }, + { + CS_ARCH_M680X, + (cs_mode)(CS_MODE_M680X_6309), + (unsigned char *)HD6309_CODE, + sizeof(HD6309_CODE) - 1, + "M680X_HD6309", + }, + { + CS_ARCH_M680X, + (cs_mode)(CS_MODE_M680X_6800), + (unsigned char *)M6800_CODE, + sizeof(M6800_CODE) - 1, + "M680X_M6800", + }, + { + CS_ARCH_M680X, + (cs_mode)(CS_MODE_M680X_6801), + (unsigned char *)M6801_CODE, + sizeof(M6801_CODE) - 1, + "M680X_M6801", + }, + { + CS_ARCH_M680X, + (cs_mode)(CS_MODE_M680X_6805), + (unsigned char *)M6805_CODE, + sizeof(M6805_CODE) - 1, + "M680X_M68HC05", + }, + { + CS_ARCH_M680X, + (cs_mode)(CS_MODE_M680X_6808), + (unsigned char *)M6808_CODE, + sizeof(M6808_CODE) - 1, + "M680X_M68HC08", + }, + { + CS_ARCH_M680X, + (cs_mode)(CS_MODE_M680X_6809), + (unsigned char *)M6809_CODE, + sizeof(M6809_CODE) - 1, + "M680X_M6809", + }, + { + CS_ARCH_M680X, + (cs_mode)(CS_MODE_M680X_6811), + (unsigned char *)M6811_CODE, + sizeof(M6811_CODE) - 1, + "M680X_M68HC11", + }, + { + CS_ARCH_M680X, + (cs_mode)(CS_MODE_M680X_CPU12), + (unsigned char *)CPU12_CODE, + sizeof(CPU12_CODE) - 1, + "M680X_CPU12", + }, + { + CS_ARCH_M680X, + (cs_mode)(CS_MODE_M680X_HCS08), + (unsigned char *)HCS08_CODE, + sizeof(HCS08_CODE) - 1, + "M680X_HCS08", + }, + }; + + uint64_t address = 0x1000; + csh handle; + cs_insn *insn; + int i; + size_t count; + const char *nine_spaces = " "; + + if (!consistency_checks()) + abort(); + + for (i = 0; i < sizeof(platforms) / sizeof(platforms[0]); i++) { + cs_err err = cs_open(platforms[i].arch, platforms[i].mode, + &handle); + + if (err) { + printf("Failed on cs_open() with error returned: %u\n", + err); + abort(); + } + +#ifdef WITH_DETAILS + cs_option(handle, CS_OPT_DETAIL, CS_OPT_ON); +#endif + + count = cs_disasm(handle, platforms[i].code, platforms[i].size, + address, 0, &insn); + + if (count) { + size_t j; + + printf("********************\n"); + printf("Platform: %s\n", platforms[i].comment); + print_string_hex("Code: ", platforms[i].code, + platforms[i].size); + printf("Disasm:\n"); + + for (j = 0; j < count; j++) { + int slen; + printf("0x%04x: ", (uint16_t)insn[j].address); + print_string_hex_short(insn[j].bytes, + insn[j].size); + printf("%.*s", 1 + ((5 - insn[j].size) * 2), + nine_spaces); + printf("%s", insn[j].mnemonic); + slen = (int)strlen(insn[j].mnemonic); + printf("%.*s", 1 + (5 - slen), nine_spaces); + printf("%s\n", insn[j].op_str); +#ifdef WITH_DETAILS + print_insn_detail(handle, &insn[j]); +#endif + } + + // free memory allocated by cs_disasm() + cs_free(insn, count); + } + else { + printf("********************\n"); + printf("Platform: %s\n", platforms[i].comment); + print_string_hex("Code:", platforms[i].code, + platforms[i].size); + printf("ERROR: Failed to disasm given code!\n"); + abort(); + } + + cs_close(&handle); + } +} + +int main() +{ + test(); + + return 0; +} diff --git a/capstone/tests/test_m68k.c b/capstone/tests/test_m68k.c new file mode 100644 index 000000000..aff11dfac --- /dev/null +++ b/capstone/tests/test_m68k.c @@ -0,0 +1,217 @@ +/* Capstone Disassembler Engine */ +/* By Daniel Collin, 2013-2019 */ + +#include <stdio.h> +#include <assert.h> + +#include <capstone/platform.h> +#include <capstone/capstone.h> + +struct platform { + cs_arch arch; + cs_mode mode; + unsigned char* code; + size_t size; + const char* comment; +}; + +static csh handle; + +static 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"); +} + +const char* s_addressing_modes[] = { + "<invalid mode>", + + "Register Direct - Data", + "Register Direct - Address", + + "Register Indirect - Address", + "Register Indirect - Address with Postincrement", + "Register Indirect - Address with Predecrement", + "Register Indirect - Address with Displacement", + + "Address Register Indirect With Index - 8-bit displacement", + "Address Register Indirect With Index - Base displacement", + + "Memory indirect - Postindex", + "Memory indirect - Preindex", + + "Program Counter Indirect - with Displacement", + + "Program Counter Indirect with Index - with 8-Bit Displacement", + "Program Counter Indirect with Index - with Base Displacement", + + "Program Counter Memory Indirect - Postindexed", + "Program Counter Memory Indirect - Preindexed", + + "Absolute Data Addressing - Short", + "Absolute Data Addressing - Long", + "Immediate value", +}; + +static void print_read_write_regs(cs_detail* detail) +{ + int i; + + for (i = 0; i < detail->regs_read_count; ++i) + { + uint16_t reg_id = detail->regs_read[i]; + const char* reg_name = cs_reg_name(handle, reg_id); + printf("\treading from reg: %s\n", reg_name); + } + + for (i = 0; i < detail->regs_write_count; ++i) + { + uint16_t reg_id = detail->regs_write[i]; + const char* reg_name = cs_reg_name(handle, reg_id); + printf("\twriting to reg: %s\n", reg_name); + } +} + +static void print_insn_detail(cs_insn *ins) +{ + cs_m68k* m68k; + cs_detail* detail; + int i; + + // detail can be NULL on "data" instruction if SKIPDATA option is turned ON + if (ins->detail == NULL) + return; + + detail = ins->detail; + m68k = &detail->m68k; + if (m68k->op_count) + printf("\top_count: %u\n", m68k->op_count); + + print_read_write_regs(detail); + + printf("\tgroups_count: %u\n", detail->groups_count); + + for (i = 0; i < m68k->op_count; i++) { + cs_m68k_op* op = &(m68k->operands[i]); + + switch((int)op->type) { + default: + break; + case M68K_OP_REG: + printf("\t\toperands[%u].type: REG = %s\n", i, cs_reg_name(handle, op->reg)); + break; + case M68K_OP_IMM: + printf("\t\toperands[%u].type: IMM = 0x%x\n", i, (int)op->imm); + break; + case M68K_OP_MEM: + printf("\t\toperands[%u].type: MEM\n", i); + if (op->mem.base_reg != M68K_REG_INVALID) + printf("\t\t\toperands[%u].mem.base: REG = %s\n", + i, cs_reg_name(handle, op->mem.base_reg)); + if (op->mem.index_reg != M68K_REG_INVALID) { + printf("\t\t\toperands[%u].mem.index: REG = %s\n", + i, cs_reg_name(handle, op->mem.index_reg)); + printf("\t\t\toperands[%u].mem.index: size = %c\n", + i, op->mem.index_size ? 'l' : 'w'); + } + if (op->mem.disp != 0) + printf("\t\t\toperands[%u].mem.disp: 0x%x\n", i, op->mem.disp); + if (op->mem.scale != 0) + printf("\t\t\toperands[%u].mem.scale: %d\n", i, op->mem.scale); + + printf("\t\taddress mode: %s\n", s_addressing_modes[op->address_mode]); + break; + case M68K_OP_FP_SINGLE: + printf("\t\toperands[%u].type: FP_SINGLE\n", i); + printf("\t\t\toperands[%u].simm: %f\n", i, op->simm); + break; + case M68K_OP_FP_DOUBLE: + printf("\t\toperands[%u].type: FP_DOUBLE\n", i); + printf("\t\t\toperands[%u].dimm: %lf\n", i, op->dimm); + break; + case M68K_OP_REG_BITS: + printf("\t\toperands[%u].type: REG_BITS = $%x\n", i, op->register_bits); + break; + case M68K_OP_REG_PAIR: + printf("\t\toperands[%u].type: REG_PAIR = (%s, %s)\n", i, + cs_reg_name(handle, op->reg_pair.reg_0), + cs_reg_name(handle, op->reg_pair.reg_1)); + break; + } + } + + printf("\n"); +} + +static void test() +{ +#define M68K_CODE "\xf0\x10\xf0\x00\x48\xaf\xff\xff\x7f\xff\x11\xb0\x01\x37\x7f\xff\xff\xff\x12\x34\x56\x78\x01\x33\x10\x10\x10\x10\x32\x32\x32\x32\x4C\x00\x54\x04\x48\xe7\xe0\x30\x4C\xDF\x0C\x07\xd4\x40\x87\x5a\x4e\x71\x02\xb4\xc0\xde\xc0\xde\x5c\x00\x1d\x80\x71\x12\x01\x23\xf2\x3c\x44\x22\x40\x49\x0e\x56\x54\xc5\xf2\x3c\x44\x00\x44\x7a\x00\x00\xf2\x00\x0a\x28\x4E\xB9\x00\x00\x00\x12\x4E\x75" + struct platform platforms[] = { + { + CS_ARCH_M68K, + (cs_mode)(CS_MODE_BIG_ENDIAN | CS_MODE_M68K_040), + (unsigned char*)M68K_CODE, + sizeof(M68K_CODE) - 1, + "M68K", + }, + }; + + uint64_t address = 0x01000; + cs_insn *insn; + int i; + size_t count; + + for (i = 0; i < sizeof(platforms)/sizeof(platforms[0]); i++) { + cs_err err = cs_open(platforms[i].arch, platforms[i].mode, &handle); + if (err) { + printf("Failed on cs_open() with error returned: %u\n", err); + abort(); + } + + cs_option(handle, CS_OPT_DETAIL, CS_OPT_ON); + + count = cs_disasm(handle, platforms[i].code, platforms[i].size, address, 0, &insn); + if (count) { + size_t j; + + printf("****************\n"); + printf("Platform: %s\n", platforms[i].comment); + print_string_hex("Code: ", platforms[i].code, platforms[i].size); + printf("Disasm:\n"); + + for (j = 0; j < count; j++) { + assert(address == insn[j].address && "this means the size of the previous instruction was incorrect"); + address += insn[j].size; + printf("0x%" PRIx64 ":\t%s\t%s\n", insn[j].address, insn[j].mnemonic, insn[j].op_str); + print_insn_detail(&insn[j]); + } + printf("0x%" PRIx64 ":\n", insn[j-1].address + insn[j-1].size); + + // free memory allocated by cs_disasm() + cs_free(insn, count); + } else { + printf("****************\n"); + printf("Platform: %s\n", platforms[i].comment); + print_string_hex("Code:", platforms[i].code, platforms[i].size); + printf("ERROR: Failed to disasm given code!\n"); + abort(); + } + + printf("\n"); + + cs_close(&handle); + } +} + +int main() +{ + test(); + + return 0; +} diff --git a/capstone/tests/test_mips.c b/capstone/tests/test_mips.c new file mode 100644 index 000000000..e5c5a400c --- /dev/null +++ b/capstone/tests/test_mips.c @@ -0,0 +1,175 @@ +/* Capstone Disassembler Engine */ +/* By Nguyen Anh Quynh <aquynh@gmail.com>, 2013-2019 */ + +#include <stdio.h> +#include <stdlib.h> + +#include <capstone/platform.h> +#include <capstone/capstone.h> + +struct platform { + cs_arch arch; + cs_mode mode; + unsigned char *code; + size_t size; + const char *comment; +}; + +static csh handle; + +static 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"); +} + +static void print_insn_detail(cs_insn *ins) +{ + int i; + cs_mips *mips; + + // detail can be NULL on "data" instruction if SKIPDATA option is turned ON + if (ins->detail == NULL) + return; + + mips = &(ins->detail->mips); + if (mips->op_count) + printf("\top_count: %u\n", mips->op_count); + + for (i = 0; i < mips->op_count; i++) { + cs_mips_op *op = &(mips->operands[i]); + switch((int)op->type) { + default: + break; + case MIPS_OP_REG: + printf("\t\toperands[%u].type: REG = %s\n", i, cs_reg_name(handle, op->reg)); + break; + case MIPS_OP_IMM: + printf("\t\toperands[%u].type: IMM = 0x%" PRIx64 "\n", i, op->imm); + break; + case MIPS_OP_MEM: + printf("\t\toperands[%u].type: MEM\n", i); + if (op->mem.base != MIPS_REG_INVALID) + printf("\t\t\toperands[%u].mem.base: REG = %s\n", + i, cs_reg_name(handle, op->mem.base)); + if (op->mem.disp != 0) + printf("\t\t\toperands[%u].mem.disp: 0x%" PRIx64 "\n", i, op->mem.disp); + + break; + } + + } + + printf("\n"); +} + +static void test() +{ +#define MIPS_CODE "\x0C\x10\x00\x97\x00\x00\x00\x00\x24\x02\x00\x0c\x8f\xa2\x00\x00\x34\x21\x34\x56" +#define MIPS_CODE2 "\x56\x34\x21\x34\xc2\x17\x01\x00" +#define MIPS_32R6M "\x00\x07\x00\x07\x00\x11\x93\x7c\x01\x8c\x8b\x7c\x00\xc7\x48\xd0" +#define MIPS_32R6 "\xec\x80\x00\x19\x7c\x43\x22\xa0" +#define MIPS_64SD "\x70\x00\xb2\xff" + + struct platform platforms[] = { + { + CS_ARCH_MIPS, + (cs_mode)(CS_MODE_MIPS32 | CS_MODE_BIG_ENDIAN), + (unsigned char *)MIPS_CODE, + sizeof(MIPS_CODE) - 1, + "MIPS-32 (Big-endian)" + }, + { + CS_ARCH_MIPS, + (cs_mode)(CS_MODE_MIPS64 | CS_MODE_LITTLE_ENDIAN), + (unsigned char *)MIPS_CODE2, + sizeof(MIPS_CODE2) - 1, + "MIPS-64-EL (Little-endian)" + }, + { + CS_ARCH_MIPS, + (cs_mode)(CS_MODE_MIPS32R6 | CS_MODE_MICRO | CS_MODE_BIG_ENDIAN), + (unsigned char*)MIPS_32R6M, + sizeof(MIPS_32R6M) - 1, + "MIPS-32R6 | Micro (Big-endian)" + }, + { + CS_ARCH_MIPS, + (cs_mode)(CS_MODE_MIPS32R6 | CS_MODE_BIG_ENDIAN), + (unsigned char*)MIPS_32R6, + sizeof(MIPS_32R6) - 1, + "MIPS-32R6 (Big-endian)" + }, + { + CS_ARCH_MIPS, + (cs_mode)(CS_MODE_MIPS64 | CS_MODE_MIPS2 | CS_MODE_LITTLE_ENDIAN), + (unsigned char *)MIPS_64SD, + sizeof(MIPS_64SD) - 1, + "MIPS-64-EL + Mips II (Little-endian)" + }, + { + CS_ARCH_MIPS, + (cs_mode)(CS_MODE_MIPS64 | CS_MODE_LITTLE_ENDIAN), + (unsigned char *)MIPS_64SD, + sizeof(MIPS_64SD) - 1, + "MIPS-64-EL (Little-endian)" + }, + }; + + uint64_t address = 0x1000; + cs_insn *insn; + int i; + size_t count; + + for (i = 0; i < sizeof(platforms)/sizeof(platforms[0]); i++) { + cs_err err = cs_open(platforms[i].arch, platforms[i].mode, &handle); + if (err) { + printf("Failed on cs_open() with error returned: %u\n", err); + abort(); + } + + cs_option(handle, CS_OPT_DETAIL, CS_OPT_ON); + + count = cs_disasm(handle, platforms[i].code, platforms[i].size, address, 0, &insn); + if (count) { + size_t j; + + printf("****************\n"); + printf("Platform: %s\n", platforms[i].comment); + print_string_hex("Code:", platforms[i].code, platforms[i].size); + printf("Disasm:\n"); + + for (j = 0; j < count; j++) { + printf("0x%" PRIx64 ":\t%s\t%s\n", insn[j].address, insn[j].mnemonic, insn[j].op_str); + print_insn_detail(&insn[j]); + } + printf("0x%" PRIx64 ":\n", insn[j-1].address + insn[j-1].size); + + // free memory allocated by cs_disasm() + cs_free(insn, count); + } else { + printf("****************\n"); + printf("Platform: %s\n", platforms[i].comment); + print_string_hex("Code:", platforms[i].code, platforms[i].size); + printf("ERROR: Failed to disasm given code!\n"); + abort(); + } + + printf("\n"); + + cs_close(&handle); + } +} + +int main() +{ + test(); + + return 0; +} diff --git a/capstone/tests/test_mos65xx.c b/capstone/tests/test_mos65xx.c new file mode 100644 index 000000000..cc31de803 --- /dev/null +++ b/capstone/tests/test_mos65xx.c @@ -0,0 +1,230 @@ +/* Capstone Disassembler Engine */ +/* By Sebastian Macke <sebastian@macke.de>, 2018 */ + +#include <stdio.h> +#include <stdlib.h> + +#include <capstone/platform.h> +#include <capstone/capstone.h> + +struct platform { + cs_arch arch; + cs_mode mode; + unsigned char *code; + size_t size; + const char *comment; +}; + +static csh handle; + +static 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"); +} + +static const char *get_am_name(mos65xx_address_mode mode) +{ + switch(mode) { + default: + case MOS65XX_AM_NONE: + return "No address mode"; + case MOS65XX_AM_IMP: + return "implied"; + case MOS65XX_AM_ACC: + return "accumulator"; + case MOS65XX_AM_IMM: + return "immediate value"; + case MOS65XX_AM_REL: + return "relative"; + case MOS65XX_AM_INT: + return "interrupt signature"; + case MOS65XX_AM_BLOCK: + return "block move"; + case MOS65XX_AM_ZP: + return "zero page"; + case MOS65XX_AM_ZP_X: + return "zero page indexed with x"; + case MOS65XX_AM_ZP_Y: + return "zero page indexed with y"; + case MOS65XX_AM_ZP_REL: + return "relative bit branch"; + case MOS65XX_AM_ZP_IND: + return "zero page indirect"; + case MOS65XX_AM_ZP_X_IND: + return "zero page indexed with x indirect"; + case MOS65XX_AM_ZP_IND_Y: + return "zero page indirect indexed with y"; + case MOS65XX_AM_ZP_IND_LONG: + return "zero page indirect long"; + case MOS65XX_AM_ZP_IND_LONG_Y: + return "zero page indirect long indexed with y"; + case MOS65XX_AM_ABS: + return "absolute"; + case MOS65XX_AM_ABS_X: + return "absolute indexed with x"; + case MOS65XX_AM_ABS_Y: + return "absolute indexed with y"; + case MOS65XX_AM_ABS_IND: + return "absolute indirect"; + case MOS65XX_AM_ABS_X_IND: + return "absolute indexed with x indirect"; + case MOS65XX_AM_ABS_IND_LONG: + return "absolute indirect long"; + case MOS65XX_AM_ABS_LONG: + return "absolute long"; + case MOS65XX_AM_ABS_LONG_X: + return "absolute long indexed with x"; + case MOS65XX_AM_SR: + return "stack relative"; + case MOS65XX_AM_SR_IND_Y: + return "stack relative indirect indexed with y"; + } +} + + +static void print_insn_detail(cs_insn *ins) +{ + cs_mos65xx *mos65xx; + int i; + + // detail can be NULL on "data" instruction if SKIPDATA option is turned ON + if (ins->detail == NULL) + return; + + mos65xx = &(ins->detail->mos65xx); + + // printf("insn_detail\n"); + printf("\taddress mode: %s\n", get_am_name(mos65xx->am)); + printf("\tmodifies flags: %s\n", mos65xx->modifies_flags ? "true": "false"); + + if (mos65xx->op_count) + printf("\top_count: %u\n", mos65xx->op_count); + + for (i = 0; i < mos65xx->op_count; i++) { + cs_mos65xx_op *op = &(mos65xx->operands[i]); + switch((int)op->type) { + default: + break; + case MOS65XX_OP_REG: + printf("\t\toperands[%u].type: REG = %s\n", i, cs_reg_name(handle, op->reg)); + break; + case MOS65XX_OP_IMM: + printf("\t\toperands[%u].type: IMM = 0x%x\n", i, op->imm); + break; + case MOS65XX_OP_MEM: + printf("\t\toperands[%u].type: MEM = 0x%x\n", i, op->mem); + break; + } + } +} + +static void test() +{ +#define M6502_CODE "\xa1\x12\xa5\x12\xa9\x12\xad\x34\x12\xb1\x12\xb5\x12\xb9\x34\x12\xbd\x34\x12" \ + "\x0d\x34\x12\x00\x81\x87\x6c\x01\x00\x85\xFF\x10\x00\x19\x42\x42\x00\x49\x42" + +#define M65C02_CODE "\x1a\x3a" \ + "\x02\x12\x03\x5c\x34\x12" + +#define MW65C02_CODE \ + "\x07\x12\x27\x12\x47\x12\x67\x12\x87\x12\xa7\x12\xc7\x12\xe7\x12" \ + "\x0f\x12\xfd\x4f\x12\xfd\x8f\x12\xfd\xcf\x12\xfd" + +#define M65816_CODE \ + "\xa9\x34\x12" "\xad\x34\x12" "\xbd\x34\x12" "\xb9\x34\x12" \ + "\xaf\x56\x34\x12" "\xbf\x56\x34\x12" \ + "\xa5\x12" "\xb5\x12" "\xb2\x12" "\xa1\x12" "\xb1\x12" "\xa7\x12" "\xb7\x12" \ + "\xa3\x12" "\xb3\x12" \ + "\xc2\x00" "\xe2\x00" "\x54\x34\x12" "\x44\x34\x12" "\x02\x12" + + struct platform platforms[] = { + { + CS_ARCH_MOS65XX, + (cs_mode)(CS_MODE_MOS65XX_6502), + (unsigned char *)M6502_CODE, + sizeof(M6502_CODE) - 1, + "MOS65XX_6502" + }, + { + CS_ARCH_MOS65XX, + (cs_mode)(CS_MODE_MOS65XX_65C02), + (unsigned char *)M65C02_CODE, + sizeof(M65C02_CODE) - 1, + "MOS65XX_65C02" + }, + { + CS_ARCH_MOS65XX, + (cs_mode)(CS_MODE_MOS65XX_W65C02), + (unsigned char *)MW65C02_CODE, + sizeof(MW65C02_CODE) - 1, + "MOS65XX_W65C02" + }, + { + CS_ARCH_MOS65XX, + (cs_mode)(CS_MODE_MOS65XX_65816_LONG_MX), + (unsigned char *)M65816_CODE, + sizeof(M65816_CODE) - 1, + "MOS65XX_65816 (long m/x)" + }, + }; + + uint64_t address = 0x1000; + cs_insn *insn; + int i; + size_t count; + + for (i = 0; i < sizeof(platforms)/sizeof(platforms[0]); i++) { + cs_err err = cs_open(platforms[i].arch, platforms[i].mode, &handle); + if (err) { + printf("Failed on cs_open() with error returned: %u (%s)\n", err, cs_strerror(err)); + abort(); + } + + cs_option(handle, CS_OPT_DETAIL, CS_OPT_ON); + cs_option(handle, CS_OPT_SYNTAX, CS_OPT_SYNTAX_MOTOROLA); + + count = cs_disasm(handle, platforms[i].code, platforms[i].size, address, 0, &insn); + + if (count) { + size_t j; + + printf("****************\n"); + printf("Platform: %s\n", platforms[i].comment); + print_string_hex("Code:", platforms[i].code, platforms[i].size); + printf("Disasm:\n"); + + for (j = 0; j < count; j++) { + printf("0x%" PRIx64 ":\t%s\t%s\n", insn[j].address, insn[j].mnemonic, insn[j].op_str); + print_insn_detail(&insn[j]); + puts(""); + } + printf("0x%" PRIx64 ":\n", insn[j-1].address + insn[j-1].size); + + // free memory allocated by cs_disasm() + cs_free(insn, count); + } else { + printf("****************\n"); + printf("Platform: %s\n", platforms[i].comment); + print_string_hex("Code:", platforms[i].code, platforms[i].size); + printf("ERROR: Failed to disasm given code!\n"); + abort(); + } + + printf("\n"); + + cs_close(&handle); + } +} + +int main() +{ + test(); + return 0; +} diff --git a/capstone/tests/test_ppc.c b/capstone/tests/test_ppc.c new file mode 100644 index 000000000..43da000e2 --- /dev/null +++ b/capstone/tests/test_ppc.c @@ -0,0 +1,186 @@ +/* Capstone Disassembler Engine */ +/* By Nguyen Anh Quynh <aquynh@gmail.com>, 2013-2019 */ + +#include <stdio.h> + +#include <capstone/platform.h> +#include <capstone/capstone.h> + +struct platform { + cs_arch arch; + cs_mode mode; + unsigned char *code; + size_t size; + const char *comment; +}; + +static csh handle; + +static 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"); +} + +static const char* get_bc_name(int bc) +{ + switch(bc) { + default: + case PPC_BC_INVALID: + return ("invalid"); + case PPC_BC_LT: + return ("lt"); + case PPC_BC_LE: + return ("le"); + case PPC_BC_EQ: + return ("eq"); + case PPC_BC_GE: + return ("ge"); + case PPC_BC_GT: + return ("gt"); + case PPC_BC_NE: + return ("ne"); + case PPC_BC_UN: + return ("un"); + case PPC_BC_NU: + return ("nu"); + case PPC_BC_SO: + return ("so"); + case PPC_BC_NS: + return ("ns"); + } +} + +static void print_insn_detail(cs_insn *ins) +{ + cs_ppc *ppc; + int i; + + // detail can be NULL on "data" instruction if SKIPDATA option is turned ON + if (ins->detail == NULL) + return; + + ppc = &(ins->detail->ppc); + if (ppc->op_count) + printf("\top_count: %u\n", ppc->op_count); + + for (i = 0; i < ppc->op_count; i++) { + cs_ppc_op *op = &(ppc->operands[i]); + switch((int)op->type) { + default: + break; + case PPC_OP_REG: + printf("\t\toperands[%u].type: REG = %s\n", i, cs_reg_name(handle, op->reg)); + break; + case PPC_OP_IMM: + printf("\t\toperands[%u].type: IMM = 0x%" PRIx64 "\n", i, op->imm); + break; + case PPC_OP_MEM: + printf("\t\toperands[%u].type: MEM\n", i); + if (op->mem.base != PPC_REG_INVALID) + printf("\t\t\toperands[%u].mem.base: REG = %s\n", + i, cs_reg_name(handle, op->mem.base)); + if (op->mem.disp != 0) + printf("\t\t\toperands[%u].mem.disp: 0x%x\n", i, op->mem.disp); + + break; + case PPC_OP_CRX: + printf("\t\toperands[%u].type: CRX\n", i); + printf("\t\t\toperands[%u].crx.scale: %d\n", i, op->crx.scale); + printf("\t\t\toperands[%u].crx.reg: %s\n", i, cs_reg_name(handle, op->crx.reg)); + printf("\t\t\toperands[%u].crx.cond: %s\n", i, get_bc_name(op->crx.cond)); + break; + } + } + + if (ppc->bc != 0) + printf("\tBranch code: %u\n", ppc->bc); + + if (ppc->bh != 0) + printf("\tBranch hint: %u\n", ppc->bh); + + if (ppc->update_cr0) + printf("\tUpdate-CR0: True\n"); + + printf("\n"); +} + +static void test() +{ +#define PPC_CODE "\x43\x20\x0c\x07\x41\x56\xff\x17\x80\x20\x00\x00\x80\x3f\x00\x00\x10\x43\x23\x0e\xd0\x44\x00\x80\x4c\x43\x22\x02\x2d\x03\x00\x80\x7c\x43\x20\x14\x7c\x43\x20\x93\x4f\x20\x00\x21\x4c\xc8\x00\x21\x40\x82\x00\x14" +#define PPC_CODE2 "\x10\x60\x2a\x10\x10\x64\x28\x88\x7c\x4a\x5d\x0f" + + struct platform platforms[] = { + { + CS_ARCH_PPC, + CS_MODE_BIG_ENDIAN, + (unsigned char*)PPC_CODE, + sizeof(PPC_CODE) - 1, + "PPC-64", + }, + { + CS_ARCH_PPC, + (cs_mode)(CS_MODE_BIG_ENDIAN + CS_MODE_QPX), + (unsigned char*)PPC_CODE2, + sizeof(PPC_CODE2) - 1, + "PPC-64 + QPX", + }, + }; + + uint64_t address = 0x1000; + cs_insn *insn; + int i; + size_t count; + + for (i = 0; i < sizeof(platforms)/sizeof(platforms[0]); i++) { + cs_err err = cs_open(platforms[i].arch, platforms[i].mode, &handle); + if (err) { + printf("Failed on cs_open() with error returned: %u\n", err); + abort(); + } + + cs_option(handle, CS_OPT_DETAIL, CS_OPT_ON); + + count = cs_disasm(handle, platforms[i].code, platforms[i].size, address, 0, &insn); + if (count) { + size_t j; + + printf("****************\n"); + printf("Platform: %s\n", platforms[i].comment); + print_string_hex("Code:", platforms[i].code, platforms[i].size); + printf("Disasm:\n"); + + for (j = 0; j < count; j++) { + printf("0x%" PRIx64 ":\t%s\t%s\n", insn[j].address, insn[j].mnemonic, insn[j].op_str); + print_insn_detail(&insn[j]); + } + printf("0x%" PRIx64 ":\n", insn[j-1].address + insn[j-1].size); + + // free memory allocated by cs_disasm() + cs_free(insn, count); + } else { + printf("****************\n"); + printf("Platform: %s\n", platforms[i].comment); + print_string_hex("Code:", platforms[i].code, platforms[i].size); + printf("ERROR: Failed to disasm given code!\n"); + abort(); + } + + printf("\n"); + + cs_close(&handle); + } +} + +int main() +{ + test(); + + return 0; +} diff --git a/capstone/tests/test_riscv.c b/capstone/tests/test_riscv.c new file mode 100644 index 000000000..a9b8b10c8 --- /dev/null +++ b/capstone/tests/test_riscv.c @@ -0,0 +1,154 @@ +#include <stdio.h> +#include <stdlib.h> + +#include <capstone/platform.h> +#include <capstone/capstone.h> + +struct platform { + cs_arch arch; + cs_mode mode; + unsigned char *code; + size_t size; + const char *comment; +}; + +static csh handle; + +static 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"); +} + +static void print_insn_detail(cs_insn *ins) +{ + int i; + int n; + cs_riscv *riscv; + cs_detail *detail; + + // detail can be NULL on "data" instruction if SKIPDATA option is turned ON + if (ins->detail == NULL) + return; + + riscv = &(ins->detail->riscv); + detail = ins->detail; + if (riscv->op_count) + printf("\top_count: %u\n", riscv->op_count); + + for (i = 0; i < riscv->op_count; i++) { + cs_riscv_op *op = &(riscv->operands[i]); + switch((int)op->type) { + default: + printf("\terror in opt_type: %u\n", (int)op->type); + break; + case RISCV_OP_REG: + printf("\t\toperands[%u].type: REG = %s\n", i, cs_reg_name(handle, op->reg)); + break; + case RISCV_OP_IMM: + printf("\t\toperands[%u].type: IMM = 0x%" PRIx64 "\n", i, op->imm); + break; + case RISCV_OP_MEM: + printf("\t\toperands[%u].type: MEM\n", i); + if (op->mem.base != RISCV_REG_INVALID) + printf("\t\t\toperands[%u].mem.base: REG = %s\n", + i, cs_reg_name(handle, op->mem.base)); + if (op->mem.disp != 0) + printf("\t\t\toperands[%u].mem.disp: 0x%" PRIx64 "\n", i, op->mem.disp); + + break; + } + + } + + //print the groups this instruction belongs to + if (detail->groups_count > 0) { + printf("\tThis instruction belongs to groups: "); + for (n = 0; n < detail->groups_count; n++) { + printf("%s ", cs_group_name(handle, detail->groups[n])); + } + printf("\n"); + } + + printf("\n"); +} + +static void test() +{ +#define RISCV_CODE32 "\x37\x34\x00\x00\x97\x82\x00\x00\xef\x00\x80\x00\xef\xf0\x1f\xff\xe7\x00\x45\x00\xe7\x00\xc0\xff\x63\x05\x41\x00\xe3\x9d\x61\xfe\x63\xca\x93\x00\x63\x53\xb5\x00\x63\x65\xd6\x00\x63\x76\xf7\x00\x03\x88\x18\x00\x03\x99\x49\x00\x03\xaa\x6a\x00\x03\xcb\x2b\x01\x03\xdc\x8c\x01\x23\x86\xad\x03\x23\x9a\xce\x03\x23\x8f\xef\x01\x93\x00\xe0\x00\x13\xa1\x01\x01\x13\xb2\x02\x7d\x13\xc3\x03\xdd\x13\xe4\xc4\x12\x13\xf5\x85\x0c\x13\x96\xe6\x01\x13\xd7\x97\x01\x13\xd8\xf8\x40\x33\x89\x49\x01\xb3\x0a\x7b\x41\x33\xac\xac\x01\xb3\x3d\xde\x01\x33\xd2\x62\x40\xb3\x43\x94\x00\x33\xe5\xc5\x00\xb3\x76\xf7\x00\xb3\x54\x39\x01\xb3\x50\x31\x00\x33\x9f\x0f\x00" +#define RISCV_CODE64 "\x13\x04\xa8\x7a" // aaa80413 + struct platform platforms[] = { + { + CS_ARCH_RISCV, + CS_MODE_RISCV32, + (unsigned char *)RISCV_CODE32, + sizeof(RISCV_CODE32) - 1, + "riscv32" + }, + { + CS_ARCH_RISCV, + CS_MODE_RISCV64, + (unsigned char *)RISCV_CODE64, + sizeof(RISCV_CODE64) - 1, + "riscv64" + } + }; + + uint64_t address = 0x1000; + cs_insn *insn; + int i; + size_t count; + + for (i = 0; i < sizeof(platforms)/sizeof(platforms[0]); i++) { + cs_err err = cs_open(platforms[i].arch, platforms[i].mode, &handle); + if (err) { + printf("Failed on cs_open() with error returned: %u\n", err); + continue; + } + + //To turn on or off the Print Details option + //cs_option(handle, CS_OPT_DETAIL, CS_OPT_OFF); + cs_option(handle, CS_OPT_DETAIL, CS_OPT_ON); + + count = cs_disasm(handle, platforms[i].code, platforms[i].size, address, 0, &insn); + if (count) { + size_t j; + + printf("****************\n"); + printf("Platform: %s\n", platforms[i].comment); + print_string_hex("Code:", platforms[i].code, platforms[i].size); + printf("Disasm:\n"); + + for (j = 0; j < count; j++) { + printf("0x%" PRIx64 ":\t%s\t%s\n", insn[j].address, insn[j].mnemonic, insn[j].op_str); + print_insn_detail(&insn[j]); + } + printf("0x%" PRIx64 ":\n", insn[j-1].address + insn[j-1].size); + + // free memory allocated by cs_disasm() + cs_free(insn, count); + } else { + printf("****************\n"); + printf("Platform: %s\n", platforms[i].comment); + print_string_hex("Code:", platforms[i].code, platforms[i].size); + printf("ERROR: Failed to disasm given code!\n"); + } + + printf("\n"); + + cs_close(&handle); + } +} + +int main() +{ + test(); + + return 0; +} diff --git a/capstone/tests/test_skipdata.c b/capstone/tests/test_skipdata.c new file mode 100644 index 000000000..8ab046f10 --- /dev/null +++ b/capstone/tests/test_skipdata.c @@ -0,0 +1,184 @@ +/* Capstone Disassembler Engine */ +/* By Nguyen Anh Quynh <aquynh@gmail.com>, 2013-2019 */ + +#include <stdio.h> +#include <stdlib.h> + +#include <capstone/platform.h> +#include <capstone/capstone.h> + +struct platform { + cs_arch arch; + cs_mode mode; + unsigned char *code; + size_t size; + const char *comment; + cs_opt_type opt_type; + cs_opt_value opt_value; + cs_opt_type opt_skipdata; + size_t skipdata; +}; + +static void print_string_hex(unsigned char *str, size_t len) +{ + unsigned char *c; + + printf("Code: "); + for (c = str; c < str + len; c++) { + printf("0x%02x ", *c & 0xff); + } + printf("\n"); +} + +#ifdef CAPSTONE_HAS_ARM +static size_t CAPSTONE_API mycallback(const uint8_t *buffer, size_t buffer_size, size_t offset, void *p) +{ + // always skip 2 bytes when encountering data + return 2; +} +#endif + +static void test() +{ +#ifdef CAPSTONE_HAS_X86 +#define X86_CODE32 "\x8d\x4c\x32\x08\x01\xd8\x81\xc6\x34\x12\x00\x00\x00\x91\x92" +#endif +#define RANDOM_CODE "\xed\x00\x00\x00\x00\x1a\x5a\x0f\x1f\xff\xc2\x09\x80\x00\x00\x00\x07\xf7\xeb\x2a\xff\xff\x7f\x57\xe3\x01\xff\xff\x7f\x57\xeb\x00\xf0\x00\x00\x24\xb2\x4f\x00\x78" + +#if defined(CAPSTONE_HAS_X86) + cs_opt_skipdata skipdata = { + // rename default "data" instruction from ".byte" to "db" + "db", + }; +#endif + +#ifdef CAPSTONE_HAS_ARM + cs_opt_skipdata skipdata_callback = { + "db", + &mycallback, + }; +#endif + + struct platform platforms[] = { +#ifdef CAPSTONE_HAS_X86 + { + CS_ARCH_X86, + CS_MODE_32, + (unsigned char*)X86_CODE32, + sizeof(X86_CODE32) - 1, + "X86 32 (Intel syntax) - Skip data", + }, + { + CS_ARCH_X86, + CS_MODE_32, + (unsigned char*)X86_CODE32, + sizeof(X86_CODE32) - 1, + "X86 32 (Intel syntax) - Skip data with custom mnemonic", + CS_OPT_INVALID, + CS_OPT_OFF, + CS_OPT_SKIPDATA_SETUP, + (size_t) &skipdata, + }, +#endif +#ifdef CAPSTONE_HAS_ARM + { + CS_ARCH_ARM, + CS_MODE_ARM, + (unsigned char*)RANDOM_CODE, + sizeof(RANDOM_CODE) - 1, + "Arm - Skip data", + }, + { + CS_ARCH_ARM, + CS_MODE_ARM, + (unsigned char*)RANDOM_CODE, + sizeof(RANDOM_CODE) - 1, + "Arm - Skip data with callback", + CS_OPT_INVALID, + CS_OPT_OFF, + CS_OPT_SKIPDATA_SETUP, + (size_t) &skipdata_callback, + }, +#endif + }; + + csh handle; + uint64_t address = 0x1000; + cs_insn *insn; + cs_err err; + int i; + size_t count; + + for (i = 0; i < sizeof(platforms)/sizeof(platforms[0]); i++) { + printf("****************\n"); + printf("Platform: %s\n", platforms[i].comment); + err = cs_open(platforms[i].arch, platforms[i].mode, &handle); + if (err) { + printf("Failed on cs_open() with error returned: %u\n", err); + abort(); + } + + if (platforms[i].opt_type) + cs_option(handle, platforms[i].opt_type, platforms[i].opt_value); + + // turn on SKIPDATA mode + cs_option(handle, CS_OPT_SKIPDATA, CS_OPT_ON); + cs_option(handle, platforms[i].opt_skipdata, platforms[i].skipdata); + + count = cs_disasm(handle, platforms[i].code, platforms[i].size, address, 0, &insn); + if (count) { + size_t j; + + print_string_hex(platforms[i].code, platforms[i].size); + printf("Disasm:\n"); + + for (j = 0; j < count; j++) { + printf("0x%" PRIx64 ":\t%s\t\t%s\n", + insn[j].address, insn[j].mnemonic, insn[j].op_str); + } + + // print out the next offset, after the last insn + printf("0x%" PRIx64 ":\n", insn[j-1].address + insn[j-1].size); + + // free memory allocated by cs_disasm() + cs_free(insn, count); + } else { + printf("****************\n"); + printf("Platform: %s\n", platforms[i].comment); + print_string_hex(platforms[i].code, platforms[i].size); + printf("ERROR: Failed to disasm given code!\n"); + abort(); + } + + printf("\n"); + + cs_close(&handle); + } +} + +int main() +{ + test(); + +#if 0 + #define offsetof(st, m) __builtin_offsetof(st, m) + + cs_insn insn; + printf("size: %lu\n", sizeof(insn)); + printf("@id: %lu\n", offsetof(cs_insn, id)); + printf("@address: %lu\n", offsetof(cs_insn, address)); + printf("@size: %lu\n", offsetof(cs_insn, size)); + printf("@bytes: %lu\n", offsetof(cs_insn, bytes)); + printf("@mnemonic: %lu\n", offsetof(cs_insn, mnemonic)); + printf("@op_str: %lu\n", offsetof(cs_insn, op_str)); + printf("@regs_read: %lu\n", offsetof(cs_insn, regs_read)); + printf("@regs_read_count: %lu\n", offsetof(cs_insn, regs_read_count)); + printf("@regs_write: %lu\n", offsetof(cs_insn, regs_write)); + printf("@regs_write_count: %lu\n", offsetof(cs_insn, regs_write_count)); + printf("@groups: %lu\n", offsetof(cs_insn, groups)); + printf("@groups_count: %lu\n", offsetof(cs_insn, groups_count)); + printf("@arch: %lu\n", offsetof(cs_insn, x86)); +#endif + + return 0; +} diff --git a/capstone/tests/test_sparc.c b/capstone/tests/test_sparc.c new file mode 100644 index 000000000..98c39494e --- /dev/null +++ b/capstone/tests/test_sparc.c @@ -0,0 +1,152 @@ +/* Capstone Disassembler Engine */ +/* By Nguyen Anh Quynh <aquynh@gmail.com>, 2013-2019 */ + +#include <stdio.h> + +#include <capstone/platform.h> +#include <capstone/capstone.h> + +struct platform { + cs_arch arch; + cs_mode mode; + unsigned char *code; + size_t size; + const char *comment; +}; + +static csh handle; + +static 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"); +} + +static void print_insn_detail(cs_insn *ins) +{ + cs_sparc *sparc; + int i; + + // detail can be NULL on "data" instruction if SKIPDATA option is turned ON + if (ins->detail == NULL) + return; + + sparc = &(ins->detail->sparc); + if (sparc->op_count) + printf("\top_count: %u\n", sparc->op_count); + + for (i = 0; i < sparc->op_count; i++) { + cs_sparc_op *op = &(sparc->operands[i]); + switch((int)op->type) { + default: + break; + case SPARC_OP_REG: + printf("\t\toperands[%u].type: REG = %s\n", i, cs_reg_name(handle, op->reg)); + break; + case SPARC_OP_IMM: + printf("\t\toperands[%u].type: IMM = 0x%" PRIx64 "\n", i, op->imm); + break; + case SPARC_OP_MEM: + printf("\t\toperands[%u].type: MEM\n", i); + if (op->mem.base != X86_REG_INVALID) + printf("\t\t\toperands[%u].mem.base: REG = %s\n", + i, cs_reg_name(handle, op->mem.base)); + if (op->mem.index != X86_REG_INVALID) + printf("\t\t\toperands[%u].mem.index: REG = %s\n", + i, cs_reg_name(handle, op->mem.index)); + if (op->mem.disp != 0) + printf("\t\t\toperands[%u].mem.disp: 0x%x\n", i, op->mem.disp); + + break; + } + } + + if (sparc->cc != 0) + printf("\tCode condition: %u\n", sparc->cc); + + if (sparc->hint != 0) + printf("\tHint code: %u\n", sparc->hint); + + printf("\n"); +} + +static void test() +{ +#define SPARC_CODE "\x80\xa0\x40\x02\x85\xc2\x60\x08\x85\xe8\x20\x01\x81\xe8\x00\x00\x90\x10\x20\x01\xd5\xf6\x10\x16\x21\x00\x00\x0a\x86\x00\x40\x02\x01\x00\x00\x00\x12\xbf\xff\xff\x10\xbf\xff\xff\xa0\x02\x00\x09\x0d\xbf\xff\xff\xd4\x20\x60\x00\xd4\x4e\x00\x16\x2a\xc2\x80\x03" + +#define SPARCV9_CODE "\x81\xa8\x0a\x24\x89\xa0\x10\x20\x89\xa0\x1a\x60\x89\xa0\x00\xe0" + + struct platform platforms[] = { + { + CS_ARCH_SPARC, + CS_MODE_BIG_ENDIAN, + (unsigned char*)SPARC_CODE, + sizeof(SPARC_CODE) - 1, + "Sparc", + }, + { + CS_ARCH_SPARC, + (cs_mode)(CS_MODE_BIG_ENDIAN + CS_MODE_V9), + (unsigned char*)SPARCV9_CODE, + sizeof(SPARCV9_CODE) - 1, + "SparcV9" + }, + }; + + uint64_t address = 0x1000; + cs_insn *insn; + int i; + size_t count; + + for (i = 0; i < sizeof(platforms)/sizeof(platforms[0]); i++) { + cs_err err = cs_open(platforms[i].arch, platforms[i].mode, &handle); + if (err) { + printf("Failed on cs_open() with error returned: %u\n", err); + abort(); + } + + cs_option(handle, CS_OPT_DETAIL, CS_OPT_ON); + + count = cs_disasm(handle, platforms[i].code, platforms[i].size, address, 0, &insn); + if (count) { + size_t j; + + printf("****************\n"); + printf("Platform: %s\n", platforms[i].comment); + print_string_hex("Code:", platforms[i].code, platforms[i].size); + printf("Disasm:\n"); + + for (j = 0; j < count; j++) { + printf("0x%" PRIx64 ":\t%s\t%s\n", insn[j].address, insn[j].mnemonic, insn[j].op_str); + print_insn_detail(&insn[j]); + } + printf("0x%" PRIx64 ":\n", insn[j-1].address + insn[j-1].size); + + // free memory allocated by cs_disasm() + cs_free(insn, count); + } else { + printf("****************\n"); + printf("Platform: %s\n", platforms[i].comment); + print_string_hex("Code:", platforms[i].code, platforms[i].size); + printf("ERROR: Failed to disasm given code!\n"); + abort(); + } + + printf("\n"); + + cs_close(&handle); + } +} + +int main() +{ + test(); + + return 0; +} diff --git a/capstone/tests/test_systemz.c b/capstone/tests/test_systemz.c new file mode 100644 index 000000000..f662247b8 --- /dev/null +++ b/capstone/tests/test_systemz.c @@ -0,0 +1,145 @@ +/* Capstone Disassembler Engine */ +/* By Nguyen Anh Quynh <aquynh@gmail.com>, 2013-2019 */ + +#include <stdio.h> + +#include <capstone/platform.h> +#include <capstone/capstone.h> + +struct platform { + cs_arch arch; + cs_mode mode; + unsigned char *code; + size_t size; + const char *comment; +}; + +static csh handle; + +static 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"); +} + +static void print_insn_detail(cs_insn *ins) +{ + cs_sysz *sysz; + int i; + + // detail can be NULL on "data" instruction if SKIPDATA option is turned ON + if (ins->detail == NULL) + return; + + sysz = &(ins->detail->sysz); + if (sysz->op_count) + printf("\top_count: %u\n", sysz->op_count); + + for (i = 0; i < sysz->op_count; i++) { + cs_sysz_op *op = &(sysz->operands[i]); + switch((int)op->type) { + default: + break; + case SYSZ_OP_REG: + printf("\t\toperands[%u].type: REG = %s\n", i, cs_reg_name(handle, op->reg)); + break; + case SYSZ_OP_ACREG: + printf("\t\toperands[%u].type: ACREG = %u\n", i, op->reg); + break; + case SYSZ_OP_IMM: + printf("\t\toperands[%u].type: IMM = 0x%" PRIx64 "\n", i, op->imm); + break; + case SYSZ_OP_MEM: + printf("\t\toperands[%u].type: MEM\n", i); + if (op->mem.base != SYSZ_REG_INVALID) + printf("\t\t\toperands[%u].mem.base: REG = %s\n", + i, cs_reg_name(handle, op->mem.base)); + if (op->mem.index != SYSZ_REG_INVALID) + printf("\t\t\toperands[%u].mem.index: REG = %s\n", + i, cs_reg_name(handle, op->mem.index)); + if (op->mem.length != 0) + printf("\t\t\toperands[%u].mem.length: 0x%" PRIx64 "\n", i, op->mem.length); + if (op->mem.disp != 0) + printf("\t\t\toperands[%u].mem.disp: 0x%" PRIx64 "\n", i, op->mem.disp); + + break; + } + } + + if (sysz->cc != 0) + printf("\tCode condition: %u\n", sysz->cc); + + printf("\n"); +} + +static void test() +{ +#define SYSZ_CODE "\xed\x00\x00\x00\x00\x1a\x5a\x0f\x1f\xff\xc2\x09\x80\x00\x00\x00\x07\xf7\xeb\x2a\xff\xff\x7f\x57\xe3\x01\xff\xff\x7f\x57\xeb\x00\xf0\x00\x00\x24\xb2\x4f\x00\x78\xec\x18\x00\x00\xc1\x7f" + + struct platform platforms[] = { + { + CS_ARCH_SYSZ, + CS_MODE_BIG_ENDIAN, + (unsigned char*)SYSZ_CODE, + sizeof(SYSZ_CODE) - 1, + "SystemZ", + }, + }; + + uint64_t address = 0x1000; + cs_insn *insn; + int i; + size_t count; + + for (i = 0; i < sizeof(platforms)/sizeof(platforms[0]); i++) { + cs_err err = cs_open(platforms[i].arch, platforms[i].mode, &handle); + if (err) { + printf("Failed on cs_open() with error returned: %u\n", err); + abort(); + } + + cs_option(handle, CS_OPT_DETAIL, CS_OPT_ON); + + count = cs_disasm(handle, platforms[i].code, platforms[i].size, address, 0, &insn); + if (count) { + size_t j; + + printf("****************\n"); + printf("Platform: %s\n", platforms[i].comment); + print_string_hex("Code:", platforms[i].code, platforms[i].size); + printf("Disasm:\n"); + + for (j = 0; j < count; j++) { + printf("0x%" PRIx64 ":\t%s\t%s\n", insn[j].address, insn[j].mnemonic, insn[j].op_str); + print_insn_detail(&insn[j]); + } + printf("0x%" PRIx64 ":\n", insn[j-1].address + insn[j-1].size); + + // free memory allocated by cs_disasm() + cs_free(insn, count); + } else { + printf("****************\n"); + printf("Platform: %s\n", platforms[i].comment); + print_string_hex("Code:", platforms[i].code, platforms[i].size); + printf("ERROR: Failed to disasm given code!\n"); + abort(); + } + + printf("\n"); + + cs_close(&handle); + } +} + +int main() +{ + test(); + + return 0; +} diff --git a/capstone/tests/test_tms320c64x.c b/capstone/tests/test_tms320c64x.c new file mode 100644 index 000000000..86a6d76d7 --- /dev/null +++ b/capstone/tests/test_tms320c64x.c @@ -0,0 +1,193 @@ +/* Capstone Disassembly Engine */ +/* TMS320C64x Backend by Fotis Loukos <me@fotisl.com> 2016 */ + +#include <stdio.h> + +#include <capstone/capstone.h> + +struct platform { + cs_arch arch; + cs_mode mode; + unsigned char *code; + size_t size; + const char *comment; +}; + +static csh handle; + +static 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"); +} + +static void print_insn_detail(cs_insn *ins) +{ + cs_tms320c64x *tms320c64x; + int i; + + // detail can be NULL on "data" instruction if SKIPDATA option is turned ON + if (ins->detail == NULL) + return; + + tms320c64x = &(ins->detail->tms320c64x); + if (tms320c64x->op_count) + printf("\top_count: %u\n", tms320c64x->op_count); + + for (i = 0; i < tms320c64x->op_count; i++) { + cs_tms320c64x_op *op = &(tms320c64x->operands[i]); + switch((int)op->type) { + default: + break; + case TMS320C64X_OP_REG: + printf("\t\toperands[%u].type: REG = %s\n", i, cs_reg_name(handle, op->reg)); + break; + case TMS320C64X_OP_IMM: + printf("\t\toperands[%u].type: IMM = 0x%x\n", i, op->imm); + break; + case TMS320C64X_OP_MEM: + printf("\t\toperands[%u].type: MEM\n", i); + if (op->mem.base != TMS320C64X_REG_INVALID) + printf("\t\t\toperands[%u].mem.base: REG = %s\n", + i, cs_reg_name(handle, op->mem.base)); + printf("\t\t\toperands[%u].mem.disptype: ", i); + if(op->mem.disptype == TMS320C64X_MEM_DISP_INVALID) { + printf("Invalid\n"); + printf("\t\t\toperands[%u].mem.disp: %u\n", i, op->mem.disp); + } + if(op->mem.disptype == TMS320C64X_MEM_DISP_CONSTANT) { + printf("Constant\n"); + printf("\t\t\toperands[%u].mem.disp: %u\n", i, op->mem.disp); + } + if(op->mem.disptype == TMS320C64X_MEM_DISP_REGISTER) { + printf("Register\n"); + printf("\t\t\toperands[%u].mem.disp: %s\n", i, cs_reg_name(handle, op->mem.disp)); + } + printf("\t\t\toperands[%u].mem.unit: %u\n", i, op->mem.unit); + printf("\t\t\toperands[%u].mem.direction: ", i); + if(op->mem.direction == TMS320C64X_MEM_DIR_INVALID) + printf("Invalid\n"); + if(op->mem.direction == TMS320C64X_MEM_DIR_FW) + printf("Forward\n"); + if(op->mem.direction == TMS320C64X_MEM_DIR_BW) + printf("Backward\n"); + printf("\t\t\toperands[%u].mem.modify: ", i); + if(op->mem.modify == TMS320C64X_MEM_MOD_INVALID) + printf("Invalid\n"); + if(op->mem.modify == TMS320C64X_MEM_MOD_NO) + printf("No\n"); + if(op->mem.modify == TMS320C64X_MEM_MOD_PRE) + printf("Pre\n"); + if(op->mem.modify == TMS320C64X_MEM_MOD_POST) + printf("Post\n"); + printf("\t\t\toperands[%u].mem.scaled: %u\n", i, op->mem.scaled); + + + break; + case TMS320C64X_OP_REGPAIR: + printf("\t\toperands[%u].type: REGPAIR = %s:%s\n", i, cs_reg_name(handle, op->reg + 1), cs_reg_name(handle, op->reg)); + break; + } + } + + printf("\tFunctional unit: "); + switch(tms320c64x->funit.unit) { + case TMS320C64X_FUNIT_D: + printf("D%u\n", tms320c64x->funit.side); + break; + case TMS320C64X_FUNIT_L: + printf("L%u\n", tms320c64x->funit.side); + break; + case TMS320C64X_FUNIT_M: + printf("M%u\n", tms320c64x->funit.side); + break; + case TMS320C64X_FUNIT_S: + printf("S%u\n", tms320c64x->funit.side); + break; + case TMS320C64X_FUNIT_NO: + printf("No Functional Unit\n"); + break; + default: + printf("Unknown (Unit %u, Side %u)\n", tms320c64x->funit.unit, tms320c64x->funit.side); + break; + } + if(tms320c64x->funit.crosspath == 1) + printf("\tCrosspath: 1\n"); + + if(tms320c64x->condition.reg != TMS320C64X_REG_INVALID) + printf("\tCondition: [%c%s]\n", (tms320c64x->condition.zero == 1) ? '!' : ' ', cs_reg_name(handle, tms320c64x->condition.reg)); + printf("\tParallel: %s\n", (tms320c64x->parallel == 1) ? "true" : "false"); + + printf("\n"); +} + +static void test() +{ +#define TMS320C64X_CODE "\x01\xac\x88\x40\x81\xac\x88\x43\x00\x00\x00\x00\x02\x90\x32\x96\x02\x80\x46\x9e\x05\x3c\x83\xe6\x0b\x0c\x8b\x24" + + struct platform platforms[] = { + { + CS_ARCH_TMS320C64X, + CS_MODE_BIG_ENDIAN, + (unsigned char*)TMS320C64X_CODE, + sizeof(TMS320C64X_CODE) - 1, + "TMS320C64x", + }, + }; + + uint64_t address = 0x1000; + cs_insn *insn; + int i; + size_t count; + + for (i = 0; i < sizeof(platforms)/sizeof(platforms[0]); i++) { + cs_err err = cs_open(platforms[i].arch, platforms[i].mode, &handle); + if (err) { + printf("Failed on cs_open() with error returned: %u\n", err); + continue; + } + + cs_option(handle, CS_OPT_DETAIL, CS_OPT_ON); + + count = cs_disasm(handle, platforms[i].code, platforms[i].size, address, 0, &insn); + if (count) { + size_t j; + + printf("****************\n"); + printf("Platform: %s\n", platforms[i].comment); + print_string_hex("Code:", platforms[i].code, platforms[i].size); + printf("Disasm:\n"); + + for (j = 0; j < count; j++) { + printf("0x%"PRIx64":\t%s\t%s\n", insn[j].address, insn[j].mnemonic, insn[j].op_str); + print_insn_detail(&insn[j]); + } + printf("0x%"PRIx64":\n", insn[j-1].address + insn[j-1].size); + + // free memory allocated by cs_disasm() + cs_free(insn, count); + } else { + printf("****************\n"); + printf("Platform: %s\n", platforms[i].comment); + print_string_hex("Code:", platforms[i].code, platforms[i].size); + printf("ERROR: Failed to disasm given code!\n"); + } + + printf("\n"); + + cs_close(&handle); + } +} + +int main() +{ + test(); + + return 0; +} diff --git a/capstone/tests/test_wasm.c b/capstone/tests/test_wasm.c new file mode 100644 index 000000000..0f98bdf60 --- /dev/null +++ b/capstone/tests/test_wasm.c @@ -0,0 +1,149 @@ +/* Capstone Disassembler Engine */ +/* By Spike <spikeinhouse@gmail.com>, 2018 */ + +#include <stdio.h> +#include <stdlib.h> + +#include <capstone/platform.h> +#include <capstone/capstone.h> + +static csh handle; + +struct platform { + cs_arch arch; + cs_mode mode; + unsigned char *code; + size_t size; + const char *comment; +}; + +static 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"); +} + +static void print_insn_detail(csh cs_handle, cs_insn *ins) +{ + cs_wasm *wasm; + + // detail can be NULL on "data" instruction if SKIPDATA option is turned ON + if (ins->detail == NULL) + return; + + 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"); + } + + wasm = &(ins->detail->wasm); + + if (wasm->op_count > 0) { + unsigned int i; + + printf("\tOperand count: %u\n", wasm->op_count); + + for (i = 0; i < wasm->op_count; i++) { + switch (wasm->operands[i].type) { + default: + break; + case WASM_OP_INT7: + printf("\t\tOperand[%u] type: int7\n", i); + printf("\t\tOperand[%u] value: %d\n", i, wasm->operands[i].int7); + break; + case WASM_OP_UINT32: + printf("\t\tOperand[%u] type: uint32\n", i); + printf("\t\tOperand[%u] value: 0x%x\n", i, wasm->operands[i].uint32); + break; + case WASM_OP_UINT64: + printf("\t\tOperand[%u] type: uint64\n", i); + printf("\t\tOperand[%u] value: 0x%" PRIx64 "\n", i, wasm->operands[i].uint64); + break; + case WASM_OP_VARUINT32: + printf("\t\tOperand[%u] type: varuint32\n", i); + printf("\t\tOperand[%u] value: 0x%x\n", i, wasm->operands[i].varuint32); + break; + case WASM_OP_VARUINT64: + printf("\t\tOperand[%u] type: varuint64\n", i); + printf("\t\tOperand[%u] value: 0x%" PRIx64 "\n", i, wasm->operands[i].varuint64); + break; + } + printf("\t\tOperand[%u] size: %u\n", i, wasm->operands[i].size); + } + } +} + +static void test() +{ +#define WASM_CODE "\x20\x00\x20\x01\x41\x20\x10\xc9\x01\x45\x0b" + struct platform platforms[] = { + { + CS_ARCH_WASM, + 0, + (unsigned char *)WASM_CODE, + sizeof(WASM_CODE) - 1, + "WASM" + }, + }; + + uint64_t address = 0xffff; + cs_insn *insn; + size_t count; + int i; + + for (i = 0; i < sizeof(platforms)/sizeof(platforms[0]); i++) { + cs_err err = cs_open(platforms[i].arch, platforms[i].mode, &handle); + if (err) { + printf("Failed on cs_open() with error returned: %u\n", err); + abort(); + } + + cs_option(handle, CS_OPT_DETAIL, CS_OPT_ON); + + count = cs_disasm(handle, platforms[i].code, platforms[i].size, address, 0, &insn); + if (count) { + size_t j; + printf("****************\n"); + printf("Platform: %s\n", platforms[i].comment); + print_string_hex("Code: ", platforms[i].code, platforms[i].size); + printf("Disasm:\n"); + + for (j = 0; j < count; j++) { + printf("0x%" PRIx64 ":\t%s\t%s\n", insn[j].address, insn[j].mnemonic, insn[j].op_str); + print_insn_detail(handle, &insn[j]); + } + printf("0x%" PRIx64 ":\n", insn[j-1].address + insn[j-1].size); + + // free memory allocated by cs_disasm() + cs_free(insn, count); + } else { + printf("****************\n"); + printf("Platform: %s\n", platforms[i].comment); + print_string_hex("Code: ", platforms[i].code, platforms[i].size); + printf("ERROR: Failed to disasm given code!\n"); + abort(); + } + + printf("\n"); + + cs_close(&handle); + } +} + +int main() +{ + test(); + return 0; +} + diff --git a/capstone/tests/test_winkernel.cpp b/capstone/tests/test_winkernel.cpp new file mode 100644 index 000000000..6413b1a2c --- /dev/null +++ b/capstone/tests/test_winkernel.cpp @@ -0,0 +1,172 @@ +/* Capstone Disassembly Engine */ +/* By Satoshi Tanda <tanda.sat@gmail.com>, 2016 */ + +#include <ntddk.h> + +#include <capstone/platform.h> +#include <capstone/capstone.h> + +#ifdef __cplusplus +extern "C" { +#endif + +#include "../utils.h" // for cs_snprintf + +#ifdef __cplusplus +} +#endif + +EXTERN_C DRIVER_INITIALIZE DriverEntry; + +#pragma warning(push) +#pragma warning(disable : 4005) // 'identifier' : macro redefinition +#pragma warning(disable : 4007) // 'main': must be '__cdecl' + +// Drivers must protect floating point hardware state. See use of float. +// Use KeSaveFloatingPointState/KeRestoreFloatingPointState around floating +// point operations. Display Drivers should use the corresponding Eng... routines. +#pragma warning(disable : 28110) // Suppress this, as it is false positive. + +// "Import" existing tests into this file. All code is encaptured into unique +// namespace so that the same name does not conflict. Beware that those code +// is going to be compiled as C++ source file and not C files because this file +// is C++. + +namespace basic { +#include "test_basic.c" +} // namespace basic + +namespace detail { +#include "test_detail.c" +} // namespace detail + +namespace skipdata { +#include "test_skipdata.c" +} // namespace skipdata + +namespace iter { +#include "test_iter.c" +} // namespace iter + +namespace customized_mnem_ { +#include "test_customized_mnem.c" +} // namespace customized_mnem_ + +namespace arm { +#include "test_arm.c" +} // namespace arm + +namespace arm64 { +#include "test_arm64.c" +} // namespace arm64 + +namespace mips { +#include "test_mips.c" +} // namespace mips + +namespace m68k { +#include "test_m68k.c" +} // namespace m68k + +namespace ppc { +#include "test_ppc.c" +} // namespace ppc + +namespace sparc { +#include "test_sparc.c" +} // namespace sparc + +namespace systemz { +#include "test_systemz.c" +} // namespace systemz + +namespace x86 { +#include "test_x86.c" +} // namespace x86 + +namespace xcore { +#include "test_xcore.c" +} // namespace xcore + +#pragma warning(pop) + +// Exercises all existing regression tests +static void test() +{ + KFLOATING_SAVE float_save; + NTSTATUS status; + + // Any of Capstone APIs cannot be called at IRQL higher than DISPATCH_LEVEL + // since our malloc implementation using ExAllocatePoolWithTag() is able to + // allocate memory only up to the DISPATCH_LEVEL level. + NT_ASSERT(KeGetCurrentIrql() <= DISPATCH_LEVEL); + + // On a 32bit driver, KeSaveFloatingPointState() is required before using any + // Capstone function because Capstone can access to the MMX/x87 registers and + // 32bit Windows requires drivers to use KeSaveFloatingPointState() before and + // KeRestoreFloatingPointState() after accessing them. See "Using Floating + // Point or MMX in a WDM Driver" on MSDN for more details. + status = KeSaveFloatingPointState(&float_save); + if (!NT_SUCCESS(status)) { + printf("ERROR: Failed to save floating point state!\n"); + return; + } + + basic::test(); + detail::test(); + skipdata::test(); + iter::test(); + customized_mnem_::test(); + arm::test(); + arm64::test(); + mips::test(); + m68k::test(); + ppc::test(); + sparc::test(); + systemz::test(); + x86::test(); + xcore::test(); + + // Restores the nonvolatile floating-point context. + KeRestoreFloatingPointState(&float_save); +} + +// Functional test for cs_winkernel_vsnprintf() +static void cs_winkernel_vsnprintf_test() +{ + char buf[10]; + bool ok = true; + ok = (ok && cs_snprintf(buf, sizeof(buf), "%s", "") == 0 && strcmp(buf, "") == 0); + ok = (ok && cs_snprintf(buf, sizeof(buf), "%s", "0") == 1 && strcmp(buf, "0") == 0); + ok = (ok && cs_snprintf(buf, sizeof(buf), "%s", "012345678") == 9 && strcmp(buf, "012345678") == 0); + ok = (ok && cs_snprintf(buf, sizeof(buf), "%s", "0123456789") == 10 && strcmp(buf, "012345678") == 0); + ok = (ok && cs_snprintf(buf, sizeof(buf), "%s", "01234567890") == 11 && strcmp(buf, "012345678") == 0); + ok = (ok && cs_snprintf(buf, sizeof(buf), "%s", "0123456789001234567890") == 22 && strcmp(buf, "012345678") == 0); + if (!ok) { + printf("ERROR: cs_winkernel_vsnprintf_test() did not produce expected results!\n"); + } +} + +// Driver entry point +EXTERN_C NTSTATUS DriverEntry(PDRIVER_OBJECT DriverObject, PUNICODE_STRING RegistryPath) +{ + UNREFERENCED_PARAMETER(DriverObject); + UNREFERENCED_PARAMETER(RegistryPath); + cs_winkernel_vsnprintf_test(); + test(); + return STATUS_CANCELLED; +} + +// This functions mimics printf() but does not return the same value as printf() +// would do. printf() is required to exercise regression tests. +_Use_decl_annotations_ +int __cdecl printf(const char * format, ...) +{ + NTSTATUS status; + va_list args; + + va_start(args, format); + status = vDbgPrintEx(DPFLTR_DEFAULT_ID, DPFLTR_ERROR_LEVEL, format, args); + va_end(args); + return NT_SUCCESS(status); +} diff --git a/capstone/tests/test_x86.c b/capstone/tests/test_x86.c new file mode 100644 index 000000000..775c096d3 --- /dev/null +++ b/capstone/tests/test_x86.c @@ -0,0 +1,464 @@ +/* Capstone Disassembler Engine */ +/* By Nguyen Anh Quynh <aquynh@gmail.com>, 2013 */ + +#include <stdio.h> +#include <stdlib.h> + +#include <capstone/platform.h> +#include <capstone/capstone.h> + +static csh handle; + +struct platform { + cs_arch arch; + cs_mode mode; + unsigned char *code; + size_t size; + const char *comment; + cs_opt_type opt_type; + cs_opt_value opt_value; +}; + +static 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"); +} + +static const char *get_eflag_name(uint64_t flag) +{ + switch(flag) { + default: + return NULL; + case X86_EFLAGS_UNDEFINED_OF: + return "UNDEF_OF"; + case X86_EFLAGS_UNDEFINED_SF: + return "UNDEF_SF"; + case X86_EFLAGS_UNDEFINED_ZF: + return "UNDEF_ZF"; + case X86_EFLAGS_MODIFY_AF: + return "MOD_AF"; + case X86_EFLAGS_UNDEFINED_PF: + return "UNDEF_PF"; + case X86_EFLAGS_MODIFY_CF: + return "MOD_CF"; + case X86_EFLAGS_MODIFY_SF: + return "MOD_SF"; + case X86_EFLAGS_MODIFY_ZF: + return "MOD_ZF"; + case X86_EFLAGS_UNDEFINED_AF: + return "UNDEF_AF"; + case X86_EFLAGS_MODIFY_PF: + return "MOD_PF"; + case X86_EFLAGS_UNDEFINED_CF: + return "UNDEF_CF"; + case X86_EFLAGS_MODIFY_OF: + return "MOD_OF"; + case X86_EFLAGS_RESET_OF: + return "RESET_OF"; + case X86_EFLAGS_RESET_CF: + return "RESET_CF"; + case X86_EFLAGS_RESET_DF: + return "RESET_DF"; + case X86_EFLAGS_RESET_IF: + return "RESET_IF"; + case X86_EFLAGS_TEST_OF: + return "TEST_OF"; + case X86_EFLAGS_TEST_SF: + return "TEST_SF"; + case X86_EFLAGS_TEST_ZF: + return "TEST_ZF"; + case X86_EFLAGS_TEST_PF: + return "TEST_PF"; + case X86_EFLAGS_TEST_CF: + return "TEST_CF"; + case X86_EFLAGS_RESET_SF: + return "RESET_SF"; + case X86_EFLAGS_RESET_AF: + return "RESET_AF"; + case X86_EFLAGS_RESET_TF: + return "RESET_TF"; + case X86_EFLAGS_RESET_NT: + return "RESET_NT"; + case X86_EFLAGS_PRIOR_OF: + return "PRIOR_OF"; + case X86_EFLAGS_PRIOR_SF: + return "PRIOR_SF"; + case X86_EFLAGS_PRIOR_ZF: + return "PRIOR_ZF"; + case X86_EFLAGS_PRIOR_AF: + return "PRIOR_AF"; + case X86_EFLAGS_PRIOR_PF: + return "PRIOR_PF"; + case X86_EFLAGS_PRIOR_CF: + return "PRIOR_CF"; + case X86_EFLAGS_PRIOR_TF: + return "PRIOR_TF"; + case X86_EFLAGS_PRIOR_IF: + return "PRIOR_IF"; + case X86_EFLAGS_PRIOR_DF: + return "PRIOR_DF"; + case X86_EFLAGS_TEST_NT: + return "TEST_NT"; + case X86_EFLAGS_TEST_DF: + return "TEST_DF"; + case X86_EFLAGS_RESET_PF: + return "RESET_PF"; + case X86_EFLAGS_PRIOR_NT: + return "PRIOR_NT"; + case X86_EFLAGS_MODIFY_TF: + return "MOD_TF"; + case X86_EFLAGS_MODIFY_IF: + return "MOD_IF"; + case X86_EFLAGS_MODIFY_DF: + return "MOD_DF"; + case X86_EFLAGS_MODIFY_NT: + return "MOD_NT"; + case X86_EFLAGS_MODIFY_RF: + return "MOD_RF"; + case X86_EFLAGS_SET_CF: + return "SET_CF"; + case X86_EFLAGS_SET_DF: + return "SET_DF"; + case X86_EFLAGS_SET_IF: + return "SET_IF"; + } +} + +static const char *get_fpu_flag_name(uint64_t flag) +{ + switch (flag) { + default: + return NULL; + case X86_FPU_FLAGS_MODIFY_C0: + return "MOD_C0"; + case X86_FPU_FLAGS_MODIFY_C1: + return "MOD_C1"; + case X86_FPU_FLAGS_MODIFY_C2: + return "MOD_C2"; + case X86_FPU_FLAGS_MODIFY_C3: + return "MOD_C3"; + case X86_FPU_FLAGS_RESET_C0: + return "RESET_C0"; + case X86_FPU_FLAGS_RESET_C1: + return "RESET_C1"; + case X86_FPU_FLAGS_RESET_C2: + return "RESET_C2"; + case X86_FPU_FLAGS_RESET_C3: + return "RESET_C3"; + case X86_FPU_FLAGS_SET_C0: + return "SET_C0"; + case X86_FPU_FLAGS_SET_C1: + return "SET_C1"; + case X86_FPU_FLAGS_SET_C2: + return "SET_C2"; + case X86_FPU_FLAGS_SET_C3: + return "SET_C3"; + case X86_FPU_FLAGS_UNDEFINED_C0: + return "UNDEF_C0"; + case X86_FPU_FLAGS_UNDEFINED_C1: + return "UNDEF_C1"; + case X86_FPU_FLAGS_UNDEFINED_C2: + return "UNDEF_C2"; + case X86_FPU_FLAGS_UNDEFINED_C3: + return "UNDEF_C3"; + case X86_FPU_FLAGS_TEST_C0: + return "TEST_C0"; + case X86_FPU_FLAGS_TEST_C1: + return "TEST_C1"; + case X86_FPU_FLAGS_TEST_C2: + return "TEST_C2"; + case X86_FPU_FLAGS_TEST_C3: + return "TEST_C3"; + } +} + +static void print_insn_detail(csh ud, cs_mode mode, cs_insn *ins) +{ + int count, i; + cs_x86 *x86; + cs_regs regs_read, regs_write; + uint8_t regs_read_count, regs_write_count; + + // detail can be NULL on "data" instruction if SKIPDATA option is turned ON + if (ins->detail == NULL) + return; + + x86 = &(ins->detail->x86); + + print_string_hex("\tPrefix:", x86->prefix, 4); + + print_string_hex("\tOpcode:", x86->opcode, 4); + + printf("\trex: 0x%x\n", x86->rex); + + printf("\taddr_size: %u\n", x86->addr_size); + printf("\tmodrm: 0x%x\n", x86->modrm); + if (x86->encoding.modrm_offset != 0) { + printf("\tmodrm_offset: 0x%x\n", x86->encoding.modrm_offset); + } + + printf("\tdisp: 0x%" PRIx64 "\n", x86->disp); + if (x86->encoding.disp_offset != 0) { + printf("\tdisp_offset: 0x%x\n", x86->encoding.disp_offset); + } + + if (x86->encoding.disp_size != 0) { + printf("\tdisp_size: 0x%x\n", x86->encoding.disp_size); + } + + // SIB is not available in 16-bit mode + if ((mode & CS_MODE_16) == 0) { + printf("\tsib: 0x%x\n", x86->sib); + if (x86->sib_base != X86_REG_INVALID) + printf("\t\tsib_base: %s\n", cs_reg_name(handle, x86->sib_base)); + if (x86->sib_index != X86_REG_INVALID) + printf("\t\tsib_index: %s\n", cs_reg_name(handle, x86->sib_index)); + if (x86->sib_scale != 0) + printf("\t\tsib_scale: %d\n", x86->sib_scale); + } + + // XOP code condition + if (x86->xop_cc != X86_XOP_CC_INVALID) { + printf("\txop_cc: %u\n", x86->xop_cc); + } + + // SSE code condition + if (x86->sse_cc != X86_SSE_CC_INVALID) { + printf("\tsse_cc: %u\n", x86->sse_cc); + } + + // AVX code condition + if (x86->avx_cc != X86_AVX_CC_INVALID) { + printf("\tavx_cc: %u\n", x86->avx_cc); + } + + // AVX Suppress All Exception + if (x86->avx_sae) { + printf("\tavx_sae: %u\n", x86->avx_sae); + } + + // AVX Rounding Mode + if (x86->avx_rm != X86_AVX_RM_INVALID) { + printf("\tavx_rm: %u\n", x86->avx_rm); + } + + // Print out all immediate operands + count = cs_op_count(ud, ins, X86_OP_IMM); + if (count) { + printf("\timm_count: %u\n", count); + for (i = 1; i < count + 1; i++) { + int index = cs_op_index(ud, ins, X86_OP_IMM, i); + printf("\t\timms[%u]: 0x%" PRIx64 "\n", i, x86->operands[index].imm); + if (x86->encoding.imm_offset != 0) { + printf("\timm_offset: 0x%x\n", x86->encoding.imm_offset); + } + + if (x86->encoding.imm_size != 0) { + printf("\timm_size: 0x%x\n", x86->encoding.imm_size); + } + } + } + + if (x86->op_count) + printf("\top_count: %u\n", x86->op_count); + + // Print out all operands + for (i = 0; i < x86->op_count; i++) { + cs_x86_op *op = &(x86->operands[i]); + + switch((int)op->type) { + case X86_OP_REG: + printf("\t\toperands[%u].type: REG = %s\n", i, cs_reg_name(handle, op->reg)); + break; + case X86_OP_IMM: + printf("\t\toperands[%u].type: IMM = 0x%" PRIx64 "\n", i, op->imm); + break; + case X86_OP_MEM: + printf("\t\toperands[%u].type: MEM\n", i); + if (op->mem.segment != X86_REG_INVALID) + printf("\t\t\toperands[%u].mem.segment: REG = %s\n", i, cs_reg_name(handle, op->mem.segment)); + if (op->mem.base != X86_REG_INVALID) + printf("\t\t\toperands[%u].mem.base: REG = %s\n", i, cs_reg_name(handle, op->mem.base)); + if (op->mem.index != X86_REG_INVALID) + printf("\t\t\toperands[%u].mem.index: REG = %s\n", i, cs_reg_name(handle, op->mem.index)); + if (op->mem.scale != 1) + printf("\t\t\toperands[%u].mem.scale: %u\n", i, op->mem.scale); + if (op->mem.disp != 0) + printf("\t\t\toperands[%u].mem.disp: 0x%" PRIx64 "\n", i, op->mem.disp); + break; + default: + break; + } + + // AVX broadcast type + if (op->avx_bcast != X86_AVX_BCAST_INVALID) + printf("\t\toperands[%u].avx_bcast: %u\n", i, op->avx_bcast); + + // AVX zero opmask {z} + if (op->avx_zero_opmask != false) + printf("\t\toperands[%u].avx_zero_opmask: TRUE\n", i); + + printf("\t\toperands[%u].size: %u\n", i, op->size); + + switch(op->access) { + default: + break; + case CS_AC_READ: + printf("\t\toperands[%u].access: READ\n", i); + break; + case CS_AC_WRITE: + printf("\t\toperands[%u].access: WRITE\n", i); + break; + case CS_AC_READ | CS_AC_WRITE: + printf("\t\toperands[%u].access: READ | WRITE\n", i); + break; + } + } + + // Print out all registers accessed by this instruction (either implicit or explicit) + if (!cs_regs_access(ud, ins, + regs_read, ®s_read_count, + regs_write, ®s_write_count)) { + if (regs_read_count) { + printf("\tRegisters read:"); + for(i = 0; i < regs_read_count; i++) { + printf(" %s", cs_reg_name(handle, regs_read[i])); + } + printf("\n"); + } + + if (regs_write_count) { + printf("\tRegisters modified:"); + for(i = 0; i < regs_write_count; i++) { + printf(" %s", cs_reg_name(handle, regs_write[i])); + } + printf("\n"); + } + } + + if (x86->eflags || x86->fpu_flags) { + for(i = 0; i < ins->detail->groups_count; i++) { + if (ins->detail->groups[i] == X86_GRP_FPU) { + printf("\tFPU_FLAGS:"); + for(i = 0; i <= 63; i++) + if (x86->fpu_flags & ((uint64_t)1 << i)) { + printf(" %s", get_fpu_flag_name((uint64_t)1 << i)); + } + printf("\n"); + break; + } + } + + if (i == ins->detail->groups_count) { + printf("\tEFLAGS:"); + for(i = 0; i <= 63; i++) + if (x86->eflags & ((uint64_t)1 << i)) { + printf(" %s", get_eflag_name((uint64_t)1 << i)); + } + printf("\n"); + } + } + + printf("\n"); +} + +static void test() +{ +#define X86_CODE64 "\x55\x48\x8b\x05\xb8\x13\x00\x00\xe9\xea\xbe\xad\xde\xff\x25\x23\x01\x00\x00\xe8\xdf\xbe\xad\xde\x74\xff" +#define X86_CODE16 "\x8d\x4c\x32\x08\x01\xd8\x81\xc6\x34\x12\x00\x00\x05\x23\x01\x00\x00\x36\x8b\x84\x91\x23\x01\x00\x00\x41\x8d\x84\x39\x89\x67\x00\x00\x8d\x87\x89\x67\x00\x00\xb4\xc6\x66\xe9\xb8\x00\x00\x00\x67\xff\xa0\x23\x01\x00\x00\x66\xe8\xcb\x00\x00\x00\x74\xfc" +#define X86_CODE32 "\x8d\x4c\x32\x08\x01\xd8\x81\xc6\x34\x12\x00\x00\x05\x23\x01\x00\x00\x36\x8b\x84\x91\x23\x01\x00\x00\x41\x8d\x84\x39\x89\x67\x00\x00\x8d\x87\x89\x67\x00\x00\xb4\xc6\xe9\xea\xbe\xad\xde\xff\xa0\x23\x01\x00\x00\xe8\xdf\xbe\xad\xde\x74\xff" + + struct platform platforms[] = { + { + CS_ARCH_X86, + CS_MODE_16, + (unsigned char *)X86_CODE16, + sizeof(X86_CODE16) - 1, + "X86 16bit (Intel syntax)" + }, + { + CS_ARCH_X86, + CS_MODE_32, + (unsigned char *)X86_CODE32, + sizeof(X86_CODE32) - 1, + "X86 32 (AT&T syntax)", + CS_OPT_SYNTAX, + CS_OPT_SYNTAX_ATT, + }, + { + CS_ARCH_X86, + CS_MODE_32, + (unsigned char *)X86_CODE32, + sizeof(X86_CODE32) - 1, + "X86 32 (Intel syntax)" + }, + { + CS_ARCH_X86, + CS_MODE_64, + (unsigned char *)X86_CODE64, + sizeof(X86_CODE64) - 1, + "X86 64 (Intel syntax)" + }, + }; + + uint64_t address = 0x1000; + cs_insn *insn; + int i; + size_t count; + + for (i = 0; i < sizeof(platforms)/sizeof(platforms[0]); i++) { + cs_err err = cs_open(platforms[i].arch, platforms[i].mode, &handle); + if (err) { + printf("Failed on cs_open() with error returned: %u\n", err); + abort(); + } + + if (platforms[i].opt_type) + cs_option(handle, platforms[i].opt_type, platforms[i].opt_value); + + cs_option(handle, CS_OPT_DETAIL, CS_OPT_ON); + + count = cs_disasm(handle, platforms[i].code, platforms[i].size, address, 0, &insn); + if (count) { + size_t j; + + printf("****************\n"); + printf("Platform: %s\n", platforms[i].comment); + print_string_hex("Code:", platforms[i].code, platforms[i].size); + printf("Disasm:\n"); + + for (j = 0; j < count; j++) { + printf("0x%" PRIx64 ":\t%s\t%s\n", insn[j].address, insn[j].mnemonic, insn[j].op_str); + print_insn_detail(handle, platforms[i].mode, &insn[j]); + } + printf("0x%" PRIx64 ":\n", insn[j-1].address + insn[j-1].size); + + // free memory allocated by cs_disasm() + cs_free(insn, count); + } else { + printf("****************\n"); + printf("Platform: %s\n", platforms[i].comment); + print_string_hex("Code:", platforms[i].code, platforms[i].size); + printf("ERROR: Failed to disasm given code!\n"); + abort(); + } + + printf("\n"); + + cs_close(&handle); + } +} + +int main() +{ + test(); + + return 0; +} diff --git a/capstone/tests/test_xcore.c b/capstone/tests/test_xcore.c new file mode 100644 index 000000000..12cc1f1bb --- /dev/null +++ b/capstone/tests/test_xcore.c @@ -0,0 +1,140 @@ +/* Capstone Disassembler Engine */ +/* By Nguyen Anh Quynh <aquynh@gmail.com>, 2013-2014 */ + +#include <stdio.h> + +#include <capstone/platform.h> +#include <capstone/capstone.h> + +struct platform { + cs_arch arch; + cs_mode mode; + unsigned char *code; + size_t size; + const char *comment; +}; + +static csh handle; + +static 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"); +} + +static void print_insn_detail(cs_insn *ins) +{ + cs_xcore *xcore; + int i; + + // detail can be NULL on "data" instruction if SKIPDATA option is turned ON + if (ins->detail == NULL) + return; + + xcore = &(ins->detail->xcore); + if (xcore->op_count) + printf("\top_count: %u\n", xcore->op_count); + + for (i = 0; i < xcore->op_count; i++) { + cs_xcore_op *op = &(xcore->operands[i]); + switch((int)op->type) { + default: + break; + case XCORE_OP_REG: + printf("\t\toperands[%u].type: REG = %s\n", i, cs_reg_name(handle, op->reg)); + break; + case XCORE_OP_IMM: + printf("\t\toperands[%u].type: IMM = 0x%x\n", i, op->imm); + break; + case XCORE_OP_MEM: + printf("\t\toperands[%u].type: MEM\n", i); + if (op->mem.base != XCORE_REG_INVALID) + printf("\t\t\toperands[%u].mem.base: REG = %s\n", + i, cs_reg_name(handle, op->mem.base)); + if (op->mem.index != XCORE_REG_INVALID) + printf("\t\t\toperands[%u].mem.index: REG = %s\n", + i, cs_reg_name(handle, op->mem.index)); + if (op->mem.disp != 0) + printf("\t\t\toperands[%u].mem.disp: 0x%x\n", i, op->mem.disp); + if (op->mem.direct != 1) + printf("\t\t\toperands[%u].mem.direct: -1\n", i); + + + break; + } + } + + printf("\n"); +} + +static void test() +{ +#define XCORE_CODE "\xfe\x0f\xfe\x17\x13\x17\xc6\xfe\xec\x17\x97\xf8\xec\x4f\x1f\xfd\xec\x37\x07\xf2\x45\x5b\xf9\xfa\x02\x06\x1b\x10\x09\xfd\xec\xa7" + + struct platform platforms[] = { + { + CS_ARCH_XCORE, + CS_MODE_BIG_ENDIAN, + (unsigned char*)XCORE_CODE, + sizeof(XCORE_CODE) - 1, + "XCore", + }, + }; + + uint64_t address = 0x1000; + cs_insn *insn; + int i; + size_t count; + + for (i = 0; i < sizeof(platforms)/sizeof(platforms[0]); i++) { + cs_err err = cs_open(platforms[i].arch, platforms[i].mode, &handle); + if (err) { + printf("Failed on cs_open() with error returned: %u\n", err); + abort(); + } + + cs_option(handle, CS_OPT_DETAIL, CS_OPT_ON); + + count = cs_disasm(handle, platforms[i].code, platforms[i].size, address, 0, &insn); + if (count) { + size_t j; + + printf("****************\n"); + printf("Platform: %s\n", platforms[i].comment); + print_string_hex("Code:", platforms[i].code, platforms[i].size); + printf("Disasm:\n"); + + for (j = 0; j < count; j++) { + printf("0x%" PRIx64 ":\t%s\t%s\n", insn[j].address, insn[j].mnemonic, insn[j].op_str); + print_insn_detail(&insn[j]); + } + printf("0x%" PRIx64 ":\n", insn[j-1].address + insn[j-1].size); + + // free memory allocated by cs_disasm() + cs_free(insn, count); + } else { + printf("****************\n"); + printf("Platform: %s\n", platforms[i].comment); + print_string_hex("Code:", platforms[i].code, platforms[i].size); + printf("ERROR: Failed to disasm given code!\n"); + abort(); + } + + printf("\n"); + + cs_close(&handle); + } +} + +int main() +{ + test(); + + return 0; +} |