From 87221fa742193ac18742db718f58d1a22ad9b1d0 Mon Sep 17 00:00:00 2001 From: Sebastian Macke Date: Sun, 2 Dec 2018 21:39:41 +0100 Subject: [PATCH] Add support for the MOS65XX family such as the MOS 6502. Signed-off-by: Sebastian Macke --- CMakeLists.txt | 20 +- Makefile | 18 +- arch/MOS65XX/MOS65XXDisassembler.c | 591 +++++++++++++++++++++++++++++ arch/MOS65XX/MOS65XXDisassembler.h | 22 ++ arch/MOS65XX/MOS65XXModule.c | 32 ++ arch/MOS65XX/MOS65XXModule.h | 12 + config.mk | 2 +- cs.c | 39 +- cstool/cstool.c | 8 + cstool/cstool_mos65xx.c | 76 ++++ include/capstone/capstone.h | 4 + include/capstone/mos65xx.h | 148 ++++++++ tests/Makefile | 4 + tests/test_detail.c | 12 + tests/test_iter.c | 13 + tests/test_mos65xx.c | 168 ++++++++ 16 files changed, 1163 insertions(+), 6 deletions(-) create mode 100644 arch/MOS65XX/MOS65XXDisassembler.c create mode 100644 arch/MOS65XX/MOS65XXDisassembler.h create mode 100644 arch/MOS65XX/MOS65XXModule.c create mode 100644 arch/MOS65XX/MOS65XXModule.h create mode 100644 cstool/cstool_mos65xx.c create mode 100644 include/capstone/mos65xx.h create mode 100644 tests/test_mos65xx.c diff --git a/CMakeLists.txt b/CMakeLists.txt index c4848a8c..8bfc689d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -28,8 +28,8 @@ option(CAPSTONE_BUILD_TESTS "Build tests" ON) option(CAPSTONE_BUILD_CSTOOL "Build cstool" ON) option(CAPSTONE_USE_DEFAULT_ALLOC "Use default memory allocation functions" ON) -set(SUPPORTED_ARCHITECTURES ARM ARM64 M68K MIPS PPC SPARC SYSZ XCORE X86 TMS320C64X M680X EVM) -set(SUPPORTED_ARCHITECTURE_LABELS ARM ARM64 M68K MIPS PowerPC Sparc SystemZ XCore x86 TMS320C64x M680x EVM) +set(SUPPORTED_ARCHITECTURES ARM ARM64 M68K MIPS PPC SPARC SYSZ XCORE X86 TMS320C64X M680X EVM MOS65XX) +set(SUPPORTED_ARCHITECTURE_LABELS ARM ARM64 M68K MIPS PowerPC Sparc SystemZ XCore x86 TMS320C64x M680x EVM MOS65XX) list(LENGTH SUPPORTED_ARCHITECTURES count) math(EXPR count "${count}-1") @@ -112,6 +112,7 @@ set(HEADERS_COMMON include/capstone/m68k.h include/capstone/tms320c64x.h include/capstone/m680x.h + include/capstone/mos65xx.h include/capstone/platform.h ) @@ -444,6 +445,17 @@ if (CAPSTONE_EVM_SUPPORT) set(TEST_SOURCES ${TEST_SOURCES} test_evm.c) endif () +if (CAPSTONE_MOS65XX_SUPPORT) + add_definitions(-DCAPSTONE_HAS_MOS65XX) + set(SOURCES_MOS65XX + arch/MOS65XX/MOS65XXModule.c + arch/MOS65XX/MOS65XXDisassembler.c) + set(HEADERS_SOURCES_MOS65XX + arch/MOS65XX/MOS65XXDisassembler.h + ) + set(TEST_SOURCES ${TEST_SOURCES} test_mos65xx.c) +endif () + if (CAPSTONE_OSXKERNEL_SUPPORT) add_definitions(-DCAPSTONE_HAS_OSXKERNEL) endif () @@ -462,6 +474,7 @@ set(ALL_SOURCES ${SOURCES_TMS320C64X} ${SOURCES_M680X} ${SOURCES_EVM} + ${SOURCES_MOS65XX} ) set(ALL_HEADERS @@ -479,6 +492,7 @@ set(ALL_HEADERS ${HEADERS_TMS320C64X} ${HEADERS_M680X} ${HEADERS_EVM} + ${HEADERS_MOS65XX} ) include_directories("${PROJECT_SOURCE_DIR}/include") @@ -559,6 +573,7 @@ source_group("Source\\M68K" FILES ${SOURCES_M68K}) source_group("Source\\TMS320C64x" FILES ${SOURCES_TMS320C64X}) source_group("Source\\M680X" FILES ${SOURCES_M680X}) source_group("Source\\EVM" FILES ${SOURCES_EVM}) +source_group("Source\\MOS65XX" FILES ${SOURCES_MOS65XX}) source_group("Include\\Common" FILES ${HEADERS_COMMON}) source_group("Include\\Engine" FILES ${HEADERS_ENGINE}) @@ -574,6 +589,7 @@ source_group("Include\\M68K" FILES ${HEADERS_M68K}) source_group("Include\\TMS320C64x" FILES ${HEADERS_TMS320C64X}) source_group("Include\\M680X" FILES ${HEADERS_MC680X}) source_group("Include\\EVM" FILES ${HEADERS_EVM}) +source_group("Include\\MOS65XX" FILES ${HEADERS_MOS65XX}) ### test library 64bit routine: get_property(LIB64 GLOBAL PROPERTY FIND_LIBRARY_USE_LIB64_PATHS) diff --git a/Makefile b/Makefile index 93508d77..36ab08a9 100644 --- a/Makefile +++ b/Makefile @@ -250,9 +250,21 @@ ifneq (,$(findstring evm,$(CAPSTONE_ARCHS))) endif +DEP_MOS65XX = +DEP_MOS65XX += $(wildcard arch/MOS65XX/MOS65XX*.inc) + +LIBOBJ_MOS65XX = +ifneq (,$(findstring mos65xx,$(CAPSTONE_ARCHS))) + CFLAGS += -DCAPSTONE_HAS_MOS65XX + LIBSRC_MOS65XX += $(wildcard arch/MOS65XX/MOS65XX*.c) + LIBOBJ_MOS65XX += $(LIBSRC_MOS65XX:%.c=$(OBJDIR)/%.o) +endif + + LIBOBJ = LIBOBJ += $(OBJDIR)/cs.o $(OBJDIR)/utils.o $(OBJDIR)/SStream.o $(OBJDIR)/MCInstrDesc.o $(OBJDIR)/MCRegisterInfo.o -LIBOBJ += $(LIBOBJ_ARM) $(LIBOBJ_ARM64) $(LIBOBJ_M68K) $(LIBOBJ_MIPS) $(LIBOBJ_PPC) $(LIBOBJ_SPARC) $(LIBOBJ_SYSZ) $(LIBOBJ_X86) $(LIBOBJ_XCORE) $(LIBOBJ_TMS320C64X) $(LIBOBJ_M680X) $(LIBOBJ_EVM) +LIBOBJ += $(LIBOBJ_ARM) $(LIBOBJ_ARM64) $(LIBOBJ_M68K) $(LIBOBJ_MIPS) $(LIBOBJ_PPC) $(LIBOBJ_SPARC) $(LIBOBJ_SYSZ) +LIBOBJ += $(LIBOBJ_X86) $(LIBOBJ_XCORE) $(LIBOBJ_TMS320C64X) $(LIBOBJ_M680X) $(LIBOBJ_EVM) $(LIBOBJ_MOS65XX) LIBOBJ += $(OBJDIR)/MCInst.o @@ -381,6 +393,7 @@ $(LIBOBJ_XCORE): $(DEP_XCORE) $(LIBOBJ_TMS320C64X): $(DEP_TMS320C64X) $(LIBOBJ_M680X): $(DEP_M680X) $(LIBOBJ_EVM): $(DEP_EVM) +$(LIBOBJ_MOS65XX): $(DEP_MOS65XX) ifeq ($(CAPSTONE_STATIC),yes) $(ARCHIVE): $(LIBOBJ) @@ -456,11 +469,12 @@ dist: TESTS = test_basic test_detail test_arm test_arm64 test_m68k test_mips test_ppc test_sparc -TESTS += test_systemz test_x86 test_xcore test_iter test_evm +TESTS += test_systemz test_x86 test_xcore test_iter test_evm test_mos65xx TESTS += test_basic.static test_detail.static test_arm.static test_arm64.static TESTS += test_m68k.static test_mips.static test_ppc.static test_sparc.static TESTS += test_systemz.static test_x86.static test_xcore.static test_m680x.static TESTS += test_skipdata test_skipdata.static test_iter.static test_evm.static +TESTS += test_mos65xx.static check: $(TESTS) fuzztest test_%: ./tests/$@ > /dev/null && echo OK || echo FAILED diff --git a/arch/MOS65XX/MOS65XXDisassembler.c b/arch/MOS65XX/MOS65XXDisassembler.c new file mode 100644 index 00000000..08473f62 --- /dev/null +++ b/arch/MOS65XX/MOS65XXDisassembler.c @@ -0,0 +1,591 @@ +/* Capstone Disassembly Engine */ +/* MOS65XX Backend by Sebastian Macke 2018 */ + +#include "capstone/mos65xx.h" +#include "MOS65XXDisassembler.h" + +typedef struct OpInfo { + mos65xx_insn ins; + mos65xx_address_mode am; +} OpInfo; + +const struct OpInfo OpInfoTable[]= { + MOS65XX_INS_BRK , MOS65XX_AM_IMP , // 0x00 + MOS65XX_INS_ORA , MOS65XX_AM_INDX, // 0x01 + MOS65XX_INS_INVALID, MOS65XX_AM_NONE, // 0x02 + MOS65XX_INS_INVALID, MOS65XX_AM_NONE, // 0x03 + MOS65XX_INS_NOP , MOS65XX_AM_ZP , // 0x04 + MOS65XX_INS_ORA , MOS65XX_AM_ZP , // 0x05 + MOS65XX_INS_ASL , MOS65XX_AM_ZP , // 0x06 + MOS65XX_INS_INVALID, MOS65XX_AM_NONE, // 0x07 + MOS65XX_INS_PHP , MOS65XX_AM_IMP , // 0x08 + MOS65XX_INS_ORA , MOS65XX_AM_IMM , // 0x09 + MOS65XX_INS_ASL , MOS65XX_AM_ACC , // 0x0a + MOS65XX_INS_INVALID, MOS65XX_AM_NONE, // 0x0b + MOS65XX_INS_NOP , MOS65XX_AM_ABS , // 0x0c + MOS65XX_INS_ORA , MOS65XX_AM_ABS , // 0x0d + MOS65XX_INS_ASL , MOS65XX_AM_ABS , // 0x0e + MOS65XX_INS_INVALID, MOS65XX_AM_NONE, // 0x0f + MOS65XX_INS_BPL , MOS65XX_AM_REL , // 0x10 + MOS65XX_INS_ORA , MOS65XX_AM_INDY, // 0x11 + MOS65XX_INS_INVALID, MOS65XX_AM_NONE, // 0x12 + MOS65XX_INS_INVALID, MOS65XX_AM_NONE, // 0x13 + MOS65XX_INS_NOP , MOS65XX_AM_ZPX , // 0x14 + MOS65XX_INS_ORA , MOS65XX_AM_ZPX , // 0x15 + MOS65XX_INS_ASL , MOS65XX_AM_ZPX , // 0x16 + MOS65XX_INS_INVALID, MOS65XX_AM_NONE, // 0x17 + MOS65XX_INS_CLC , MOS65XX_AM_IMP , // 0x18 + MOS65XX_INS_ORA , MOS65XX_AM_ABSY, // 0x19 + MOS65XX_INS_NOP , MOS65XX_AM_IMP , // 0x1a + MOS65XX_INS_INVALID, MOS65XX_AM_NONE, // 0x1b + MOS65XX_INS_NOP , MOS65XX_AM_ABS , // 0x1c + MOS65XX_INS_ORA , MOS65XX_AM_ABSX, // 0x1d + MOS65XX_INS_ASL , MOS65XX_AM_ABSX, // 0x1e + MOS65XX_INS_INVALID, MOS65XX_AM_NONE, // 0x1f + MOS65XX_INS_JSR , MOS65XX_AM_ABS , // 0x20 + MOS65XX_INS_AND , MOS65XX_AM_INDX, // 0x21 + MOS65XX_INS_INVALID, MOS65XX_AM_NONE, // 0x22 + MOS65XX_INS_INVALID, MOS65XX_AM_NONE, // 0x23 + MOS65XX_INS_BIT , MOS65XX_AM_ZP , // 0x24 + MOS65XX_INS_AND , MOS65XX_AM_ZP , // 0x25 + MOS65XX_INS_ROL , MOS65XX_AM_ZP , // 0x26 + MOS65XX_INS_INVALID, MOS65XX_AM_NONE, // 0x27 + MOS65XX_INS_PLP , MOS65XX_AM_IMP , // 0x28 + MOS65XX_INS_AND , MOS65XX_AM_IMM , // 0x29 + MOS65XX_INS_ROL , MOS65XX_AM_ACC , // 0x2a + MOS65XX_INS_INVALID, MOS65XX_AM_NONE, // 0x2b + MOS65XX_INS_BIT , MOS65XX_AM_ABS , // 0x2c + MOS65XX_INS_AND , MOS65XX_AM_ABS , // 0x2d + MOS65XX_INS_ROL , MOS65XX_AM_ABS , // 0x2e + MOS65XX_INS_INVALID, MOS65XX_AM_NONE, // 0x2f + MOS65XX_INS_BMI , MOS65XX_AM_REL , // 0x30 + MOS65XX_INS_AND , MOS65XX_AM_INDY, // 0x31 + MOS65XX_INS_INVALID, MOS65XX_AM_NONE, // 0x32 + MOS65XX_INS_INVALID, MOS65XX_AM_NONE, // 0x33 + MOS65XX_INS_NOP , MOS65XX_AM_ZPX , // 0x34 + MOS65XX_INS_AND , MOS65XX_AM_ZPX , // 0x35 + MOS65XX_INS_ROL , MOS65XX_AM_ZPX , // 0x36 + MOS65XX_INS_INVALID, MOS65XX_AM_NONE, // 0x37 + MOS65XX_INS_SEC , MOS65XX_AM_IMP , // 0x38 + MOS65XX_INS_AND , MOS65XX_AM_ABSY, // 0x39 + MOS65XX_INS_NOP , MOS65XX_AM_IMP , // 0x3a + MOS65XX_INS_INVALID, MOS65XX_AM_NONE, // 0x3b + MOS65XX_INS_NOP , MOS65XX_AM_ABSX, // 0x3c + MOS65XX_INS_AND , MOS65XX_AM_ABSX, // 0x3d + MOS65XX_INS_ROL , MOS65XX_AM_ABSX, // 0x3e + MOS65XX_INS_INVALID, MOS65XX_AM_NONE, // 0x3f + MOS65XX_INS_RTI , MOS65XX_AM_IMP , // 0x40 + MOS65XX_INS_EOR , MOS65XX_AM_INDX, // 0x41 + MOS65XX_INS_INVALID, MOS65XX_AM_NONE, // 0x42 + MOS65XX_INS_INVALID, MOS65XX_AM_NONE, // 0x43 + MOS65XX_INS_NOP , MOS65XX_AM_ZP , // 0x44 + MOS65XX_INS_EOR , MOS65XX_AM_ZP , // 0x45 + MOS65XX_INS_LSR , MOS65XX_AM_ZP , // 0x46 + MOS65XX_INS_INVALID, MOS65XX_AM_NONE, // 0x47 + MOS65XX_INS_PHA , MOS65XX_AM_IMP , // 0x48 + MOS65XX_INS_EOR , MOS65XX_AM_IMM , // 0x49 + MOS65XX_INS_LSR , MOS65XX_AM_ACC , // 0x4a + MOS65XX_INS_INVALID, MOS65XX_AM_NONE, // 0x4b + MOS65XX_INS_JMP , MOS65XX_AM_ABS , // 0x4c + MOS65XX_INS_EOR , MOS65XX_AM_ABS , // 0x4d + MOS65XX_INS_LSR , MOS65XX_AM_ABS , // 0x4e + MOS65XX_INS_INVALID, MOS65XX_AM_NONE, // 0x4f + MOS65XX_INS_BVC , MOS65XX_AM_REL , // 0x50 + MOS65XX_INS_EOR , MOS65XX_AM_INDY, // 0x51 + MOS65XX_INS_INVALID, MOS65XX_AM_NONE, // 0x52 + MOS65XX_INS_INVALID, MOS65XX_AM_NONE, // 0x53 + MOS65XX_INS_NOP , MOS65XX_AM_ZPX , // 0x54 + MOS65XX_INS_EOR , MOS65XX_AM_ZPX , // 0x55 + MOS65XX_INS_LSR , MOS65XX_AM_ZPX , // 0x56 + MOS65XX_INS_INVALID, MOS65XX_AM_NONE, // 0x57 + MOS65XX_INS_CLI , MOS65XX_AM_IMP , // 0x58 + MOS65XX_INS_EOR , MOS65XX_AM_ABSY, // 0x59 + MOS65XX_INS_NOP , MOS65XX_AM_IMP , // 0x5a + MOS65XX_INS_INVALID, MOS65XX_AM_NONE, // 0x5b + MOS65XX_INS_NOP , MOS65XX_AM_ABSX, // 0x5c + MOS65XX_INS_EOR , MOS65XX_AM_ABSX, // 0x5d + MOS65XX_INS_LSR , MOS65XX_AM_ABSX, // 0x5e + MOS65XX_INS_INVALID, MOS65XX_AM_NONE, // 0x5f + MOS65XX_INS_RTS , MOS65XX_AM_IMP , // 0x60 + MOS65XX_INS_ADC , MOS65XX_AM_INDX, // 0x61 + MOS65XX_INS_INVALID, MOS65XX_AM_NONE, // 0x62 + MOS65XX_INS_INVALID, MOS65XX_AM_NONE, // 0x63 + MOS65XX_INS_NOP , MOS65XX_AM_ZP , // 0x64 + MOS65XX_INS_ADC , MOS65XX_AM_ZP , // 0x65 + MOS65XX_INS_ROR , MOS65XX_AM_ZP , // 0x66 + MOS65XX_INS_INVALID, MOS65XX_AM_NONE, // 0x67 + MOS65XX_INS_PLA , MOS65XX_AM_IMP , // 0x68 + MOS65XX_INS_ADC , MOS65XX_AM_IMM , // 0x69 + MOS65XX_INS_ROR , MOS65XX_AM_ACC , // 0x6a + MOS65XX_INS_INVALID, MOS65XX_AM_NONE, // 0x6b + MOS65XX_INS_JMP , MOS65XX_AM_IND , // 0x6c + MOS65XX_INS_ADC , MOS65XX_AM_ABS , // 0x6d + MOS65XX_INS_ROR , MOS65XX_AM_ABS , // 0x6e + MOS65XX_INS_INVALID, MOS65XX_AM_NONE, // 0x6f + MOS65XX_INS_BVS , MOS65XX_AM_REL , // 0x70 + MOS65XX_INS_ADC , MOS65XX_AM_INDY, // 0x71 + MOS65XX_INS_INVALID, MOS65XX_AM_NONE, // 0x72 + MOS65XX_INS_INVALID, MOS65XX_AM_NONE, // 0x73 + MOS65XX_INS_NOP , MOS65XX_AM_ZPX , // 0x74 + MOS65XX_INS_ADC , MOS65XX_AM_ZPX , // 0x75 + MOS65XX_INS_ROR , MOS65XX_AM_ZPX , // 0x76 + MOS65XX_INS_INVALID, MOS65XX_AM_NONE, // 0x77 + MOS65XX_INS_SEI , MOS65XX_AM_IMP , // 0x78 + MOS65XX_INS_ADC , MOS65XX_AM_ABSY, // 0x79 + MOS65XX_INS_NOP , MOS65XX_AM_IMP , // 0x7a + MOS65XX_INS_INVALID, MOS65XX_AM_NONE, // 0x7b + MOS65XX_INS_NOP , MOS65XX_AM_ABSX, // 0x7c + MOS65XX_INS_ADC , MOS65XX_AM_ABSX, // 0x7d + MOS65XX_INS_ROR , MOS65XX_AM_ABSX, // 0x7e + MOS65XX_INS_INVALID, MOS65XX_AM_NONE, // 0x7f + MOS65XX_INS_NOP , MOS65XX_AM_IMP , // 0x80 + MOS65XX_INS_STA , MOS65XX_AM_INDX, // 0x81 + MOS65XX_INS_NOP , MOS65XX_AM_IMP , // 0x82 + MOS65XX_INS_INVALID, MOS65XX_AM_NONE, // 0x83 + MOS65XX_INS_STY , MOS65XX_AM_ZP , // 0x84 + MOS65XX_INS_STA , MOS65XX_AM_ZP , // 0x85 + MOS65XX_INS_STX , MOS65XX_AM_ZP , // 0x86 + MOS65XX_INS_INVALID, MOS65XX_AM_NONE, // 0x87 + MOS65XX_INS_DEY , MOS65XX_AM_IMP , // 0x88 + MOS65XX_INS_NOP , MOS65XX_AM_IMP , // 0x89 + MOS65XX_INS_TXA , MOS65XX_AM_IMP , // 0x8a + MOS65XX_INS_INVALID, MOS65XX_AM_NONE, // 0x8b + MOS65XX_INS_STY , MOS65XX_AM_ABS , // 0x8c + MOS65XX_INS_STA , MOS65XX_AM_ABS , // 0x8d + MOS65XX_INS_STX , MOS65XX_AM_ABS , // 0x8e + MOS65XX_INS_INVALID, MOS65XX_AM_NONE, // 0x8f + MOS65XX_INS_BCC , MOS65XX_AM_REL , // 0x90 + MOS65XX_INS_STA , MOS65XX_AM_INDY, // 0x91 + MOS65XX_INS_INVALID, MOS65XX_AM_NONE, // 0x92 + MOS65XX_INS_INVALID, MOS65XX_AM_NONE, // 0x93 + MOS65XX_INS_STY , MOS65XX_AM_ZPX , // 0x94 + MOS65XX_INS_STA , MOS65XX_AM_ZPX , // 0x95 + MOS65XX_INS_STX , MOS65XX_AM_ZPY , // 0x96 + MOS65XX_INS_INVALID, MOS65XX_AM_NONE, // 0x97 + MOS65XX_INS_TYA , MOS65XX_AM_IMP , // 0x98 + MOS65XX_INS_STA , MOS65XX_AM_ABSY, // 0x99 + MOS65XX_INS_TXS , MOS65XX_AM_IMP , // 0x9a + MOS65XX_INS_INVALID, MOS65XX_AM_NONE, // 0x9b + MOS65XX_INS_INVALID, MOS65XX_AM_NONE, // 0x9c + MOS65XX_INS_STA , MOS65XX_AM_ABSX, // 0x9d + MOS65XX_INS_INVALID, MOS65XX_AM_NONE, // 0x9e + MOS65XX_INS_INVALID, MOS65XX_AM_NONE, // 0x9f + MOS65XX_INS_LDY , MOS65XX_AM_IMM , // 0xa0 + MOS65XX_INS_LDA , MOS65XX_AM_INDX, // 0xa1 + MOS65XX_INS_LDX , MOS65XX_AM_IMM , // 0xa2 + MOS65XX_INS_INVALID, MOS65XX_AM_NONE, // 0xa3 + MOS65XX_INS_LDY , MOS65XX_AM_ZP , // 0xa4 + MOS65XX_INS_LDA , MOS65XX_AM_ZP , // 0xa5 + MOS65XX_INS_LDX , MOS65XX_AM_ZP , // 0xa6 + MOS65XX_INS_INVALID, MOS65XX_AM_NONE, // 0xa7 + MOS65XX_INS_TAY , MOS65XX_AM_IMP , // 0xa8 + MOS65XX_INS_LDA , MOS65XX_AM_IMM , // 0xa9 + MOS65XX_INS_TAX , MOS65XX_AM_IMP , // 0xaa + MOS65XX_INS_INVALID, MOS65XX_AM_NONE, // 0xab + MOS65XX_INS_LDY , MOS65XX_AM_ABS , // 0xac + MOS65XX_INS_LDA , MOS65XX_AM_ABS , // 0xad + MOS65XX_INS_LDX , MOS65XX_AM_ABS , // 0xae + MOS65XX_INS_INVALID, MOS65XX_AM_NONE, // 0xaf + MOS65XX_INS_BCS , MOS65XX_AM_REL , // 0xb0 + MOS65XX_INS_LDA , MOS65XX_AM_INDY, // 0xb1 + MOS65XX_INS_INVALID, MOS65XX_AM_NONE, // 0xb2 + MOS65XX_INS_INVALID, MOS65XX_AM_NONE, // 0xb3 + MOS65XX_INS_LDY , MOS65XX_AM_ZPX , // 0xb4 + MOS65XX_INS_LDA , MOS65XX_AM_ZPX , // 0xb5 + MOS65XX_INS_LDX , MOS65XX_AM_ZPY , // 0xb6 + MOS65XX_INS_INVALID, MOS65XX_AM_NONE, // 0xb7 + MOS65XX_INS_CLV , MOS65XX_AM_IMP , // 0xb8 + MOS65XX_INS_LDA , MOS65XX_AM_ABSY, // 0xb9 + MOS65XX_INS_TSX , MOS65XX_AM_IMP , // 0xba + MOS65XX_INS_INVALID, MOS65XX_AM_NONE, // 0xbb + MOS65XX_INS_LDY , MOS65XX_AM_ABSX, // 0xbc + MOS65XX_INS_LDA , MOS65XX_AM_ABSX, // 0xbd + MOS65XX_INS_LDX , MOS65XX_AM_ABSY, // 0xbe + MOS65XX_INS_INVALID, MOS65XX_AM_NONE, // 0xbf + MOS65XX_INS_CPY , MOS65XX_AM_IMM , // 0xc0 + MOS65XX_INS_CMP , MOS65XX_AM_INDX, // 0xc1 + MOS65XX_INS_NOP , MOS65XX_AM_IMP , // 0xc2 + MOS65XX_INS_INVALID, MOS65XX_AM_NONE, // 0xc3 + MOS65XX_INS_CPY , MOS65XX_AM_ZP , // 0xc4 + MOS65XX_INS_CMP , MOS65XX_AM_ZP , // 0xc5 + MOS65XX_INS_DEC , MOS65XX_AM_ZP , // 0xc6 + MOS65XX_INS_INVALID, MOS65XX_AM_NONE, // 0xc7 + MOS65XX_INS_INY , MOS65XX_AM_IMP , // 0xc8 + MOS65XX_INS_CMP , MOS65XX_AM_IMM , // 0xc9 + MOS65XX_INS_DEX , MOS65XX_AM_IMP , // 0xca + MOS65XX_INS_INVALID, MOS65XX_AM_NONE, // 0xcb + MOS65XX_INS_CPY , MOS65XX_AM_ABS , // 0xcc + MOS65XX_INS_CMP , MOS65XX_AM_ABS , // 0xcd + MOS65XX_INS_DEC , MOS65XX_AM_ABS , // 0xce + MOS65XX_INS_INVALID, MOS65XX_AM_NONE, // 0xcf + MOS65XX_INS_BNE , MOS65XX_AM_REL , // 0xd0 + MOS65XX_INS_CMP , MOS65XX_AM_INDY, // 0xd1 + MOS65XX_INS_INVALID, MOS65XX_AM_NONE, // 0xd2 + MOS65XX_INS_INVALID, MOS65XX_AM_NONE, // 0xd3 + MOS65XX_INS_NOP , MOS65XX_AM_ZPX , // 0xd4 + MOS65XX_INS_CMP , MOS65XX_AM_ZPX , // 0xd5 + MOS65XX_INS_DEC , MOS65XX_AM_ZPX , // 0xd6 + MOS65XX_INS_INVALID, MOS65XX_AM_NONE, // 0xd7 + MOS65XX_INS_CLD , MOS65XX_AM_IMP , // 0xd8 + MOS65XX_INS_CMP , MOS65XX_AM_ABSY, // 0xd9 + MOS65XX_INS_NOP , MOS65XX_AM_IMP , // 0xda + MOS65XX_INS_INVALID, MOS65XX_AM_NONE, // 0xdb + MOS65XX_INS_NOP , MOS65XX_AM_ABSX, // 0xdc + MOS65XX_INS_CMP , MOS65XX_AM_ABSX, // 0xdd + MOS65XX_INS_DEC , MOS65XX_AM_ABSX, // 0xde + MOS65XX_INS_INVALID, MOS65XX_AM_NONE, // 0xdf + MOS65XX_INS_CPX , MOS65XX_AM_IMM , // 0xe0 + MOS65XX_INS_SBC , MOS65XX_AM_INDX, // 0xe1 + MOS65XX_INS_NOP , MOS65XX_AM_IMP , // 0xe2 + MOS65XX_INS_INVALID, MOS65XX_AM_NONE, // 0xe3 + MOS65XX_INS_CPX , MOS65XX_AM_ZP , // 0xe4 + MOS65XX_INS_SBC , MOS65XX_AM_ZP , // 0xe5 + MOS65XX_INS_INC , MOS65XX_AM_ZP , // 0xe6 + MOS65XX_INS_INVALID, MOS65XX_AM_NONE, // 0xe7 + MOS65XX_INS_INX , MOS65XX_AM_IMP , // 0xe8 + MOS65XX_INS_SBC , MOS65XX_AM_IMM , // 0xe9 + MOS65XX_INS_NOP , MOS65XX_AM_IMP , // 0xea + MOS65XX_INS_INVALID, MOS65XX_AM_NONE, // 0xeb + MOS65XX_INS_CPX , MOS65XX_AM_ABS , // 0xec + MOS65XX_INS_SBC , MOS65XX_AM_ABS , // 0xed + MOS65XX_INS_INC , MOS65XX_AM_ABS , // 0xee + MOS65XX_INS_INVALID, MOS65XX_AM_NONE, // 0xef + MOS65XX_INS_BEQ , MOS65XX_AM_REL , // 0xf0 + MOS65XX_INS_SBC , MOS65XX_AM_INDY, // 0xf1 + MOS65XX_INS_INVALID, MOS65XX_AM_NONE, // 0xf2 + MOS65XX_INS_INVALID, MOS65XX_AM_NONE, // 0xf3 + MOS65XX_INS_NOP , MOS65XX_AM_ZPX , // 0xf4 + MOS65XX_INS_SBC , MOS65XX_AM_ZPX , // 0xf5 + MOS65XX_INS_INC , MOS65XX_AM_ZPX , // 0xf6 + MOS65XX_INS_INVALID, MOS65XX_AM_NONE, // 0xf7 + MOS65XX_INS_SED , MOS65XX_AM_IMP , // 0xf8 + MOS65XX_INS_SBC , MOS65XX_AM_ABSY, // 0xf9 + MOS65XX_INS_NOP , MOS65XX_AM_IMP , // 0xfa + MOS65XX_INS_INVALID, MOS65XX_AM_NONE, // 0xfb + MOS65XX_INS_NOP , MOS65XX_AM_ABSX, // 0xfc + MOS65XX_INS_SBC , MOS65XX_AM_ABSX, // 0xfd + MOS65XX_INS_INC , MOS65XX_AM_ABSX, // 0xfe + MOS65XX_INS_INVALID, MOS65XX_AM_NONE, // 0xff +}; + +static const char* RegNames[] = { + "invalid", "A", "X", "Y", "P", "SP" +}; + +#ifndef CAPSTONE_DIET +static const char* GroupNames[] = { + NULL, + "jump", + "call", + "ret", + NULL, + "iret", + "branch_relative" +}; + +typedef struct InstructionInfo { + char* name; + mos65xx_group_type group_type; + mos65xx_reg write, read; + bool modifies_status; +} InstructionInfo; + +const struct InstructionInfo InstructionInfoTable[]= { + "INVALID", MOS65XX_GRP_INVALID, MOS65XX_REG_INVALID, MOS65XX_REG_INVALID, false, + "ADC", MOS65XX_GRP_INVALID, MOS65XX_REG_ACC, MOS65XX_REG_INVALID, true, + "AND", MOS65XX_GRP_INVALID, MOS65XX_REG_ACC, MOS65XX_REG_INVALID, true, + "ASL", MOS65XX_GRP_INVALID, MOS65XX_REG_INVALID, MOS65XX_REG_INVALID, true, + "BCC", MOS65XX_GRP_BRANCH_RELATIVE, MOS65XX_REG_INVALID, MOS65XX_REG_P, false, + "BCS", MOS65XX_GRP_BRANCH_RELATIVE, MOS65XX_REG_INVALID, MOS65XX_REG_P, false, + "BEQ", MOS65XX_GRP_BRANCH_RELATIVE, MOS65XX_REG_INVALID, MOS65XX_REG_P, false, + "BIT", MOS65XX_GRP_INVALID, MOS65XX_REG_INVALID, MOS65XX_REG_INVALID, true, + "BMI", MOS65XX_GRP_BRANCH_RELATIVE, MOS65XX_REG_INVALID, MOS65XX_REG_P, false, + "BNE", MOS65XX_GRP_BRANCH_RELATIVE, MOS65XX_REG_INVALID, MOS65XX_REG_P, false, + "BPL", MOS65XX_GRP_BRANCH_RELATIVE, MOS65XX_REG_INVALID, MOS65XX_REG_P, false, + "BRK", MOS65XX_GRP_INVALID, MOS65XX_REG_SP, MOS65XX_REG_INVALID, false, + "BVC", MOS65XX_GRP_BRANCH_RELATIVE, MOS65XX_REG_INVALID, MOS65XX_REG_P, false, + "BVS", MOS65XX_GRP_BRANCH_RELATIVE, MOS65XX_REG_INVALID, MOS65XX_REG_P, false, + "CLC", MOS65XX_GRP_INVALID, MOS65XX_REG_INVALID, MOS65XX_REG_INVALID, true, + "CLD", MOS65XX_GRP_INVALID, MOS65XX_REG_INVALID, MOS65XX_REG_INVALID, true, + "CLI", MOS65XX_GRP_INVALID, MOS65XX_REG_INVALID, MOS65XX_REG_INVALID, true, + "CLV", MOS65XX_GRP_INVALID, MOS65XX_REG_INVALID, MOS65XX_REG_INVALID, true, + "CMP", MOS65XX_GRP_INVALID, MOS65XX_REG_INVALID, MOS65XX_REG_ACC, true, + "CPX", MOS65XX_GRP_INVALID, MOS65XX_REG_INVALID, MOS65XX_REG_X, true, + "CPY", MOS65XX_GRP_INVALID, MOS65XX_REG_INVALID, MOS65XX_REG_Y, true, + "DEC", MOS65XX_GRP_INVALID, MOS65XX_REG_INVALID, MOS65XX_REG_INVALID, true, + "DEX", MOS65XX_GRP_INVALID, MOS65XX_REG_X, MOS65XX_REG_X, true, + "DEY", MOS65XX_GRP_INVALID, MOS65XX_REG_Y, MOS65XX_REG_Y, true, + "EOR", MOS65XX_GRP_INVALID, MOS65XX_REG_INVALID, MOS65XX_REG_INVALID, true, + "INC", MOS65XX_GRP_INVALID, MOS65XX_REG_INVALID, MOS65XX_REG_INVALID, true, + "INX", MOS65XX_GRP_INVALID, MOS65XX_REG_X, MOS65XX_REG_X, true, + "INY", MOS65XX_GRP_INVALID, MOS65XX_REG_Y, MOS65XX_REG_Y, true, + "JMP", MOS65XX_GRP_JUMP, MOS65XX_REG_INVALID, MOS65XX_REG_INVALID, false, + "JSR", MOS65XX_GRP_CALL, MOS65XX_REG_INVALID, MOS65XX_REG_INVALID, false, + "LDA", MOS65XX_GRP_INVALID, MOS65XX_REG_ACC, MOS65XX_REG_INVALID, true, + "LDX", MOS65XX_GRP_INVALID, MOS65XX_REG_X, MOS65XX_REG_INVALID, true, + "LDY", MOS65XX_GRP_INVALID, MOS65XX_REG_Y, MOS65XX_REG_INVALID, true, + "LSR", MOS65XX_GRP_INVALID, MOS65XX_REG_INVALID, MOS65XX_REG_INVALID, true, + "NOP", MOS65XX_GRP_INVALID, MOS65XX_REG_INVALID, MOS65XX_REG_INVALID, false, + "ORA", MOS65XX_GRP_INVALID, MOS65XX_REG_ACC, MOS65XX_REG_INVALID, true, + "PHA", MOS65XX_GRP_INVALID, MOS65XX_REG_SP, MOS65XX_REG_ACC, false, + "PLA", MOS65XX_GRP_INVALID, MOS65XX_REG_ACC, MOS65XX_REG_SP, true, + "PHP", MOS65XX_GRP_INVALID, MOS65XX_REG_SP, MOS65XX_REG_P, false, + "PLP", MOS65XX_GRP_INVALID, MOS65XX_REG_INVALID, MOS65XX_REG_SP, true, + "ROL", MOS65XX_GRP_INVALID, MOS65XX_REG_INVALID, MOS65XX_REG_INVALID, true, + "ROR", MOS65XX_GRP_INVALID, MOS65XX_REG_INVALID, MOS65XX_REG_INVALID, true, + "RTI", MOS65XX_GRP_IRET, MOS65XX_REG_SP, MOS65XX_REG_INVALID, true, + "RTS", MOS65XX_GRP_RET, MOS65XX_REG_SP, MOS65XX_REG_INVALID, false, + "SBC", MOS65XX_GRP_INVALID, MOS65XX_REG_ACC, MOS65XX_REG_INVALID, true, + "SEC", MOS65XX_GRP_INVALID, MOS65XX_REG_INVALID, MOS65XX_REG_INVALID, true, + "SED", MOS65XX_GRP_INVALID, MOS65XX_REG_INVALID, MOS65XX_REG_INVALID, true, + "SEI", MOS65XX_GRP_INVALID, MOS65XX_REG_INVALID, MOS65XX_REG_INVALID, true, + "STA", MOS65XX_GRP_INVALID, MOS65XX_REG_INVALID, MOS65XX_REG_ACC, false, + "STX", MOS65XX_GRP_INVALID, MOS65XX_REG_INVALID, MOS65XX_REG_X, false, + "STY", MOS65XX_GRP_INVALID, MOS65XX_REG_INVALID, MOS65XX_REG_Y, false, + "TAX", MOS65XX_GRP_INVALID, MOS65XX_REG_X, MOS65XX_REG_ACC, true, + "TAY", MOS65XX_GRP_INVALID, MOS65XX_REG_Y, MOS65XX_REG_ACC, true, + "TSX", MOS65XX_GRP_INVALID, MOS65XX_REG_X, MOS65XX_REG_SP, true, + "TXA", MOS65XX_GRP_INVALID, MOS65XX_REG_ACC, MOS65XX_REG_X, true, + "TXS", MOS65XX_GRP_INVALID, MOS65XX_REG_SP, MOS65XX_REG_X, true, + "TYA", MOS65XX_GRP_INVALID, MOS65XX_REG_ACC, MOS65XX_REG_Y, true, +}; +#endif + +int getInstructionLength(mos65xx_address_mode am) +{ + switch(am) { + case MOS65XX_AM_NONE: + case MOS65XX_AM_ACC: + case MOS65XX_AM_IMP: + return 1; + + case MOS65XX_AM_IMM: + case MOS65XX_AM_ZPX: + case MOS65XX_AM_ZPY: + case MOS65XX_AM_ZP: + case MOS65XX_AM_REL: + return 2; + + case MOS65XX_AM_ABS: + case MOS65XX_AM_ABSX: + case MOS65XX_AM_ABSY: + case MOS65XX_AM_INDX: + case MOS65XX_AM_INDY: + case MOS65XX_AM_IND: + return 3; + } +} + +#ifndef CAPSTONE_DIET +void fillDetails(MCInst *MI, unsigned char opcode) { + cs_detail *detail = MI->flat_insn->detail; + mos65xx_insn ins = OpInfoTable[opcode].ins; + mos65xx_address_mode am = OpInfoTable[opcode].am; + + detail->mos65xx.am = am; + detail->mos65xx.modifies_flags = InstructionInfoTable[ins].modifies_status; + detail->groups_count = 0; + detail->regs_read_count = 0; + detail->regs_write_count = 0; + detail->mos65xx.op_count = 0; + + if (InstructionInfoTable[ins].group_type != MOS65XX_GRP_INVALID) { + detail->groups[0] = InstructionInfoTable[ins].group_type; + detail->groups_count++; + } + + if (InstructionInfoTable[ins].read != MOS65XX_REG_INVALID) { + detail->regs_read[detail->regs_read_count++] = InstructionInfoTable[ins].read; + } else if (OpInfoTable[opcode].am == MOS65XX_AM_ACC) { + detail->regs_read[detail->regs_read_count++] = MOS65XX_REG_ACC; + } else if (OpInfoTable[opcode].am == MOS65XX_AM_INDY || OpInfoTable[opcode].am == MOS65XX_AM_ABSY || OpInfoTable[opcode].am == MOS65XX_AM_ZPY) { + detail->regs_read[detail->regs_read_count++] = MOS65XX_REG_Y; + } else if (OpInfoTable[opcode].am == MOS65XX_AM_INDX || OpInfoTable[opcode].am == MOS65XX_AM_ABSX || OpInfoTable[opcode].am == MOS65XX_AM_ZPX) { + detail->regs_read[detail->regs_read_count++] = MOS65XX_REG_X; + } + + if (InstructionInfoTable[ins].write != MOS65XX_REG_INVALID) { + detail->regs_write[detail->regs_write_count++] = InstructionInfoTable[ins].write; + } else if (OpInfoTable[opcode].am == MOS65XX_AM_ACC) { + detail->regs_write[detail->regs_write_count++] = MOS65XX_REG_ACC; + } + + if (InstructionInfoTable[ins].modifies_status) { + detail->regs_write[detail->regs_write_count++] = MOS65XX_REG_P; + } + + switch(am) { + case MOS65XX_AM_IMP: + case MOS65XX_AM_REL: + break; + case MOS65XX_AM_IMM: + detail->mos65xx.operands[detail->mos65xx.op_count].type = MOS65XX_OP_IMM; + detail->mos65xx.operands[detail->mos65xx.op_count].mem = MI->Operands[0].ImmVal; + detail->mos65xx.op_count++; + break; + case MOS65XX_AM_ACC: + detail->mos65xx.operands[detail->mos65xx.op_count].type = MOS65XX_OP_REG; + detail->mos65xx.operands[detail->mos65xx.op_count].reg = MOS65XX_REG_ACC; + detail->mos65xx.op_count++; + break; + default: + detail->mos65xx.operands[detail->mos65xx.op_count].type = MOS65XX_OP_MEM; + detail->mos65xx.operands[detail->mos65xx.op_count].mem = MI->Operands[0].ImmVal; + detail->mos65xx.op_count++; + break; + } +} +#endif + +void MOS65XX_printInst(MCInst *MI, struct SStream *O, void *PrinterInfo) +{ +#ifndef CAPSTONE_DIET + unsigned char opcode = MI->Opcode; + + SStream_concat0(O, InstructionInfoTable[OpInfoTable[MI->Opcode].ins].name); + unsigned int value = MI->Operands[0].ImmVal; + + switch (OpInfoTable[opcode].am) + { + case MOS65XX_AM_IMP: + break; + + case MOS65XX_AM_ACC: + SStream_concat(O, " A"); + break; + + case MOS65XX_AM_ABS: + SStream_concat(O, " $%04X", value); + break; + + case MOS65XX_AM_IMM: + SStream_concat(O, " #$%02X", value); + break; + + case MOS65XX_AM_ZP: + SStream_concat(O, " $%02X", value); + break; + + case MOS65XX_AM_ABSX: + SStream_concat(O, " $%04X,x", value); + break; + + case MOS65XX_AM_ABSY: + SStream_concat(O, " $%04X,y", value); + break; + + case MOS65XX_AM_ZPX: + SStream_concat(O, " $%02X,x", value); + break; + + case MOS65XX_AM_ZPY: + SStream_concat(O, " $%02X,y", value); + break; + + case MOS65XX_AM_REL: + SStream_concat(O, " $%04X", MI->address + (signed char) value + 2); + break; + + case MOS65XX_AM_IND: + SStream_concat(O, " ($%04X)", value); + break; + + case MOS65XX_AM_INDX: + SStream_concat(O, " ($%04X,x)", value); + break; + + case MOS65XX_AM_INDY: + SStream_concat(O, " ($%04X),y", value); + break; + } +#endif +} + +bool MOS65XX_getInstruction(csh ud, const uint8_t *code, size_t code_len, + MCInst *MI, uint16_t *size, uint64_t address, void *inst_info) +{ + unsigned char opcode; + unsigned char len; + mos65xx_insn ins; + + if (code_len == 0) { + *size = 1; + return false; + } + + opcode = code[0]; + ins = OpInfoTable[opcode].ins; + if (ins == MOS65XX_INS_INVALID) { + *size = 1; + return false; + } + + len = getInstructionLength(OpInfoTable[opcode].am); + if (code_len < len) { + *size = 1; + return false; + } + + MI->address = address; + MI->Opcode = opcode; + MI->OpcodePub = ins; + MI->size = 0; + + *size = len; + if (len == 2) { + MCOperand_CreateImm0(MI, code[1]); + } else + if (len == 3) { + MCOperand_CreateImm0(MI, (code[2]<<8) | code[1]); + } +#ifndef CAPSTONE_DIET + if (MI->flat_insn->detail) { + fillDetails(MI, opcode); + } +#endif + + return true; +} + +const char *MOS65XX_insn_name(csh handle, unsigned int id) +{ +#ifdef CAPSTONE_DIET + return NULL; +#else + if (id >= ARR_SIZE(InstructionInfoTable)) { + return NULL; + } + return InstructionInfoTable[id].name; +#endif +} + +const char* MOS65XX_reg_name(csh handle, unsigned int reg) +{ +#ifdef CAPSTONE_DIET + return NULL; +#else + if (reg >= ARR_SIZE(RegNames)) { + return NULL; + } + return RegNames[(int)reg]; +#endif +} + +void MOS65XX_get_insn_id(cs_struct *h, cs_insn *insn, unsigned int id) +{ + if (id < 256) { + insn->id = OpInfoTable[id].ins; + } +} + +const char *MOS65XX_group_name(csh handle, unsigned int id) +{ +#ifdef CAPSTONE_DIET + return NULL; +#else + if (id >= ARR_SIZE(GroupNames)) { + return NULL; + } + return GroupNames[(int)id]; +#endif +} diff --git a/arch/MOS65XX/MOS65XXDisassembler.h b/arch/MOS65XX/MOS65XXDisassembler.h new file mode 100644 index 00000000..ad663cd8 --- /dev/null +++ b/arch/MOS65XX/MOS65XXDisassembler.h @@ -0,0 +1,22 @@ +/* Capstone Disassembly Engine */ +/* MOS65XX Backend by Sebastian Macke 2018 */ + +#ifndef CAPSTONE_MOS65XXDISASSEMBLER_H +#define CAPSTONE_MOS65XXDISASSEMBLER_H + +#include "../../utils.h" + +void MOS65XX_printInst(MCInst *MI, struct SStream *O, void *PrinterInfo); + +void MOS65XX_get_insn_id(cs_struct *h, cs_insn *insn, unsigned int id); + +const char *MOS65XX_insn_name(csh handle, unsigned int id); + +const char *MOS65XX_group_name(csh handle, unsigned int id); + +const char* MOS65XX_reg_name(csh handle, unsigned int reg); + +bool MOS65XX_getInstruction(csh ud, const uint8_t *code, size_t code_len, + MCInst *MI, uint16_t *size, uint64_t address, void *inst_info); + +#endif //CAPSTONE_MOS65XXDISASSEMBLER_H diff --git a/arch/MOS65XX/MOS65XXModule.c b/arch/MOS65XX/MOS65XXModule.c new file mode 100644 index 00000000..f2a9b9ca --- /dev/null +++ b/arch/MOS65XX/MOS65XXModule.c @@ -0,0 +1,32 @@ +/* Capstone Disassembly Engine */ +/* MOS65XX Backend by Sebastian Macke 2018 */ + +#ifdef CAPSTONE_HAS_MOS65XX + +#include "../../utils.h" +#include "../../MCRegisterInfo.h" +#include "MOS65XXDisassembler.h" + +cs_err MOS65XX_global_init(cs_struct *ud) +{ + // verify if requested mode is valid + if (ud->mode) + return CS_ERR_MODE; + + ud->printer = MOS65XX_printInst; + ud->printer_info = NULL; + ud->insn_id = MOS65XX_get_insn_id; + ud->insn_name = MOS65XX_insn_name; + ud->group_name = MOS65XX_group_name; + ud->disasm = MOS65XX_getInstruction; + ud->reg_name = MOS65XX_reg_name; + + return CS_ERR_OK; +} + +cs_err MOS65XX_option(cs_struct *handle, cs_opt_type type, size_t value) +{ + return CS_ERR_OK; +} + +#endif \ No newline at end of file diff --git a/arch/MOS65XX/MOS65XXModule.h b/arch/MOS65XX/MOS65XXModule.h new file mode 100644 index 00000000..1d1ad9d4 --- /dev/null +++ b/arch/MOS65XX/MOS65XXModule.h @@ -0,0 +1,12 @@ +/* Capstone Disassembly Engine */ +/* By Sebastian Macke , 2018 */ + +#ifndef CS_MOS65XX_MODULE_H +#define CS_MOS65XX_MODULE_H + +#include "../../utils.h" + +cs_err MOS65XX_global_init(cs_struct *ud); +cs_err MOS65XX_option(cs_struct *handle, cs_opt_type type, size_t value); + +#endif diff --git a/config.mk b/config.mk index 3b078a7d..afbd0950 100644 --- a/config.mk +++ b/config.mk @@ -4,7 +4,7 @@ ################################################################################ # Specify which archs you want to compile in. By default, we build all archs. -CAPSTONE_ARCHS ?= arm aarch64 m68k mips powerpc sparc systemz x86 xcore tms320c64x m680x evm +CAPSTONE_ARCHS ?= arm aarch64 m68k mips powerpc sparc systemz x86 xcore tms320c64x m680x evm mos65xx ################################################################################ diff --git a/cs.c b/cs.c index 98f30f76..be258431 100644 --- a/cs.c +++ b/cs.c @@ -64,6 +64,7 @@ #include "arch/TMS320C64x/TMS320C64xModule.h" #include "arch/X86/X86Module.h" #include "arch/XCore/XCoreModule.h" +#include "arch/MOS65XX/MOS65XXModule.h" // constructor initialization for all archs static cs_err (*cs_arch_init[MAX_ARCH])(cs_struct *) = { @@ -127,6 +128,11 @@ static cs_err (*cs_arch_init[MAX_ARCH])(cs_struct *) = { #else NULL, #endif +#ifdef CAPSTONE_HAS_MOS65XX + MOS65XX_global_init, +#else + NULL, +#endif }; // support cs_option() for all archs @@ -191,6 +197,12 @@ static cs_err (*cs_arch_option[MAX_ARCH]) (cs_struct *, cs_opt_type, size_t valu #else NULL, #endif +#ifdef CAPSTONE_HAS_MOS65XX + MOS65XX_option, +#else + NULL, +#endif + }; // bitmask for finding disallowed modes for an arch: @@ -263,6 +275,11 @@ static cs_mode cs_arch_disallowed_mode_mask[MAX_ARCH] = { #else 0, #endif +#ifdef CAPSTONE_HAS_MOS65XX + ~(CS_MODE_BIG_ENDIAN), +#else + 0, +#endif }; // bitmask of enabled architectures @@ -303,6 +320,9 @@ static uint32_t all_arch = 0 #ifdef CAPSTONE_HAS_EVM | (1 << CS_ARCH_EVM) #endif +#ifdef CAPSTONE_HAS_MOS65XX + | (1 << CS_ARCH_MOS65XX) +#endif ; @@ -373,7 +393,8 @@ bool CAPSTONE_API cs_support(int query) (1 << CS_ARCH_PPC) | (1 << CS_ARCH_SPARC) | (1 << CS_ARCH_SYSZ) | (1 << CS_ARCH_XCORE) | (1 << CS_ARCH_M68K) | (1 << CS_ARCH_TMS320C64X) | - (1 << CS_ARCH_M680X) | (1 << CS_ARCH_EVM)); + (1 << CS_ARCH_M680X) | (1 << CS_ARCH_EVM) | + (1 << CS_ARCH_MOS65XX)); if ((unsigned int)query < CS_ARCH_MAX) return all_arch & (1 << query); @@ -639,6 +660,9 @@ static uint8_t skipdata_size(cs_struct *handle) case CS_ARCH_EVM: // EVM alignment is 1. return 1; + case CS_ARCH_MOS65XX: + // MOS65XX alignment is 1. + return 1; } } @@ -1357,6 +1381,11 @@ int CAPSTONE_API cs_op_count(csh ud, const cs_insn *insn, unsigned int op_type) if (insn->detail->evm.operands[i].type == (evm_op_type)op_type) count++; #endif + case CS_ARCH_MOS65XX: + for (i = 0; i < insn->detail->m680x.op_count; i++) + if (insn->detail->m680x.operands[i].type == (m680x_op_type)op_type) + count++; + break; break; } @@ -1493,6 +1522,14 @@ int CAPSTONE_API cs_op_index(csh ud, const cs_insn *insn, unsigned int op_type, } #endif break; + case CS_ARCH_MOS65XX: + for (i = 0; i < insn->detail->mos65xx.op_count; i++) { + if (insn->detail->mos65xx.operands[i].type == (mos65xx_op_type)op_type) + count++; + if (count == post) + return i; + } + break; } return -1; diff --git a/cstool/cstool.c b/cstool/cstool.c index 303c553c..15c8ca47 100644 --- a/cstool/cstool.c +++ b/cstool/cstool.c @@ -56,6 +56,7 @@ static struct { { "hd6309", CS_ARCH_M680X, CS_MODE_M680X_6309 }, { "hcs08", CS_ARCH_M680X, CS_MODE_M680X_HCS08 }, { "evm", CS_ARCH_EVM, 0 }, + { "mos65xx", CS_ARCH_MOS65XX, 0 }, { NULL } }; @@ -71,6 +72,7 @@ void print_insn_detail_m68k(csh handle, cs_insn *ins); void print_insn_detail_tms320c64x(csh handle, cs_insn *ins); void print_insn_detail_m680x(csh handle, cs_insn *ins); void print_insn_detail_evm(csh handle, cs_insn *ins); +void print_insn_detail_mos65xx(csh handle, cs_insn *ins); static void print_details(csh handle, cs_arch arch, cs_mode md, cs_insn *ins); @@ -207,6 +209,9 @@ static void usage(char *prog) if (cs_support(CS_ARCH_EVM)) { printf(" evm: Ethereum Virtual Machine\n"); } + if (cs_support(CS_ARCH_MOS65XX)) { + printf(" mox65xx: MOS65XX family\n"); + } printf("\nExtra options:\n"); printf(" -d show detailed information of the instructions\n"); @@ -252,6 +257,9 @@ static void print_details(csh handle, cs_arch arch, cs_mode md, cs_insn *ins) case CS_ARCH_EVM: print_insn_detail_evm(handle, ins); break; + case CS_ARCH_MOS65XX: + print_insn_detail_mos65xx(handle, ins); + break; default: break; } diff --git a/cstool/cstool_mos65xx.c b/cstool/cstool_mos65xx.c new file mode 100644 index 00000000..6b29aafc --- /dev/null +++ b/cstool/cstool_mos65xx.c @@ -0,0 +1,76 @@ +#include +#include + +#include + +void print_string_hex(char *comment, unsigned char *str, size_t len); + +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 addressing (no addressing mode)"; + case MOS65XX_AM_ACC: + return "accumulator addressing"; + case MOS65XX_AM_ABS: + return "absolute addressing"; + case MOS65XX_AM_ZP: + return "zeropage addressing"; + case MOS65XX_AM_IMM: + return "8 Bit immediate value"; + case MOS65XX_AM_ABSX: + return "indexed absolute addressing by the X index register"; + case MOS65XX_AM_ABSY: + return "indexed absolute addressing by the Y index register"; + case MOS65XX_AM_INDX: + return "indexed indirect addressing by the X index register"; + case MOS65XX_AM_INDY: + return "indirect indexed addressing by the Y index register"; + case MOS65XX_AM_ZPX: + return "indexed zeropage addressing by the X index register"; + case MOS65XX_AM_ZPY: + return "indexed zeropage addressing by the Y index register"; + case MOS65XX_AM_REL: + return "relative addressing used by branches"; + case MOS65XX_AM_IND: + return "absolute indirect addressing"; + } +} + + +void print_insn_detail_mos65xx(csh handle, cs_insn *ins) +{ + int i; + cs_mos65xx *mos65xx; + + // detail can be NULL on "data" instruction if SKIPDATA option is turned ON + if (ins->detail == NULL) + return; + + mos65xx = &(ins->detail->mos65xx); + 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; + } + } +} diff --git a/include/capstone/capstone.h b/include/capstone/capstone.h index 03770e4f..62e44088 100644 --- a/include/capstone/capstone.h +++ b/include/capstone/capstone.h @@ -84,6 +84,7 @@ typedef enum cs_arch { CS_ARCH_TMS320C64X, ///< TMS320C64x architecture CS_ARCH_M680X, ///< 680X architecture CS_ARCH_EVM, ///< Ethereum architecture + CS_ARCH_MOS65XX, ///< MOS65XX architecture (including MOS6502) CS_ARCH_MAX, CS_ARCH_ALL = 0xFFFF, // All architectures - for cs_support() } cs_arch; @@ -257,6 +258,7 @@ typedef struct cs_opt_skipdata { /// X86: 1 bytes. /// XCore: 2 bytes. /// EVM: 1 bytes. + /// MOS65XX: 1 bytes. cs_skipdata_cb_t callback; // default value is NULL /// User-defined data to be passed to @callback function pointer. @@ -276,6 +278,7 @@ typedef struct cs_opt_skipdata { #include "tms320c64x.h" #include "m680x.h" #include "evm.h" +#include "mos65xx.h" /// NOTE: All information in cs_detail is only available when CS_OPT_DETAIL = CS_OPT_ON /// Initialized as memset(., 0, offsetof(cs_detail, ARCH)+sizeof(cs_ARCH)) @@ -306,6 +309,7 @@ typedef struct cs_detail { cs_tms320c64x tms320c64x; ///< TMS320C64x architecture cs_m680x m680x; ///< M680X architecture cs_evm evm; ///< Ethereum architecture + cs_mos65xx mos65xx; ///< Ethereum architecture }; } cs_detail; diff --git a/include/capstone/mos65xx.h b/include/capstone/mos65xx.h new file mode 100644 index 00000000..ab7a27ba --- /dev/null +++ b/include/capstone/mos65xx.h @@ -0,0 +1,148 @@ +#ifndef CAPSTONE_MOS65XX_H +#define CAPSTONE_MOS65XX_H + +/* Capstone Disassembly Engine */ +/* By Sebastian Macke , 2018 */ + +#include +#include + +#include +#include + +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 addressing (no addressing mode)"; + case MOS65XX_AM_ACC: + return "accumulator addressing"; + case MOS65XX_AM_ABS: + return "absolute addressing"; + case MOS65XX_AM_ZP: + return "zeropage addressing"; + case MOS65XX_AM_IMM: + return "8 Bit immediate value"; + case MOS65XX_AM_ABSX: + return "indexed absolute addressing by the X index register"; + case MOS65XX_AM_ABSY: + return "indexed absolute addressing by the Y index register"; + case MOS65XX_AM_INDX: + return "indexed indirect addressing by the X index register"; + case MOS65XX_AM_INDY: + return "indirect indexed addressing by the Y index register"; + case MOS65XX_AM_ZPX: + return "indexed zeropage addressing by the X index register"; + case MOS65XX_AM_ZPY: + return "indexed zeropage addressing by the Y index register"; + case MOS65XX_AM_REL: + return "relative addressing used by branches"; + case MOS65XX_AM_IND: + return "absolute indirect addressing"; + } +} + + +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 MOS65XX_CODE "\x0d\x34\x12\x00\x81\x65\x87\x6c\x01\x00\x85\xFF\x10\x00\x19\x42\x42\x00\x49\x42" + + struct platform platforms[] = { + { + CS_ARCH_MOS65XX, + 0, + (unsigned char *)MOS65XX_CODE, + sizeof(MOS65XX_CODE) - 1, + "MOS65XX" + }, + }; + + 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; +}