From c6b10b21f972d61b7ae386132c7f67b741d7961d Mon Sep 17 00:00:00 2001 From: david942j Date: Wed, 13 Feb 2019 12:16:32 -0800 Subject: [PATCH 01/35] Basic changes of new arch - BPF --- CMakeLists.txt | 23 +++++++- COMPILE.TXT | 1 + COMPILE_CMAKE.TXT | 1 + Makefile | 18 +++++- arch/BPF/BPFDisassembler.c | 108 ++++++++++++++++++++++++++++++++++++ arch/BPF/BPFDisassembler.h | 27 +++++++++ arch/BPF/BPFModule.c | 27 +++++++++ arch/BPF/BPFModule.h | 12 ++++ config.mk | 2 +- cs.c | 41 +++++++++++++- include/capstone/bpf.h | 35 ++++++++++++ include/capstone/capstone.h | 6 ++ 12 files changed, 292 insertions(+), 9 deletions(-) create mode 100644 arch/BPF/BPFDisassembler.c create mode 100644 arch/BPF/BPFDisassembler.h create mode 100644 arch/BPF/BPFModule.c create mode 100644 arch/BPF/BPFModule.h create mode 100644 include/capstone/bpf.h diff --git a/CMakeLists.txt b/CMakeLists.txt index fb6883f8ff..923e4eae76 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 MOS65XX WASM) -set(SUPPORTED_ARCHITECTURE_LABELS ARM ARM64 M68K MIPS PowerPC Sparc SystemZ XCore x86 TMS320C64x M680x EVM MOS65XX WASM) +set(SUPPORTED_ARCHITECTURES ARM ARM64 M68K MIPS PPC SPARC SYSZ XCORE X86 TMS320C64X M680X EVM MOS65XX WASM BPF) +set(SUPPORTED_ARCHITECTURE_LABELS ARM ARM64 M68K MIPS PowerPC Sparc SystemZ XCore x86 TMS320C64x M680x EVM MOS65XX WASM BPF) list(LENGTH SUPPORTED_ARCHITECTURES count) math(EXPR count "${count}-1") @@ -115,6 +115,7 @@ set(HEADERS_COMMON include/capstone/tms320c64x.h include/capstone/m680x.h include/capstone/mos65xx.h + include/capstone/bpf.h include/capstone/platform.h ) @@ -475,6 +476,20 @@ if (NOT CAPSTONE_X86_ONLY AND CAPSTONE_MOS65XX_SUPPORT) set(TEST_SOURCES ${TEST_SOURCES} test_mos65xx.c) endif () +# TODO(david942j): check if all sources and headers are included +if (NOT CAPSTONE_X86_ONLY AND CAPSTONE_BPF_SUPPORT) + add_definitions(-DCAPSTONE_HAS_BPF) + set(SOURCES_BPF + arch/BPF/BPFDisassembler.c + arch/BPF/BPFModule.c + ) + set(HEADERS_BPF + arch/BPF/BPFDisassembler.h + arch/BPF/BPFModule.h + ) + set(TEST_SOURCES ${TEST_SOURCES} test_bpf.c) +endif () + if (CAPSTONE_OSXKERNEL_SUPPORT) add_definitions(-DCAPSTONE_HAS_OSXKERNEL) endif () @@ -495,6 +510,7 @@ set(ALL_SOURCES ${SOURCES_EVM} ${SOURCES_WASM} ${SOURCES_MOS65XX} + ${SOURCES_BPF} ) set(ALL_HEADERS @@ -514,6 +530,7 @@ set(ALL_HEADERS ${HEADERS_EVM} ${HEADERS_WASM} ${HEADERS_MOS65XX} + ${HEADERS_BPF} ) include_directories("${PROJECT_SOURCE_DIR}/include") @@ -596,6 +613,7 @@ source_group("Source\\M680X" FILES ${SOURCES_M680X}) source_group("Source\\EVM" FILES ${SOURCES_EVM}) source_group("Source\\WASM" FILES ${SOURCES_WASM}) source_group("Source\\MOS65XX" FILES ${SOURCES_MOS65XX}) +source_group("Source\\BPF" FILES ${SOURCES_BPF}) source_group("Include\\Common" FILES ${HEADERS_COMMON}) source_group("Include\\Engine" FILES ${HEADERS_ENGINE}) @@ -613,6 +631,7 @@ source_group("Include\\M680X" FILES ${HEADERS_MC680X}) source_group("Include\\EVM" FILES ${HEADERS_EVM}) source_group("Include\\WASM" FILES ${HEADERS_WASM}) source_group("Include\\MOS65XX" FILES ${HEADERS_MOS65XX}) +source_group("Include\\BPF" FILES ${HEADERS_BPF}) ### test library 64bit routine: get_property(LIB64 GLOBAL PROPERTY FIND_LIBRARY_USE_LIB64_PATHS) diff --git a/COMPILE.TXT b/COMPILE.TXT index 9a1edd0b0b..07f0411df6 100644 --- a/COMPILE.TXT +++ b/COMPILE.TXT @@ -96,6 +96,7 @@ Capstone requires no prerequisite packages, so it is easy to compile & install. /usr/include/capstone/systemz.h /usr/include/capstone/tms320c64x.h /usr/include/capstone/xcore.h + /usr/include/capstone/bpf.h /usr/include/capstone/platform.h /usr/lib/libcapstone.so (for Linux/*nix), or /usr/lib/libcapstone.dylib (OSX) /usr/lib/libcapstone.a diff --git a/COMPILE_CMAKE.TXT b/COMPILE_CMAKE.TXT index b1d441c8fb..e14ea08148 100644 --- a/COMPILE_CMAKE.TXT +++ b/COMPILE_CMAKE.TXT @@ -34,6 +34,7 @@ Get CMake for free from http://www.cmake.org. - CAPSTONE_X86_M680X: support M680X. Run cmake with -DCAPSTONE_M680X_SUPPORT=0 to remove M680X. - CAPSTONE_X86_EVM: support EVM. Run cmake with -DCAPSTONE_EVM_SUPPORT=0 to remove EVM. - CAPSTONE_X86_WASM: support Web Assembly. Run cmake with -DCAPSTONE_WASM_SUPPORT=0 to remove WASM. + - CAPSTONE_BPF_SUPPORT: support BPF. Run cmake with -DCAPSTONE_BPF_SUPPORT=0 to remove BPF. By default, all architectures are compiled in. diff --git a/Makefile b/Makefile index c31c7e1c44..401c33b3ed 100644 --- a/Makefile +++ b/Makefile @@ -271,10 +271,21 @@ ifneq (,$(findstring mos65xx,$(CAPSTONE_ARCHS))) endif +DEP_BPF = +DEP_BPF += $(wildcard arch/BPF/BPF*.inc) + +LIBOBJ_BPF = +ifneq (,$(findstring bpf,$(CAPSTONE_ARCHS))) + CFLAGS += -DCAPSTONE_HAS_BPF + LIBSRC_BPF += $(wildcard arch/BPF/BPF*.c) + LIBOBJ_BPF += $(LIBSRC_BPF:%.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 += $(LIBOBJ_X86) $(LIBOBJ_XCORE) $(LIBOBJ_TMS320C64X) $(LIBOBJ_M680X) $(LIBOBJ_EVM) $(LIBOBJ_MOS65XX) $(LIBOBJ_WASM) +LIBOBJ += $(LIBOBJ_X86) $(LIBOBJ_XCORE) $(LIBOBJ_TMS320C64X) $(LIBOBJ_M680X) $(LIBOBJ_EVM) $(LIBOBJ_MOS65XX) $(LIBOBJ_WASM) $(LIBOBJ_BPF) LIBOBJ += $(OBJDIR)/MCInst.o @@ -405,6 +416,7 @@ $(LIBOBJ_M680X): $(DEP_M680X) $(LIBOBJ_EVM): $(DEP_EVM) $(LIBOBJ_WASM): $(DEP_WASM) $(LIBOBJ_MOS65XX): $(DEP_MOS65XX) +$(LIBOBJ_BPF): $(DEP_BPF) ifeq ($(CAPSTONE_STATIC),yes) $(ARCHIVE): $(LIBOBJ) @@ -480,12 +492,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 test_mos65xx test_wasm +TESTS += test_systemz test_x86 test_xcore test_iter test_evm test_mos65xx test_wasm test_bpf 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 test_wasm.static +TESTS += test_mos65xx.static test_wasm.static test_bpf.static check: $(TESTS) fuzztest fuzzallcorp test_%: ./tests/$@ > /dev/null && echo OK || echo FAILED diff --git a/arch/BPF/BPFDisassembler.c b/arch/BPF/BPFDisassembler.c new file mode 100644 index 0000000000..5a07797611 --- /dev/null +++ b/arch/BPF/BPFDisassembler.c @@ -0,0 +1,108 @@ +/* Capstone Disassembly Engine */ +/* BPF Backend by david942j , 2019 */ + +#ifdef CAPSTONE_HAS_BPF + +#include "../../cs_priv.h" + +#include "BPFDisassembler.h" + +static uint16_t read_u16(cs_struct *ud, const uint8_t *code) +{ + if (MODE_IS_BIG_ENDIAN(ud->mode)) + return (code[0] << 8 | code[1]); + else + return (code[1] << 8 | code[0]); +} + +static uint32_t read_u32(cs_struct *ud, const uint8_t *code) +{ + if (MODE_IS_BIG_ENDIAN(ud->mode)) + return (code[3] << 0) | + (code[2] << 8) | + (code[1] << 16) | + ((uint32_t) code[0] << 24); + else + return ((uint32_t) code[3] << 24) | + (code[2] << 16) | + (code[1] << 8) | + (code[0] << 0); +} + +static bpf_internal *alloc_bpf_internal(size_t code_len) +{ + if (code_len < 8) + return NULL; + return cs_mem_malloc(sizeof(bpf_internal)); +} + +// Fetch a cBPF structure from code +static bpf_internal* fetch_cbpf(cs_struct *ud, const uint8_t *code, + size_t code_len) +{ + bpf_internal *bpf; + + bpf = alloc_bpf_internal(code_len); + if (bpf == NULL) + return NULL; + + bpf->op = read_u16(ud, code); + bpf->jt = *(code + 2); + bpf->jf = *(code + 3); + bpf->k = read_u32(ud, code + 4); + return bpf; +} + +// Fetch an eBPF structure from code +static bpf_internal* fetch_ebpf(cs_struct *ud, const uint8_t *code, + size_t code_len) +{ + bpf_internal *bpf; + + bpf = alloc_bpf_internal(code_len); + if (bpf == NULL) + return NULL; + + bpf->op = (uint16_t)code[0]; + bpf->dst = *(code + 1) & 0xf; + bpf->src = (*(code + 1) & 0xf0) >> 4; + bpf->offset = read_u16(ud, code + 2); + bpf->k = read_u32(ud, code + 4); + return bpf; +} + +static bool getInstruction(cs_struct *ud, MCInst *MI, bpf_internal *bpf, + uint64_t address) +{ + return false; +} + +bool CBPF_getInstruction(csh ud, const uint8_t *code, size_t code_len, + MCInst *instr, uint16_t *size, uint64_t address, void *info) +{ + bpf_internal *bpf; + + bpf = fetch_cbpf((cs_struct*)ud, code, code_len); + if (bpf == NULL) + return false; + if (!getInstruction((cs_struct*)ud, instr, bpf, address)) + return false; + *size = 8; + return true; +} + +bool EBPF_getInstruction(csh ud, const uint8_t *code, size_t code_len, + MCInst *instr, uint16_t *size, uint64_t address, void *info) +{ + bpf_internal *bpf; + + bpf = fetch_ebpf((cs_struct*)ud, code, code_len); + if (bpf == NULL) + return false; + if (!getInstruction((cs_struct*)ud, instr, bpf, address)) + return false; + *size = 8; + return true; +} + +#endif diff --git a/arch/BPF/BPFDisassembler.h b/arch/BPF/BPFDisassembler.h new file mode 100644 index 0000000000..6a05b8bd85 --- /dev/null +++ b/arch/BPF/BPFDisassembler.h @@ -0,0 +1,27 @@ +/* Capstone Disassembly Engine */ +/* BPF Backend by david942j , 2019 */ + +#ifndef CS_BPF_DISASSEMBLER_H +#define CS_BPF_DISASSEMBLER_H + +#include "../../MCInst.h" + +typedef struct bpf_internal { + uint16_t op; + uint32_t k; + /* for cBPF */ + uint8_t jt; + uint8_t jf; + /* for eBPF */ + uint8_t dst; + uint8_t src; + uint16_t offset; +} bpf_internal; + +bool CBPF_getInstruction(csh ud, const uint8_t *code, size_t code_len, + MCInst *instr, uint16_t *size, uint64_t address, void *info); + +bool EBPF_getInstruction(csh ud, const uint8_t *code, size_t code_len, + MCInst *instr, uint16_t *size, uint64_t address, void *info); + +#endif diff --git a/arch/BPF/BPFModule.c b/arch/BPF/BPFModule.c new file mode 100644 index 0000000000..6d618f8480 --- /dev/null +++ b/arch/BPF/BPFModule.c @@ -0,0 +1,27 @@ +/* Capstone Disassembly Engine */ +/* BPF Backend by david942j , 2019 */ + +#ifdef CAPSTONE_HAS_BPF + +#include "BPFDisassembler.h" +#include "BPFModule.h" + +cs_err BPF_global_init(cs_struct *ud) +{ + return CS_ERR_OK; +} + +cs_err BPF_option(cs_struct *handle, cs_opt_type type, size_t value) +{ + if (type == CS_OPT_MODE) { + if (value & CS_MODE_BPF_EXTENDED) + handle->disasm = EBPF_getInstruction; + else + handle->disasm = CBPF_getInstruction; + + handle->mode = (cs_mode)value; + } + return CS_ERR_OK; +} + +#endif diff --git a/arch/BPF/BPFModule.h b/arch/BPF/BPFModule.h new file mode 100644 index 0000000000..0ff003382f --- /dev/null +++ b/arch/BPF/BPFModule.h @@ -0,0 +1,12 @@ +/* Capstone Disassembly Engine */ +/* BPF Backend by david942j , 2019 */ + +#ifndef CS_BPF_MODULE_H +#define CS_BPF_MODULE_H + +#include "../../utils.h" + +cs_err BPF_global_init(cs_struct *ud); +cs_err BPF_option(cs_struct *handle, cs_opt_type type, size_t value); + +#endif diff --git a/config.mk b/config.mk index 6a935604ae..052fc78168 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 mos65xx wasm +CAPSTONE_ARCHS ?= arm aarch64 m68k mips powerpc sparc systemz x86 xcore tms320c64x m680x evm mos65xx wasm bpf ################################################################################ diff --git a/cs.c b/cs.c index abae2a6c36..e9e681d832 100644 --- a/cs.c +++ b/cs.c @@ -66,6 +66,7 @@ #include "arch/X86/X86Module.h" #include "arch/XCore/XCoreModule.h" #include "arch/MOS65XX/MOS65XXModule.h" +#include "arch/BPF/BPFModule.h" // constructor initialization for all archs static cs_err (*cs_arch_init[MAX_ARCH])(cs_struct *) = { @@ -139,6 +140,11 @@ static cs_err (*cs_arch_init[MAX_ARCH])(cs_struct *) = { #else NULL, #endif +#ifdef CAPSTONE_HAS_BPF + BPF_global_init, +#else + NULL, +#endif }; // support cs_option() for all archs @@ -213,7 +219,11 @@ static cs_err (*cs_arch_option[MAX_ARCH]) (cs_struct *, cs_opt_type, size_t valu #else NULL, #endif - +#ifdef CAPSTONE_HAS_BPF + BPF_option, +#else + NULL, +#endif }; // bitmask for finding disallowed modes for an arch: @@ -296,6 +306,12 @@ static cs_mode cs_arch_disallowed_mode_mask[MAX_ARCH] = { #else 0, #endif +#ifdef CAPSTONE_HAS_BPF + ~(CS_MODE_LITTLE_ENDIAN | CS_MODE_BPF_CLASSIC | CS_MODE_BPF_EXTENDED + | CS_MODE_BIG_ENDIAN), +#else + 0, +#endif }; // bitmask of enabled architectures @@ -342,6 +358,9 @@ static uint32_t all_arch = 0 #ifdef CAPSTONE_HAS_MOS65XX | (1 << CS_ARCH_MOS65XX) #endif +#ifdef CAPSTONE_HAS_BPF + | (1 << CS_ARCH_BPF) +#endif ; @@ -413,7 +432,8 @@ bool CAPSTONE_API cs_support(int query) (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_MOS65XX) | (1 << CS_ARCH_WASM)); + (1 << CS_ARCH_MOS65XX) | (1 << CS_ARCH_WASM) | + (1 << CS_ARCH_BPF)); if ((unsigned int)query < CS_ARCH_MAX) return all_arch & (1 << query); @@ -685,6 +705,9 @@ static uint8_t skipdata_size(cs_struct *handle) case CS_ARCH_MOS65XX: // MOS65XX alignment is 1. return 1; + case CS_ARCH_BPF: + // both classic and extended BPF have alignment 8. + return 8; } } @@ -1409,6 +1432,11 @@ int CAPSTONE_API cs_op_count(csh ud, const cs_insn *insn, unsigned int op_type) if (insn->detail->wasm.operands[i].type == (wasm_op_type)op_type) count++; break; + case CS_ARCH_BPF: + for (i = 0; i < insn->detail->bpf.op_count; i++) + if (insn->detail->bpf.operands[i].type == (bpf_op_type)op_type) + count++; + break; } return count; @@ -1560,7 +1588,14 @@ int CAPSTONE_API cs_op_index(csh ud, const cs_insn *insn, unsigned int op_type, return i; } break; - + case CS_ARCH_BPF: + for (i = 0; i < insn->detail->bpf.op_count; i++) { + if (insn->detail->bpf.operands[i].type == (bpf_op_type)op_type) + count++; + if (count == post) + return i; + } + break; } return -1; diff --git a/include/capstone/bpf.h b/include/capstone/bpf.h new file mode 100644 index 0000000000..7d0e233c1a --- /dev/null +++ b/include/capstone/bpf.h @@ -0,0 +1,35 @@ +/* Capstone Disassembly Engine */ +/* BPF Backend by david942j , 2019 */ + +#ifndef CAPSTONE_BPF_H +#define CAPSTONE_BPF_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include "platform.h" + +#ifdef _MSC_VER +#pragma warning(disable:4201) +#endif + +typedef enum bpf_op_type { + BPF_OP_INVALID = 0, +} bpf_op_type; + +typedef struct cs_bpf_op { + bpf_op_type type; +} cs_bpf_op; + +/// Instruction structure +typedef struct cs_bpf { + uint8_t op_count; + cs_bpf_op *operands; +} cs_bpf; + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/include/capstone/capstone.h b/include/capstone/capstone.h index e030d7af8d..a32f847131 100644 --- a/include/capstone/capstone.h +++ b/include/capstone/capstone.h @@ -86,6 +86,7 @@ typedef enum cs_arch { CS_ARCH_EVM, ///< Ethereum architecture CS_ARCH_MOS65XX, ///< MOS65XX architecture (including MOS6502) CS_ARCH_WASM, ///< WebAssembly architecture + CS_ARCH_BPF, ///< Berkeley Packet Filter architecture (including eBPF) CS_ARCH_MAX, CS_ARCH_ALL = 0xFFFF, // All architectures - for cs_support() } cs_arch; @@ -136,6 +137,8 @@ typedef enum cs_mode { CS_MODE_M680X_CPU12 = 1 << 9, ///< M680X Motorola/Freescale/NXP CPU12 ///< used on M68HC12/HCS12 CS_MODE_M680X_HCS08 = 1 << 10, ///< M680X Freescale/NXP HCS08 mode + CS_MODE_BPF_CLASSIC = 0, ///< Classic BPF mode + CS_MODE_BPF_EXTENDED = 1 << 1, ///< Extended BPF mode } cs_mode; typedef void* (CAPSTONE_API *cs_malloc_t)(size_t size); @@ -261,6 +264,7 @@ typedef struct cs_opt_skipdata { /// EVM: 1 bytes. /// WASM: 1 bytes. /// MOS65XX: 1 bytes. + /// BPF: 8 bytes. cs_skipdata_cb_t callback; // default value is NULL /// User-defined data to be passed to @callback function pointer. @@ -282,6 +286,7 @@ typedef struct cs_opt_skipdata { #include "evm.h" #include "wasm.h" #include "mos65xx.h" +#include "bpf.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)) @@ -314,6 +319,7 @@ typedef struct cs_detail { cs_evm evm; ///< Ethereum architecture cs_mos65xx mos65xx; ///< MOS65XX architecture (including MOS6502) cs_wasm wasm; ///< Web Assembly architecture + cs_bpf bpf; ///< Berkeley Packet Filter architecture (including eBPF) }; } cs_detail; From baf9a01a9796a5b28770fb67222a8ece3161716a Mon Sep 17 00:00:00 2001 From: david942j Date: Wed, 13 Feb 2019 23:41:11 -0800 Subject: [PATCH 02/35] Define some constants --- .gitignore | 1 + arch/BPF/BPFConstants.h | 77 +++++++++++++++++++++++ arch/BPF/BPFDisassembler.c | 111 +++++++++++++++++++++++++++----- arch/BPF/BPFDisassembler.h | 5 +- arch/BPF/BPFModule.c | 6 +- include/capstone/bpf.h | 56 +++++++++++++++++ tests/Makefile | 4 ++ tests/test_bpf.c | 125 +++++++++++++++++++++++++++++++++++++ 8 files changed, 360 insertions(+), 25 deletions(-) create mode 100644 arch/BPF/BPFConstants.h create mode 100644 tests/test_bpf.c diff --git a/.gitignore b/.gitignore index 1a6d320d25..6cb0223403 100644 --- a/.gitignore +++ b/.gitignore @@ -70,6 +70,7 @@ tests/test_m680x tests/test_evm tests/test_wasm tests/test_mos65xx +tests/test_bpf # regress binaries suite/regress/invalid_read_in_print_operand diff --git a/arch/BPF/BPFConstants.h b/arch/BPF/BPFConstants.h new file mode 100644 index 0000000000..0abcd980cd --- /dev/null +++ b/arch/BPF/BPFConstants.h @@ -0,0 +1,77 @@ +/* Capstone Disassembly Engine */ +/* BPF Backend by david942j , 2019 */ + +/* This file defines constants and macros used for parsing a BPF instruction */ + +#ifndef CS_BPF_CONSTANTS_H +#define CS_BPF_CONSTANTS_H + +#define BPF_CLASS(code) ((code) & 0x7) + +///< Instruction classes +#define BPF_CLASS_LD 0x00 +#define BPF_CLASS_LDX 0x01 +#define BPF_CLASS_ST 0x02 +#define BPF_CLASS_STX 0x03 +#define BPF_CLASS_ALU 0x04 +#define BPF_CLASS_JMP 0x05 +#define BPF_CLASS_RET 0x06 ///< cBPF only +#define BPF_CLASS_MISC 0x07 ///< cBPF only +#define BPF_CLASS_ALU64 0x07 ///< eBPF only + +#define BPF_OP(code) ((code) & 0xf0) + +///< Types of ALU instruction +#define BPF_ALU_ADD 0x00 +#define BPF_ALU_SUB 0x10 +#define BPF_ALU_MUL 0x20 +#define BPF_ALU_DIV 0x30 +#define BPF_ALU_OR 0x40 +#define BPF_ALU_AND 0x50 +#define BPF_ALU_LSH 0x60 +#define BPF_ALU_RSH 0x70 +#define BPF_ALU_NEG 0x80 +#define BPF_ALU_MOD 0x90 +#define BPF_ALU_XOR 0xa0 +#define BPF_ALU_MOV 0xb0 ///< eBPF only: mov reg to reg +#define BPF_ALU_ARSH 0xc0 ///< eBPF only: sign extending shift right +#define BPF_ALU_END 0xd0 ///< eBPF only: endianness conversion + +///< Types of jmp instruction +#define BPF_JUMP_JA 0x00 ///< goto +#define BPF_JUMP_JEQ 0x10 ///< '==' +#define BPF_JUMP_JGT 0x20 ///< unsigned '>' +#define BPF_JUMP_JGE 0x30 ///< unsigned '>=' +#define BPF_JUMP_JSET 0x40 ///< '&' +#define BPF_JUMP_JNE 0x50 ///< eBPF only: '!=' */ +#define BPF_JUMP_JSGT 0x60 ///< eBPF only: signed '>' +#define BPF_JUMP_JSGE 0x70 ///< eBPF only: signed '>=' +#define BPF_JUMP_CALL 0x80 ///< eBPF only: function call +#define BPF_JUMP_EXIT 0x90 ///< eBPF only: exit +#define BPF_JUMP_JLT 0xa0 ///< eBPF only: unsigned '<' +#define BPF_JUMP_JLE 0xb0 ///< eBPF only: unsigned '<=' +#define BPF_JUMP_JSLT 0xc0 ///< eBPF only: signed '<' +#define BPF_JUMP_JSLE 0xd0 ///< eBPF only: signed '<=' + +#define BPF_SRC(code) ((code) & 0x80) + +///< Source operand +#define BPF_SRC_K 0x00 +#define BPF_SRC_X 0x80 + +///< Size modifier +#define BPF_SIZE_W 0x00 ///< word +#define BPF_SIZE_H 0x08 ///< half word +#define BPF_SIZE_B 0x10 ///< byte +#define BPF_SIZE_DW 0x18 ///< eBPF only: double word + +///< Mode modifier +#define BPF_MODE_IMM 0x00 ///< used for 32-bit mov in cBPF and 64-bit in eBPF +#define BPF_MODE_ABS 0x20 +#define BPF_MODE_IND 0x40 +#define BPF_MODE_MEM 0x60 +#define BPF_MODE_LEN 0x80 ///< cBPF only, reserved in eBPF +#define BPF_MODE_MSH 0xa0 ///< cBPF only, reserved in eBPF +#define BPF_MODE_XADD 0xc0 ///< eBPF only: exclusive add + +#endif diff --git a/arch/BPF/BPFDisassembler.c b/arch/BPF/BPFDisassembler.c index 5a07797611..912b555b4e 100644 --- a/arch/BPF/BPFDisassembler.c +++ b/arch/BPF/BPFDisassembler.c @@ -3,8 +3,12 @@ #ifdef CAPSTONE_HAS_BPF +#include +#include // offsetof macro + #include "../../cs_priv.h" +#include "BPFConstants.h" #include "BPFDisassembler.h" static uint16_t read_u16(cs_struct *ud, const uint8_t *code) @@ -71,32 +75,107 @@ static bpf_internal* fetch_ebpf(cs_struct *ud, const uint8_t *code, return bpf; } +#define EBPF_MODE(ud) ((ud)->mode & CS_MODE_BPF_EXTENDED) + static bool getInstruction(cs_struct *ud, MCInst *MI, bpf_internal *bpf, uint64_t address) { + cs_detail *detail; + uint8_t opcode; + + detail = MI->flat_insn->detail; + // initialize detail + if (detail) { + memset(detail, 0, offsetof(cs_detail, bpf) + sizeof(cs_bpf)); + } + + opcode = bpf->op; + MI->address = address; + MI->OpcodePub = MI->Opcode = opcode; + switch (BPF_CLASS(bpf->op)) { + default: // will never happen + break; + case BPF_CLASS_LD: + if (detail) { + detail->groups[detail->groups_count] = BPF_GRP_LOAD; + detail->groups_count++; + } + break; + case BPF_CLASS_LDX: + if (detail) { + detail->groups[detail->groups_count] = BPF_GRP_LOAD; + detail->groups_count++; + } + break; + case BPF_CLASS_ST: + if (detail) { + detail->groups[detail->groups_count] = BPF_GRP_STORE; + detail->groups_count++; + } + break; + case BPF_CLASS_STX: + if (detail) { + detail->groups[detail->groups_count] = BPF_GRP_STORE; + detail->groups_count++; + } + break; + case BPF_CLASS_ALU: + if (detail) { + detail->groups[detail->groups_count] = BPF_GRP_ALU; + detail->groups_count++; + } + break; + case BPF_CLASS_JMP: + if (detail) { + bpf_insn_group grp = BPF_GRP_JUMP; + + if (EBPF_MODE(ud)) { + // TODO: use BPF_INSN_CALL / BPF_INSN_RETURN_R0 on MI to check + if (opcode == 0x85) + grp = BPF_GRP_CALL; + else if (opcode == 0x95) + grp = BPF_GRP_RETURN; + } + detail->groups[detail->groups_count] = grp; + detail->groups_count++; + } + break; + case BPF_CLASS_RET: + // this class in eBPF is reserved. + if (EBPF_MODE(ud)) + return false; + if (detail) { + detail->groups[detail->groups_count] = BPF_GRP_RETURN; + detail->groups_count++; + } + // BPF_CLASS_MISC and BPF_CLASS_ALU64 have exactly same value + case BPF_CLASS_MISC: + /* case BPF_CLASS_ALU64: */ + if (detail) { + bpf_insn_group grp; + + if (EBPF_MODE(ud)) + grp = BPF_GRP_ALU; + else + grp = BPF_GRP_MISC; + detail->groups[detail->groups_count] = grp; + detail->groups_count++; + } + } return false; } -bool CBPF_getInstruction(csh ud, const uint8_t *code, size_t code_len, +bool BPF_getInstruction(csh ud, const uint8_t *code, size_t code_len, MCInst *instr, uint16_t *size, uint64_t address, void *info) { + cs_struct *cs; bpf_internal *bpf; - bpf = fetch_cbpf((cs_struct*)ud, code, code_len); - if (bpf == NULL) - return false; - if (!getInstruction((cs_struct*)ud, instr, bpf, address)) - return false; - *size = 8; - return true; -} - -bool EBPF_getInstruction(csh ud, const uint8_t *code, size_t code_len, - MCInst *instr, uint16_t *size, uint64_t address, void *info) -{ - bpf_internal *bpf; - - bpf = fetch_ebpf((cs_struct*)ud, code, code_len); + cs = (cs_struct*)ud; + if (cs->mode & CS_MODE_BPF_EXTENDED) + bpf = fetch_ebpf(cs, code, code_len); + else + bpf = fetch_cbpf(cs, code, code_len); if (bpf == NULL) return false; if (!getInstruction((cs_struct*)ud, instr, bpf, address)) diff --git a/arch/BPF/BPFDisassembler.h b/arch/BPF/BPFDisassembler.h index 6a05b8bd85..0c5c0163ef 100644 --- a/arch/BPF/BPFDisassembler.h +++ b/arch/BPF/BPFDisassembler.h @@ -18,10 +18,7 @@ typedef struct bpf_internal { uint16_t offset; } bpf_internal; -bool CBPF_getInstruction(csh ud, const uint8_t *code, size_t code_len, - MCInst *instr, uint16_t *size, uint64_t address, void *info); - -bool EBPF_getInstruction(csh ud, const uint8_t *code, size_t code_len, +bool BPF_getInstruction(csh ud, const uint8_t *code, size_t code_len, MCInst *instr, uint16_t *size, uint64_t address, void *info); #endif diff --git a/arch/BPF/BPFModule.c b/arch/BPF/BPFModule.c index 6d618f8480..58245c2cd5 100644 --- a/arch/BPF/BPFModule.c +++ b/arch/BPF/BPFModule.c @@ -8,17 +8,13 @@ cs_err BPF_global_init(cs_struct *ud) { + ud->disasm = BPF_getInstruction; return CS_ERR_OK; } cs_err BPF_option(cs_struct *handle, cs_opt_type type, size_t value) { if (type == CS_OPT_MODE) { - if (value & CS_MODE_BPF_EXTENDED) - handle->disasm = EBPF_getInstruction; - else - handle->disasm = CBPF_getInstruction; - handle->mode = (cs_mode)value; } return CS_ERR_OK; diff --git a/include/capstone/bpf.h b/include/capstone/bpf.h index 7d0e233c1a..fee2512f76 100644 --- a/include/capstone/bpf.h +++ b/include/capstone/bpf.h @@ -14,12 +14,48 @@ extern "C" { #pragma warning(disable:4201) #endif +/// Operand type for instruction's operands typedef enum bpf_op_type { BPF_OP_INVALID = 0, + + BPF_OP_REG, + BPF_OP_IMM, + BPF_OP_MEM } bpf_op_type; +/// BPF registers +typedef enum bpf_reg { + BPF_REG_INVALID = 0, + BPF_REG_R0, + BPF_REG_R1, + BPF_REG_R2, + BPF_REG_R3, + BPF_REG_R4, + BPF_REG_R5, + BPF_REG_R6, + BPF_REG_R7, + BPF_REG_R8, + BPF_REG_R9, + BPF_REG_R10, + + BPF_REG_ENDING, // <-- mark the end of the list or registers +} bpf_reg; + +/// Instruction's operand referring to memory +/// This is associated with BPF_OP_MEM operand type above +typedef struct bpf_op_mem { + bpf_reg base; ///< base register + int32_t disp; ///< offset value +} bpf_op_mem; + +/// Instruction operand typedef struct cs_bpf_op { bpf_op_type type; + union { + uint8_t reg; ///< register value for REG operand + uint32_t imm; ///< immediate value IMM operand + bpf_op_mem mem; ///< base/index/scale/disp value for MEM operand + }; } cs_bpf_op; /// Instruction structure @@ -28,6 +64,26 @@ typedef struct cs_bpf { cs_bpf_op *operands; } cs_bpf; +/// BPF instruction +typedef enum bpf_insn { + BPF_INSN_ENDING, +} bpf_insn; + +/// Group of BPF instructions +typedef enum bpf_insn_group { + BPF_GRP_INVALID = 0, ///< = CS_GRP_INVALID + + BPF_GRP_LOAD, + BPF_GRP_STORE, + BPF_GRP_ALU, + BPF_GRP_JUMP, + BPF_GRP_CALL, ///< eBPF only + BPF_GRP_RETURN, + BPF_GRP_MISC, ///< cBPF only + + BPF_GRP_ENDING, ///< <-- mark the end of the list of groups +} bpf_insn_group; + #ifdef __cplusplus } #endif diff --git a/tests/Makefile b/tests/Makefile index f1d22e5e0b..eda7e3d054 100644 --- a/tests/Makefile +++ b/tests/Makefile @@ -121,6 +121,10 @@ 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))) diff --git a/tests/test_bpf.c b/tests/test_bpf.c new file mode 100644 index 0000000000..5f3971553b --- /dev/null +++ b/tests/test_bpf.c @@ -0,0 +1,125 @@ +/* Capstone Disassembly Engine */ +/* By david942j , 2019 */ + +#include +#include + +static csh handle; + +struct platform { + cs_arch arch; + cs_mode mode; + unsigned char *code; + size_t size; + 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_bpf *bpf; + + // 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); + + int i; + + printf("\tOperand count: %u\n", bpf->op_count); + + for (i = 0; i < bpf->op_count; i++) { + cs_bpf_op *op = &(bpf->operands[i]); + switch (op->type) { + default: + break; + case BPF_OP_IMM: + printf("\t\toperands[%u].type: IMM = 0x%x\n", i, op->imm); + break; + } + } +} + +static void test() +{ +#define EBPF_CODE "\x30\x00\x00\x00\x00\x00\x00\x00" + struct platform platforms[] = { + { + 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]); + } + 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; +} From 1250b092d2a9b085423a85b6ab3b7ee7a4b2e4b3 Mon Sep 17 00:00:00 2001 From: david942j Date: Thu, 14 Feb 2019 09:10:10 -0800 Subject: [PATCH 03/35] defined some API methods --- CMakeLists.txt | 5 ++ arch/BPF/BPFConstants.h | 3 +- arch/BPF/BPFDisassembler.c | 41 +++++++--------- arch/BPF/BPFInstPrinter.c | 12 +++++ arch/BPF/BPFInstPrinter.h | 16 +++++++ arch/BPF/BPFMapping.c | 78 ++++++++++++++++++++++++++++++ arch/BPF/BPFMapping.h | 18 +++++++ arch/BPF/BPFModule.c | 14 ++++++ include/capstone/bpf.h | 98 +++++++++++++++++++++++++++++++++++++- 9 files changed, 259 insertions(+), 26 deletions(-) create mode 100644 arch/BPF/BPFInstPrinter.c create mode 100644 arch/BPF/BPFInstPrinter.h create mode 100644 arch/BPF/BPFMapping.c create mode 100644 arch/BPF/BPFMapping.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 923e4eae76..7dc626a0f5 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -481,10 +481,15 @@ if (NOT CAPSTONE_X86_ONLY AND CAPSTONE_BPF_SUPPORT) add_definitions(-DCAPSTONE_HAS_BPF) set(SOURCES_BPF arch/BPF/BPFDisassembler.c + arch/BPF/BPFInstPrinter.c + arch/BPF/BPFMapping.c arch/BPF/BPFModule.c ) set(HEADERS_BPF + arch/BPF/BPFConstants.h arch/BPF/BPFDisassembler.h + arch/BPF/BPFInstPrinter.h + arch/BPF/BPFMapping.h arch/BPF/BPFModule.h ) set(TEST_SOURCES ${TEST_SOURCES} test_bpf.c) diff --git a/arch/BPF/BPFConstants.h b/arch/BPF/BPFConstants.h index 0abcd980cd..2eec463b4d 100644 --- a/arch/BPF/BPFConstants.h +++ b/arch/BPF/BPFConstants.h @@ -54,17 +54,18 @@ #define BPF_JUMP_JSLE 0xd0 ///< eBPF only: signed '<=' #define BPF_SRC(code) ((code) & 0x80) - ///< Source operand #define BPF_SRC_K 0x00 #define BPF_SRC_X 0x80 +#define BPF_SIZE(code) ((code) & 0x18) ///< Size modifier #define BPF_SIZE_W 0x00 ///< word #define BPF_SIZE_H 0x08 ///< half word #define BPF_SIZE_B 0x10 ///< byte #define BPF_SIZE_DW 0x18 ///< eBPF only: double word +#define BPF_MODE(code) ((code) & 0xe0) ///< Mode modifier #define BPF_MODE_IMM 0x00 ///< used for 32-bit mov in cBPF and 64-bit in eBPF #define BPF_MODE_ABS 0x20 diff --git a/arch/BPF/BPFDisassembler.c b/arch/BPF/BPFDisassembler.c index 912b555b4e..ba9efc3de7 100644 --- a/arch/BPF/BPFDisassembler.c +++ b/arch/BPF/BPFDisassembler.c @@ -10,6 +10,7 @@ #include "BPFConstants.h" #include "BPFDisassembler.h" +#include "BPFMapping.h" static uint16_t read_u16(cs_struct *ud, const uint8_t *code) { @@ -75,8 +76,6 @@ static bpf_internal* fetch_ebpf(cs_struct *ud, const uint8_t *code, return bpf; } -#define EBPF_MODE(ud) ((ud)->mode & CS_MODE_BPF_EXTENDED) - static bool getInstruction(cs_struct *ud, MCInst *MI, bpf_internal *bpf, uint64_t address) { @@ -92,37 +91,38 @@ static bool getInstruction(cs_struct *ud, MCInst *MI, bpf_internal *bpf, opcode = bpf->op; MI->address = address; MI->OpcodePub = MI->Opcode = opcode; + +#define PUSH_GROUP(grp) do { \ + detail->groups[detail->groups_count] = grp; \ + detail->groups_count++; \ + } while(0) + switch (BPF_CLASS(bpf->op)) { default: // will never happen break; case BPF_CLASS_LD: if (detail) { - detail->groups[detail->groups_count] = BPF_GRP_LOAD; - detail->groups_count++; + PUSH_GROUP(BPF_GRP_LOAD); } break; case BPF_CLASS_LDX: if (detail) { - detail->groups[detail->groups_count] = BPF_GRP_LOAD; - detail->groups_count++; + PUSH_GROUP(BPF_GRP_LOAD); } break; case BPF_CLASS_ST: if (detail) { - detail->groups[detail->groups_count] = BPF_GRP_STORE; - detail->groups_count++; + PUSH_GROUP(BPF_GRP_STORE); } break; case BPF_CLASS_STX: if (detail) { - detail->groups[detail->groups_count] = BPF_GRP_STORE; - detail->groups_count++; + PUSH_GROUP(BPF_GRP_STORE); } break; case BPF_CLASS_ALU: if (detail) { - detail->groups[detail->groups_count] = BPF_GRP_ALU; - detail->groups_count++; + PUSH_GROUP(BPF_GRP_ALU); } break; case BPF_CLASS_JMP: @@ -136,8 +136,7 @@ static bool getInstruction(cs_struct *ud, MCInst *MI, bpf_internal *bpf, else if (opcode == 0x95) grp = BPF_GRP_RETURN; } - detail->groups[detail->groups_count] = grp; - detail->groups_count++; + PUSH_GROUP(grp); } break; case BPF_CLASS_RET: @@ -145,24 +144,20 @@ static bool getInstruction(cs_struct *ud, MCInst *MI, bpf_internal *bpf, if (EBPF_MODE(ud)) return false; if (detail) { - detail->groups[detail->groups_count] = BPF_GRP_RETURN; - detail->groups_count++; + PUSH_GROUP(BPF_GRP_RETURN); } // BPF_CLASS_MISC and BPF_CLASS_ALU64 have exactly same value case BPF_CLASS_MISC: /* case BPF_CLASS_ALU64: */ if (detail) { - bpf_insn_group grp; - if (EBPF_MODE(ud)) - grp = BPF_GRP_ALU; + PUSH_GROUP(BPF_GRP_ALU); // ALU64 in eBPF else - grp = BPF_GRP_MISC; - detail->groups[detail->groups_count] = grp; - detail->groups_count++; + PUSH_GROUP(BPF_GRP_MISC); } } - return false; +#undef PUSH_GROUP + return true; } bool BPF_getInstruction(csh ud, const uint8_t *code, size_t code_len, diff --git a/arch/BPF/BPFInstPrinter.c b/arch/BPF/BPFInstPrinter.c new file mode 100644 index 0000000000..a78ea65c36 --- /dev/null +++ b/arch/BPF/BPFInstPrinter.c @@ -0,0 +1,12 @@ +/* Capstone Disassembly Engine */ +/* BPF Backend by david942j , 2019 */ + +#include "BPFInstPrinter.h" +#include "BPFMapping.h" + +void BPF_printInst(MCInst *MI, struct SStream *O, void *PrinterInfo) +{ + int i; + + SStream_concat(O, BPF_insn_name((csh)MI->csh, MI->Opcode)); +} diff --git a/arch/BPF/BPFInstPrinter.h b/arch/BPF/BPFInstPrinter.h new file mode 100644 index 0000000000..685a8d6565 --- /dev/null +++ b/arch/BPF/BPFInstPrinter.h @@ -0,0 +1,16 @@ +/* Capstone Disassembly Engine */ +/* BPF Backend by david942j , 2019 */ + +#ifndef CS_BPFINSTPRINTER_H +#define CS_BPFINSTPRINTER_H + +#include + +#include "../../MCInst.h" +#include "../../SStream.h" + +struct SStream; + +void BPF_printInst(MCInst *MI, struct SStream *O, void *Info); + +#endif diff --git a/arch/BPF/BPFMapping.c b/arch/BPF/BPFMapping.c new file mode 100644 index 0000000000..84c3928eef --- /dev/null +++ b/arch/BPF/BPFMapping.c @@ -0,0 +1,78 @@ +/* Capstone Disassembly Engine */ +/* BPF Backend by david942j , 2019 */ + +#include "BPFMapping.h" +#include "../../utils.h" + +#ifndef CAPSTONE_DIET +static const name_map group_name_maps[] = { + // generic groups + { BPF_GRP_INVALID, NULL }, + { BPF_GRP_LOAD, "load" }, + { BPF_GRP_STORE, "store" }, + { BPF_GRP_ALU, "alu" }, + { BPF_GRP_JUMP, "jump" }, + { BPF_GRP_CALL, "call" }, + { BPF_GRP_RETURN, "return" }, + { BPF_GRP_MISC, "misc" }, +}; +#endif + +const char *BPF_group_name(csh handle, unsigned int id) +{ +#ifndef CAPSTONE_DIET + return id2name(group_name_maps, ARR_SIZE(group_name_maps), id); +#else + return NULL; +#endif +} + +#ifndef CAPSTONE_DIET +static const name_map insn_name_maps[BPF_INS_ENDING] = { + { BPF_INS_INVALID, NULL }, + + { BPF_INS_LDABSB, "ldabsb" }, + + { BPF_INS_RET, "ret" }, +}; +#endif + +const char *BPF_insn_name(csh handle, unsigned int id) +{ +#ifndef CAPSTONE_DIET + return id2name(insn_name_maps, ARR_SIZE(insn_name_maps), id); +#else + return NULL; +#endif +} + +const char *BPF_reg_name(csh handle, unsigned int reg) +{ +#ifndef CAPSTONE_DIET + if (EBPF_MODE(handle)) { + if (reg < BPF_REG_R0 || reg > BPF_REG_R10) + return NULL; + static const char* reg_names[11] = { + "r0", "r1", "r2", "r3", "r4", + "r5", "r6", "r7", "r8", "r9", + "r10" + }; + return reg_names[reg - BPF_REG_R0]; + } + + /* cBPF mode */ + if (reg == BPF_REG_A) + return "A"; + else if (reg == BPF_REG_X) + return "X"; + else + return NULL; +#else + return NULL; +#endif +} + +void BPF_get_insn_id(cs_struct *h, cs_insn *insn, unsigned int id) +{ + insn->id = id; +} diff --git a/arch/BPF/BPFMapping.h b/arch/BPF/BPFMapping.h new file mode 100644 index 0000000000..828f2270ef --- /dev/null +++ b/arch/BPF/BPFMapping.h @@ -0,0 +1,18 @@ +/* Capstone Disassembly Engine */ +/* BPF Backend by david942j , 2019 */ + +#ifndef CS_BPFMAPPING_H +#define CS_BPFMAPPING_H + +#include + +#include "../../cs_priv.h" + +#define EBPF_MODE(ud) (((cs_struct*)ud)->mode & CS_MODE_BPF_EXTENDED) + +const char *BPF_group_name(csh handle, unsigned int id); +const char *BPF_insn_name(csh handle, unsigned int id); +const char *BPF_reg_name(csh handle, unsigned int reg); +void BPF_get_insn_id(cs_struct *h, cs_insn *insn, unsigned int id); + +#endif diff --git a/arch/BPF/BPFModule.c b/arch/BPF/BPFModule.c index 58245c2cd5..f6d56bb51c 100644 --- a/arch/BPF/BPFModule.c +++ b/arch/BPF/BPFModule.c @@ -4,11 +4,24 @@ #ifdef CAPSTONE_HAS_BPF #include "BPFDisassembler.h" +#include "BPFInstPrinter.h" +#include "BPFMapping.h" #include "BPFModule.h" cs_err BPF_global_init(cs_struct *ud) { + ud->printer = BPF_printInst; + ud->printer_info = NULL; + ud->reg_name = BPF_reg_name; + ud->insn_id = BPF_get_insn_id; + ud->insn_name = BPF_insn_name; + ud->group_name = BPF_group_name; + /* ud->post_printer = BPF_post_printer; */ +#ifndef CAPSTONE_DIET + /* ud->reg_access = BPF_reg_access; */ +#endif ud->disasm = BPF_getInstruction; + return CS_ERR_OK; } @@ -17,6 +30,7 @@ cs_err BPF_option(cs_struct *handle, cs_opt_type type, size_t value) if (type == CS_OPT_MODE) { handle->mode = (cs_mode)value; } + return CS_ERR_OK; } diff --git a/include/capstone/bpf.h b/include/capstone/bpf.h index fee2512f76..c8921bf413 100644 --- a/include/capstone/bpf.h +++ b/include/capstone/bpf.h @@ -26,6 +26,12 @@ typedef enum bpf_op_type { /// BPF registers typedef enum bpf_reg { BPF_REG_INVALID = 0, + + ///< cBPF + BPF_REG_A, + BPF_REG_X, + + ///< eBPF BPF_REG_R0, BPF_REG_R1, BPF_REG_R2, @@ -53,7 +59,7 @@ typedef struct cs_bpf_op { bpf_op_type type; union { uint8_t reg; ///< register value for REG operand - uint32_t imm; ///< immediate value IMM operand + uint64_t imm; ///< immediate value IMM operand bpf_op_mem mem; ///< base/index/scale/disp value for MEM operand }; } cs_bpf_op; @@ -66,7 +72,95 @@ typedef struct cs_bpf { /// BPF instruction typedef enum bpf_insn { - BPF_INSN_ENDING, + BPF_INS_INVALID = 0, + + ///< ALU + BPF_INS_ADD, + BPF_INS_SUB, + BPF_INS_MUL, + BPF_INS_DIV, + BPF_INS_OR, + BPF_INS_AND, + BPF_INS_LSH, + BPF_INS_RSH, + BPF_INS_NEG, + BPF_INS_MOD, + BPF_INS_XOR, + BPF_INS_MOV, ///< eBPF only + BPF_INS_ARSH, ///< eBPF only + + ///< ALU64, eBPF only + BPF_INS_ADD64, + BPF_INS_SUB64, + BPF_INS_MUL64, + BPF_INS_DIV64, + BPF_INS_OR64, + BPF_INS_AND64, + BPF_INS_LSH64, + BPF_INS_RSH64, + BPF_INS_NEG64, + BPF_INS_MOD64, + BPF_INS_XOR64, + BPF_INS_MOV64, + BPF_INS_ARSH64, + + ///< Byteswap, eBPF only + BPF_INS_LE16, + BPF_INS_LE32, + BPF_INS_LE64, + BPF_INS_BE16, + BPF_INS_BE32, + BPF_INS_BE64, + + ///< Load + BPF_INS_LDDW, ///< eBPF only, load 64-bit imm + BPF_INS_LDABSW, + BPF_INS_LDABSH, + BPF_INS_LDABSB, + BPF_INS_LDABSDW, ///< eBPF only + BPF_INS_LDINDW, + BPF_INS_LDINDH, + BPF_INS_LDINDB, + BPF_INS_LDINDDW, ///< eBPF only + BPF_INS_LDXW, + BPF_INS_LDXH, + BPF_INS_LDXB, + BPF_INS_LDXDW, ///< eBPF only + + ///< Store + BPF_INS_STW, + BPF_INS_STH, + BPF_INS_STB, + BPF_INS_STDW, ///< eBPF only + BPF_INS_STXW, + BPF_INS_STXH, + BPF_INS_STXB, + BPF_INS_STXDW, ///< eBPF only + + ///< Jump + BPF_INS_JA, + BPF_INS_JEQ, + BPF_INS_JGT, + BPF_INS_JGE, + BPF_INS_JSET, + BPF_INS_JNE, ///< eBPF only + BPF_INS_JSGT, ///< eBPF only + BPF_INS_JSGE, ///< eBPF only + BPF_INS_CALL, ///< eBPF only + BPF_INS_EXIT, ///< eBPF only + BPF_INS_JLT, ///< eBPF only + BPF_INS_JLE, ///< eBPF only + BPF_INS_JSLT, ///< eBPF only + BPF_INS_JSLE, ///< eBPF only + + ///< Return, cBPF only + BPF_INS_RET, + + ///< Misc, cBPF only + BPF_INS_TAX, + BPF_INS_TXA, + + BPF_INS_ENDING, } bpf_insn; /// Group of BPF instructions From ae2678db1a0990b8350e03bc42f83a27930ef8bd Mon Sep 17 00:00:00 2001 From: david942j Date: Thu, 14 Feb 2019 09:56:10 -0800 Subject: [PATCH 04/35] Able to print MISC instruction --- arch/BPF/BPFDisassembler.c | 21 +++++++++++++++++++-- arch/BPF/BPFMapping.c | 2 ++ tests/test_bpf.c | 8 ++++++++ 3 files changed, 29 insertions(+), 2 deletions(-) diff --git a/arch/BPF/BPFDisassembler.c b/arch/BPF/BPFDisassembler.c index ba9efc3de7..98279b6bc3 100644 --- a/arch/BPF/BPFDisassembler.c +++ b/arch/BPF/BPFDisassembler.c @@ -89,13 +89,19 @@ static bool getInstruction(cs_struct *ud, MCInst *MI, bpf_internal *bpf, } opcode = bpf->op; + + MCInst_clear(MI); MI->address = address; - MI->OpcodePub = MI->Opcode = opcode; + MCInst_setOpcodePub(MI, opcode); -#define PUSH_GROUP(grp) do { \ +#ifndef CAPSTONE_DIET + #define PUSH_GROUP(grp) do { \ detail->groups[detail->groups_count] = grp; \ detail->groups_count++; \ } while(0) +#else + #define PUSH_GROUP +#endif switch (BPF_CLASS(bpf->op)) { default: // will never happen @@ -149,6 +155,14 @@ static bool getInstruction(cs_struct *ud, MCInst *MI, bpf_internal *bpf, // BPF_CLASS_MISC and BPF_CLASS_ALU64 have exactly same value case BPF_CLASS_MISC: /* case BPF_CLASS_ALU64: */ + if (EBPF_MODE(ud)) { + } + else { + if (opcode & 0x80) + MCInst_setOpcode(MI, BPF_INS_TXA); + else + MCInst_setOpcode(MI, BPF_INS_TAX); + } if (detail) { if (EBPF_MODE(ud)) PUSH_GROUP(BPF_GRP_ALU); // ALU64 in eBPF @@ -175,6 +189,9 @@ bool BPF_getInstruction(csh ud, const uint8_t *code, size_t code_len, return false; if (!getInstruction((cs_struct*)ud, instr, bpf, address)) return false; + + cs_mem_free(bpf); + *size = 8; return true; } diff --git a/arch/BPF/BPFMapping.c b/arch/BPF/BPFMapping.c index 84c3928eef..b226672588 100644 --- a/arch/BPF/BPFMapping.c +++ b/arch/BPF/BPFMapping.c @@ -34,6 +34,8 @@ static const name_map insn_name_maps[BPF_INS_ENDING] = { { BPF_INS_LDABSB, "ldabsb" }, { BPF_INS_RET, "ret" }, + { BPF_INS_TAX, "tax" }, + { BPF_INS_TXA, "txa" }, }; #endif diff --git a/tests/test_bpf.c b/tests/test_bpf.c index 5f3971553b..bb9fc32d0a 100644 --- a/tests/test_bpf.c +++ b/tests/test_bpf.c @@ -64,6 +64,7 @@ static void print_insn_detail(csh cs_handle, cs_insn *ins) static void test() { +#define CBPF_CODE "\x87\x00\x00\x00\x00\x00\x00\x00\x07\x00\x00\x00\x00\x00\x00\x00" #define EBPF_CODE "\x30\x00\x00\x00\x00\x00\x00\x00" struct platform platforms[] = { { @@ -73,6 +74,13 @@ static void test() sizeof(EBPF_CODE) - 1, "eBPF Le" }, + { + CS_ARCH_BPF, + CS_MODE_LITTLE_ENDIAN | CS_MODE_BPF_CLASSIC, + (unsigned char *)CBPF_CODE, + sizeof(CBPF_CODE) - 1, + "cBPF Le" + }, }; uint64_t address = 0x0; cs_insn *insn; From a1fca0aa0b25c3fba4149acc1faa22d0b825c089 Mon Sep 17 00:00:00 2001 From: david942j Date: Thu, 14 Feb 2019 10:09:16 -0800 Subject: [PATCH 05/35] Follow Linux coding style --- arch/BPF/BPFConstants.h | 28 ++++---- arch/BPF/BPFDisassembler.c | 128 ++++++++++++++++++------------------- tests/test_bpf.c | 10 +-- 3 files changed, 83 insertions(+), 83 deletions(-) diff --git a/arch/BPF/BPFConstants.h b/arch/BPF/BPFConstants.h index 2eec463b4d..a783b778dc 100644 --- a/arch/BPF/BPFConstants.h +++ b/arch/BPF/BPFConstants.h @@ -22,23 +22,23 @@ #define BPF_OP(code) ((code) & 0xf0) ///< Types of ALU instruction -#define BPF_ALU_ADD 0x00 -#define BPF_ALU_SUB 0x10 -#define BPF_ALU_MUL 0x20 -#define BPF_ALU_DIV 0x30 -#define BPF_ALU_OR 0x40 -#define BPF_ALU_AND 0x50 -#define BPF_ALU_LSH 0x60 -#define BPF_ALU_RSH 0x70 -#define BPF_ALU_NEG 0x80 -#define BPF_ALU_MOD 0x90 -#define BPF_ALU_XOR 0xa0 -#define BPF_ALU_MOV 0xb0 ///< eBPF only: mov reg to reg +#define BPF_ALU_ADD 0x00 +#define BPF_ALU_SUB 0x10 +#define BPF_ALU_MUL 0x20 +#define BPF_ALU_DIV 0x30 +#define BPF_ALU_OR 0x40 +#define BPF_ALU_AND 0x50 +#define BPF_ALU_LSH 0x60 +#define BPF_ALU_RSH 0x70 +#define BPF_ALU_NEG 0x80 +#define BPF_ALU_MOD 0x90 +#define BPF_ALU_XOR 0xa0 +#define BPF_ALU_MOV 0xb0 ///< eBPF only: mov reg to reg #define BPF_ALU_ARSH 0xc0 ///< eBPF only: sign extending shift right -#define BPF_ALU_END 0xd0 ///< eBPF only: endianness conversion +#define BPF_ALU_END 0xd0 ///< eBPF only: endianness conversion ///< Types of jmp instruction -#define BPF_JUMP_JA 0x00 ///< goto +#define BPF_JUMP_JA 0x00 ///< goto #define BPF_JUMP_JEQ 0x10 ///< '==' #define BPF_JUMP_JGT 0x20 ///< unsigned '>' #define BPF_JUMP_JGE 0x30 ///< unsigned '>=' diff --git a/arch/BPF/BPFDisassembler.c b/arch/BPF/BPFDisassembler.c index 98279b6bc3..2f3989cd54 100644 --- a/arch/BPF/BPFDisassembler.c +++ b/arch/BPF/BPFDisassembler.c @@ -47,7 +47,7 @@ static bpf_internal* fetch_cbpf(cs_struct *ud, const uint8_t *code, { bpf_internal *bpf; - bpf = alloc_bpf_internal(code_len); + bpf = alloc_bpf_internal(code_len); if (bpf == NULL) return NULL; @@ -104,71 +104,71 @@ static bool getInstruction(cs_struct *ud, MCInst *MI, bpf_internal *bpf, #endif switch (BPF_CLASS(bpf->op)) { - default: // will never happen - break; - case BPF_CLASS_LD: - if (detail) { - PUSH_GROUP(BPF_GRP_LOAD); - } - break; - case BPF_CLASS_LDX: - if (detail) { - PUSH_GROUP(BPF_GRP_LOAD); - } - break; - case BPF_CLASS_ST: - if (detail) { - PUSH_GROUP(BPF_GRP_STORE); - } - break; - case BPF_CLASS_STX: - if (detail) { - PUSH_GROUP(BPF_GRP_STORE); - } - break; - case BPF_CLASS_ALU: - if (detail) { - PUSH_GROUP(BPF_GRP_ALU); - } - break; - case BPF_CLASS_JMP: - if (detail) { - bpf_insn_group grp = BPF_GRP_JUMP; - - if (EBPF_MODE(ud)) { - // TODO: use BPF_INSN_CALL / BPF_INSN_RETURN_R0 on MI to check - if (opcode == 0x85) - grp = BPF_GRP_CALL; - else if (opcode == 0x95) - grp = BPF_GRP_RETURN; - } - PUSH_GROUP(grp); - } - break; - case BPF_CLASS_RET: - // this class in eBPF is reserved. - if (EBPF_MODE(ud)) - return false; - if (detail) { - PUSH_GROUP(BPF_GRP_RETURN); - } - // BPF_CLASS_MISC and BPF_CLASS_ALU64 have exactly same value - case BPF_CLASS_MISC: - /* case BPF_CLASS_ALU64: */ + default: // will never happen + break; + case BPF_CLASS_LD: + if (detail) { + PUSH_GROUP(BPF_GRP_LOAD); + } + break; + case BPF_CLASS_LDX: + if (detail) { + PUSH_GROUP(BPF_GRP_LOAD); + } + break; + case BPF_CLASS_ST: + if (detail) { + PUSH_GROUP(BPF_GRP_STORE); + } + break; + case BPF_CLASS_STX: + if (detail) { + PUSH_GROUP(BPF_GRP_STORE); + } + break; + case BPF_CLASS_ALU: + if (detail) { + PUSH_GROUP(BPF_GRP_ALU); + } + break; + case BPF_CLASS_JMP: + if (detail) { + bpf_insn_group grp = BPF_GRP_JUMP; + if (EBPF_MODE(ud)) { + // TODO: use BPF_INSN_CALL / BPF_INSN_RETURN_R0 on MI to check + if (opcode == 0x85) + grp = BPF_GRP_CALL; + else if (opcode == 0x95) + grp = BPF_GRP_RETURN; } - else { - if (opcode & 0x80) - MCInst_setOpcode(MI, BPF_INS_TXA); - else - MCInst_setOpcode(MI, BPF_INS_TAX); - } - if (detail) { - if (EBPF_MODE(ud)) - PUSH_GROUP(BPF_GRP_ALU); // ALU64 in eBPF - else - PUSH_GROUP(BPF_GRP_MISC); - } + PUSH_GROUP(grp); + } + break; + case BPF_CLASS_RET: + // this class in eBPF is reserved. + if (EBPF_MODE(ud)) + return false; + if (detail) { + PUSH_GROUP(BPF_GRP_RETURN); + } + // BPF_CLASS_MISC and BPF_CLASS_ALU64 have exactly same value + case BPF_CLASS_MISC: + /* case BPF_CLASS_ALU64: */ + if (EBPF_MODE(ud)) { + } + else { + if (opcode & 0x80) + MCInst_setOpcode(MI, BPF_INS_TXA); + else + MCInst_setOpcode(MI, BPF_INS_TAX); + } + if (detail) { + if (EBPF_MODE(ud)) + PUSH_GROUP(BPF_GRP_ALU); // ALU64 in eBPF + else + PUSH_GROUP(BPF_GRP_MISC); + } } #undef PUSH_GROUP return true; diff --git a/tests/test_bpf.c b/tests/test_bpf.c index bb9fc32d0a..eb88a4231e 100644 --- a/tests/test_bpf.c +++ b/tests/test_bpf.c @@ -53,11 +53,11 @@ static void print_insn_detail(csh cs_handle, cs_insn *ins) for (i = 0; i < bpf->op_count; i++) { cs_bpf_op *op = &(bpf->operands[i]); switch (op->type) { - default: - break; - case BPF_OP_IMM: - printf("\t\toperands[%u].type: IMM = 0x%x\n", i, op->imm); - break; + default: + break; + case BPF_OP_IMM: + printf("\t\toperands[%u].type: IMM = 0x%x\n", i, op->imm); + break; } } } From 929a19094adbb0da478efd58092d1dd7209cd0c6 Mon Sep 17 00:00:00 2001 From: david942j Date: Fri, 15 Feb 2019 00:47:34 -0800 Subject: [PATCH 06/35] Ability to show ALU insn names --- arch/ARM/ARMMapping.c | 1 - arch/BPF/BPFConstants.h | 11 +- arch/BPF/BPFDisassembler.c | 275 ++++++++++++++++++++++++------------- arch/BPF/BPFDisassembler.h | 5 +- arch/BPF/BPFInstPrinter.c | 14 +- arch/BPF/BPFMapping.c | 158 ++++++++++++++++++++- tests/test_bpf.c | 10 +- 7 files changed, 368 insertions(+), 106 deletions(-) diff --git a/arch/ARM/ARMMapping.c b/arch/ARM/ARMMapping.c index 6043dfa08b..5f065fcaa8 100644 --- a/arch/ARM/ARMMapping.c +++ b/arch/ARM/ARMMapping.c @@ -281,7 +281,6 @@ static const insn_map insns[] = { void ARM_get_insn_id(cs_struct *h, cs_insn *insn, unsigned int id) { int i = insn_find(insns, ARR_SIZE(insns), id, &h->insn_cache); - //printf(">> id = %u\n", id); if (i != 0) { insn->id = insns[i].mapid; diff --git a/arch/BPF/BPFConstants.h b/arch/BPF/BPFConstants.h index a783b778dc..69984f22b6 100644 --- a/arch/BPF/BPFConstants.h +++ b/arch/BPF/BPFConstants.h @@ -53,10 +53,13 @@ #define BPF_JUMP_JSLT 0xc0 ///< eBPF only: signed '<' #define BPF_JUMP_JSLE 0xd0 ///< eBPF only: signed '<=' -#define BPF_SRC(code) ((code) & 0x80) +#define BPF_SRC(code) ((code) & 0x08) ///< Source operand #define BPF_SRC_K 0x00 -#define BPF_SRC_X 0x80 +#define BPF_SRC_X 0x08 + +#define BPF_SRC_LITTLE BPF_SRC_K +#define BPF_SRC_BIG BPF_SRC_X #define BPF_SIZE(code) ((code) & 0x18) ///< Size modifier @@ -75,4 +78,8 @@ #define BPF_MODE_MSH 0xa0 ///< cBPF only, reserved in eBPF #define BPF_MODE_XADD 0xc0 ///< eBPF only: exclusive add +///< Operation of misc +#define BPF_MISCOP_TAX 0x00 +#define BPF_MISCOP_TXA 0x80 + #endif diff --git a/arch/BPF/BPFDisassembler.c b/arch/BPF/BPFDisassembler.c index 2f3989cd54..71fa2b5af3 100644 --- a/arch/BPF/BPFDisassembler.c +++ b/arch/BPF/BPFDisassembler.c @@ -6,42 +6,51 @@ #include #include // offsetof macro -#include "../../cs_priv.h" - #include "BPFConstants.h" #include "BPFDisassembler.h" #include "BPFMapping.h" +#include "../../cs_priv.h" static uint16_t read_u16(cs_struct *ud, const uint8_t *code) { if (MODE_IS_BIG_ENDIAN(ud->mode)) - return (code[0] << 8 | code[1]); + return (((uint16_t)code[0] << 8) | code[1]); else - return (code[1] << 8 | code[0]); + return (((uint16_t)code[1] << 8) | code[0]); } static uint32_t read_u32(cs_struct *ud, const uint8_t *code) { if (MODE_IS_BIG_ENDIAN(ud->mode)) - return (code[3] << 0) | - (code[2] << 8) | - (code[1] << 16) | - ((uint32_t) code[0] << 24); + return ((uint32_t)read_u16(ud, code) << 16) | read_u16(ud, code + 2); + else + return ((uint32_t)read_u16(ud, code + 2) << 16) | read_u16(ud, code); +} + +static uint64_t read_u64(cs_struct *ud, const uint8_t *code) +{ + if (MODE_IS_BIG_ENDIAN(ud->mode)) + return ((uint64_t)read_u32(ud, code) << 32) | read_u32(ud, code + 4); else - return ((uint32_t) code[3] << 24) | - (code[2] << 16) | - (code[1] << 8) | - (code[0] << 0); + return ((uint64_t)read_u32(ud, code + 4) << 32) | read_u32(ud, code); } +///< Malloc bpf_internal, also checks if code_len is large enough. static bpf_internal *alloc_bpf_internal(size_t code_len) { + bpf_internal *bpf; + if (code_len < 8) return NULL; - return cs_mem_malloc(sizeof(bpf_internal)); + bpf = cs_mem_malloc(sizeof(bpf_internal)); + if (bpf == NULL) + return NULL; + /* default value */ + bpf->insn_size = 8; + return bpf; } -// Fetch a cBPF structure from code +///< Fetch a cBPF structure from code static bpf_internal* fetch_cbpf(cs_struct *ud, const uint8_t *code, size_t code_len) { @@ -52,13 +61,13 @@ static bpf_internal* fetch_cbpf(cs_struct *ud, const uint8_t *code, return NULL; bpf->op = read_u16(ud, code); - bpf->jt = *(code + 2); - bpf->jf = *(code + 3); + bpf->jt = code[2]; + bpf->jf = code[3]; bpf->k = read_u32(ud, code + 4); return bpf; } -// Fetch an eBPF structure from code +///< Fetch an eBPF structure from code static bpf_internal* fetch_ebpf(cs_struct *ud, const uint8_t *code, size_t code_len) { @@ -69,15 +78,139 @@ static bpf_internal* fetch_ebpf(cs_struct *ud, const uint8_t *code, return NULL; bpf->op = (uint16_t)code[0]; - bpf->dst = *(code + 1) & 0xf; - bpf->src = (*(code + 1) & 0xf0) >> 4; - bpf->offset = read_u16(ud, code + 2); - bpf->k = read_u32(ud, code + 4); + + // eBPF has one 16-byte instruction: BPF_LD | BPF_DW | BPF_IMM, + // in this case imm is fetched from the next 8-byte block. + if (bpf->op == (BPF_CLASS_LD | BPF_SIZE_DW | BPF_MODE_IMM)) { + if (code_len < 16) { + cs_mem_free(bpf); + return NULL; + } + bpf->k = read_u64(ud, code + 8); + bpf->insn_size = 16; + } + else { + bpf->dst = code[1] & 0xf; + bpf->src = (code[1] & 0xf0) >> 4; + bpf->offset = read_u16(ud, code + 2); + bpf->k = read_u32(ud, code + 4); + } return bpf; } -static bool getInstruction(cs_struct *ud, MCInst *MI, bpf_internal *bpf, - uint64_t address) +#define CHECK_READABLE_REG(ud, reg) do { \ + if (! ((reg) >= BPF_REG_R0 && (reg) <= BPF_REG_R10)) \ + return false; \ + } while (0) + +#define CHECK_WRITABLE_REG(ud, reg) do { \ + if (! ((reg) >= BPF_REG_R0 && (reg) < BPF_REG_R10)) \ + return false; \ + } while (0) + +static bool decodeLoad(cs_struct *ud, MCInst *MI, bpf_internal *bpf) +{ + return true; +} + +static bool decodeStore(cs_struct *ud, MCInst *MI, bpf_internal *bpf) +{ + return true; +} + +static bool decodeALU(cs_struct *ud, MCInst *MI, bpf_internal *bpf) +{ + /* + * +----------------+--------+--------------------+ + * | 4 bits | 1 bit | 3 bits | + * | operation code | source | instruction class | + * +----------------+--------+--------------------+ + * (MSB) (LSB) + */ + + if (!EBPF_MODE(ud)) { + if (BPF_OP(bpf->op) > BPF_ALU_XOR) + return false; + } + else { + if (BPF_OP(bpf->op) > BPF_ALU_END) + return false; + } + + /* NEG's source must be BPF_SRC_X */ + if (BPF_OP(bpf->op) == BPF_ALU_NEG && BPF_SRC(bpf->op) != BPF_SRC_X) + return false; + /* ALU64 class doesn't have ENDian */ + /* ENDian's imm must be one of 16, 32, 64 */ + if (BPF_OP(bpf->op) == BPF_ALU_END) { + if (BPF_CLASS(bpf->op) == BPF_CLASS_ALU64) + return false; + if (bpf->k != 16 && bpf->k != 32 && bpf->k != 64) + return false; + } + + /* Set MI->Operands */ + + /* cBPF */ + if (!EBPF_MODE(ud)) { + if (BPF_SRC(bpf->op) == BPF_SRC_K) + MCOperand_CreateImm0(MI, (int64_t)bpf->k); + else /* BPF_SRC_X */ + MCOperand_CreateReg0(MI, BPF_REG_X); + return true; + } + + /* eBPF */ + + /* - op dst, imm + * - op dst, src + * - neg dst + * - le dst + */ + /* every ALU instructions have dst op */ + CHECK_WRITABLE_REG(ud, bpf->dst + BPF_REG_R0); + MCOperand_CreateReg0(MI, bpf->dst + BPF_REG_R0); + + /* special cases */ + if (BPF_OP(bpf->op) == BPF_ALU_NEG) + return true; + if (BPF_OP(bpf->op) == BPF_ALU_END) { + /* ENDian instructions use BPF_SRC to decide using little or big endian */ + MCInst_setOpcode(MI, MCInst_getOpcode(MI) | (bpf->k << 4)); + return true; + } + + /* normal cases */ + if (BPF_SRC(bpf->op) == BPF_SRC_K) { + MCOperand_CreateImm0(MI, (int64_t)bpf->k); + } + else { /* BPF_SRC_X */ + CHECK_READABLE_REG(ud, bpf->src + BPF_REG_R0); + MCOperand_CreateReg0(MI, bpf->src + BPF_REG_R0); + } + return true; +} + +static bool decodeJump(cs_struct *ud, MCInst *MI, bpf_internal *bpf) +{ + return true; +} + +static bool decodeReturn(cs_struct *ud, MCInst *MI, bpf_internal *bpf) +{ + return true; +} + +static bool decodeMISC(cs_struct *ud, MCInst *MI, bpf_internal *bpf) +{ + uint16_t op = bpf->op ^ BPF_CLASS_MISC; + return op == BPF_MISCOP_TAX || op == BPF_MISCOP_TXA; +} + +///< 1. Check if the instruction is valid +///< 2. Set MI->opcode +///< 3. Set MI->Operands +static bool getInstruction(cs_struct *ud, MCInst *MI, bpf_internal *bpf) { cs_detail *detail; uint8_t opcode; @@ -91,108 +224,56 @@ static bool getInstruction(cs_struct *ud, MCInst *MI, bpf_internal *bpf, opcode = bpf->op; MCInst_clear(MI); - MI->address = address; - MCInst_setOpcodePub(MI, opcode); - -#ifndef CAPSTONE_DIET - #define PUSH_GROUP(grp) do { \ - detail->groups[detail->groups_count] = grp; \ - detail->groups_count++; \ - } while(0) -#else - #define PUSH_GROUP -#endif + MCInst_setOpcode(MI, opcode); - switch (BPF_CLASS(bpf->op)) { - default: // will never happen - break; + switch (BPF_CLASS(opcode)) { + default: /* should never happen */ + return false; case BPF_CLASS_LD: - if (detail) { - PUSH_GROUP(BPF_GRP_LOAD); - } - break; case BPF_CLASS_LDX: - if (detail) { - PUSH_GROUP(BPF_GRP_LOAD); - } - break; + return decodeLoad(ud, MI, bpf); case BPF_CLASS_ST: - if (detail) { - PUSH_GROUP(BPF_GRP_STORE); - } - break; case BPF_CLASS_STX: - if (detail) { - PUSH_GROUP(BPF_GRP_STORE); - } - break; + return decodeStore(ud, MI, bpf); case BPF_CLASS_ALU: - if (detail) { - PUSH_GROUP(BPF_GRP_ALU); - } - break; + return decodeALU(ud, MI, bpf); case BPF_CLASS_JMP: - if (detail) { - bpf_insn_group grp = BPF_GRP_JUMP; - - if (EBPF_MODE(ud)) { - // TODO: use BPF_INSN_CALL / BPF_INSN_RETURN_R0 on MI to check - if (opcode == 0x85) - grp = BPF_GRP_CALL; - else if (opcode == 0x95) - grp = BPF_GRP_RETURN; - } - PUSH_GROUP(grp); - } - break; + return decodeJump(ud, MI, bpf); case BPF_CLASS_RET: - // this class in eBPF is reserved. + /* eBPF doesn't have this class */ if (EBPF_MODE(ud)) return false; - if (detail) { - PUSH_GROUP(BPF_GRP_RETURN); - } - // BPF_CLASS_MISC and BPF_CLASS_ALU64 have exactly same value - case BPF_CLASS_MISC: - /* case BPF_CLASS_ALU64: */ - if (EBPF_MODE(ud)) { - } - else { - if (opcode & 0x80) - MCInst_setOpcode(MI, BPF_INS_TXA); - else - MCInst_setOpcode(MI, BPF_INS_TAX); - } - if (detail) { - if (EBPF_MODE(ud)) - PUSH_GROUP(BPF_GRP_ALU); // ALU64 in eBPF - else - PUSH_GROUP(BPF_GRP_MISC); - } + return decodeReturn(ud, MI, bpf); + /* case BPF_CLASS_MISC: */ + case BPF_CLASS_ALU64: + if (EBPF_MODE(ud)) + return decodeALU(ud, MI, bpf); + else + return decodeMISC(ud, MI, bpf); } -#undef PUSH_GROUP - return true; } bool BPF_getInstruction(csh ud, const uint8_t *code, size_t code_len, - MCInst *instr, uint16_t *size, uint64_t address, void *info) + MCInst *instr, uint16_t *size, uint64_t _address, void *info) { cs_struct *cs; bpf_internal *bpf; cs = (cs_struct*)ud; - if (cs->mode & CS_MODE_BPF_EXTENDED) + if (EBPF_MODE(cs)) bpf = fetch_ebpf(cs, code, code_len); else bpf = fetch_cbpf(cs, code, code_len); if (bpf == NULL) return false; - if (!getInstruction((cs_struct*)ud, instr, bpf, address)) + if (!getInstruction((cs_struct*)ud, instr, bpf)) { + cs_mem_free(bpf); return false; + } + *size = bpf->insn_size; cs_mem_free(bpf); - *size = 8; return true; } diff --git a/arch/BPF/BPFDisassembler.h b/arch/BPF/BPFDisassembler.h index 0c5c0163ef..9616b0816a 100644 --- a/arch/BPF/BPFDisassembler.h +++ b/arch/BPF/BPFDisassembler.h @@ -8,7 +8,7 @@ typedef struct bpf_internal { uint16_t op; - uint32_t k; + uint64_t k; /* for cBPF */ uint8_t jt; uint8_t jf; @@ -16,6 +16,9 @@ typedef struct bpf_internal { uint8_t dst; uint8_t src; uint16_t offset; + + /* length of this bpf instruction */ + uint8_t insn_size; } bpf_internal; bool BPF_getInstruction(csh ud, const uint8_t *code, size_t code_len, diff --git a/arch/BPF/BPFInstPrinter.c b/arch/BPF/BPFInstPrinter.c index a78ea65c36..9776c1a5fb 100644 --- a/arch/BPF/BPFInstPrinter.c +++ b/arch/BPF/BPFInstPrinter.c @@ -1,12 +1,24 @@ /* Capstone Disassembly Engine */ /* BPF Backend by david942j , 2019 */ +#include "BPFConstants.h" #include "BPFInstPrinter.h" #include "BPFMapping.h" +/* + * 1. human readable mnemonic + * 2. set pubOpcode (BPF_INSN_*) + * 3. set detail->bpf.operands + * */ void BPF_printInst(MCInst *MI, struct SStream *O, void *PrinterInfo) { int i; + cs_insn insn; - SStream_concat(O, BPF_insn_name((csh)MI->csh, MI->Opcode)); + /* set pubOpcode */ + insn.detail = NULL; + BPF_get_insn_id((cs_struct*)MI->csh, &insn, MCInst_getOpcode(MI)); + MCInst_setOpcodePub(MI, insn.id); + + SStream_concat(O, BPF_insn_name((csh)MI->csh, insn.id)); } diff --git a/arch/BPF/BPFMapping.c b/arch/BPF/BPFMapping.c index b226672588..006bdf1253 100644 --- a/arch/BPF/BPFMapping.c +++ b/arch/BPF/BPFMapping.c @@ -1,6 +1,7 @@ /* Capstone Disassembly Engine */ /* BPF Backend by david942j , 2019 */ +#include "BPFConstants.h" #include "BPFMapping.h" #include "../../utils.h" @@ -31,6 +32,41 @@ const char *BPF_group_name(csh handle, unsigned int id) static const name_map insn_name_maps[BPF_INS_ENDING] = { { BPF_INS_INVALID, NULL }, + { BPF_INS_ADD, "add" }, + { BPF_INS_SUB, "sub" }, + { BPF_INS_MUL, "mul" }, + { BPF_INS_DIV, "div" }, + { BPF_INS_OR, "or" }, + { BPF_INS_AND, "and" }, + { BPF_INS_LSH, "lsh" }, + { BPF_INS_RSH, "rsh" }, + { BPF_INS_NEG, "neg" }, + { BPF_INS_MOD, "mod" }, + { BPF_INS_XOR, "xor" }, + { BPF_INS_MOV, "mov" }, + { BPF_INS_ARSH, "arsh" }, + + { BPF_INS_ADD64, "add64" }, + { BPF_INS_SUB64, "sub64" }, + { BPF_INS_MUL64, "mul64" }, + { BPF_INS_DIV64, "div64" }, + { BPF_INS_OR64, "or64" }, + { BPF_INS_AND64, "and64" }, + { BPF_INS_LSH64, "lsh64" }, + { BPF_INS_RSH64, "rsh64" }, + { BPF_INS_NEG64, "neg64" }, + { BPF_INS_MOD64, "mod64" }, + { BPF_INS_XOR64, "xor64" }, + { BPF_INS_MOV64, "mov64" }, + { BPF_INS_ARSH64, "arsh64" }, + + { BPF_INS_LE16, "le16" }, + { BPF_INS_LE32, "le32" }, + { BPF_INS_LE64, "le64" }, + { BPF_INS_BE16, "be16" }, + { BPF_INS_BE32, "be32" }, + { BPF_INS_BE64, "be64" }, + { BPF_INS_LDABSB, "ldabsb" }, { BPF_INS_RET, "ret" }, @@ -74,7 +110,127 @@ const char *BPF_reg_name(csh handle, unsigned int reg) #endif } -void BPF_get_insn_id(cs_struct *h, cs_insn *insn, unsigned int id) +static bpf_insn op2insn_ALU(unsigned opcode) +{ + /* Endian is a special case */ + if (BPF_OP(opcode) == BPF_ALU_END) { + switch (opcode ^ BPF_CLASS_ALU ^ BPF_ALU_END) { + case BPF_SRC_LITTLE | (16 << 4): + return BPF_INS_LE16; + case BPF_SRC_LITTLE | (32 << 4): + return BPF_INS_LE32; + case BPF_SRC_LITTLE | (64 << 4): + return BPF_INS_LE64; + case BPF_SRC_BIG | (16 << 4): + return BPF_INS_BE16; + case BPF_SRC_BIG | (32 << 4): + return BPF_INS_BE32; + case BPF_SRC_BIG | (64 << 4): + return BPF_INS_BE64; + } + return BPF_INS_INVALID; + } + +#define CASE(c) case BPF_ALU_##c: \ + if (BPF_CLASS(opcode) == BPF_CLASS_ALU) \ + return BPF_INS_##c; \ + else \ + return BPF_INS_##c##64; + + switch (BPF_OP(opcode)) { + CASE(ADD); + CASE(SUB); + CASE(MUL); + CASE(DIV); + CASE(OR); + CASE(AND); + CASE(LSH); + CASE(RSH); + CASE(NEG); + CASE(MOD); + CASE(XOR); + CASE(MOV); + CASE(ARSH); + } +#undef CASE + + return BPF_INS_INVALID; +} + +/* + * 1. Convert opcode(id) to BPF_INS_* + * 2. Set regs_read/regs_write/groups + */ +void BPF_get_insn_id(cs_struct *ud, cs_insn *insn, unsigned int opcode) { + // No need to care the mode (cBPF or eBPF) since all checks has be done in + // BPF_getInstruction, we can simply map opcode to BPF_INS_*. + cs_detail *detail; + bpf_insn id = BPF_INS_INVALID; + bpf_insn_group grp; + + detail = insn->detail; +#ifndef CAPSTONE_DIET + #define PUSH_GROUP(grp) do { \ + if (detail) { \ + detail->groups[detail->groups_count] = grp; \ + detail->groups_count++; \ + } \ + } while(0) +#else + #define PUSH_GROUP +#endif + + switch (BPF_CLASS(opcode)) { + default: // will never happen + break; + case BPF_CLASS_LD: + PUSH_GROUP(BPF_GRP_LOAD); + break; + case BPF_CLASS_LDX: + PUSH_GROUP(BPF_GRP_LOAD); + break; + case BPF_CLASS_ST: + PUSH_GROUP(BPF_GRP_STORE); + break; + case BPF_CLASS_STX: + PUSH_GROUP(BPF_GRP_STORE); + break; + case BPF_CLASS_ALU: + id = op2insn_ALU(opcode); + PUSH_GROUP(BPF_GRP_ALU); + break; + case BPF_CLASS_JMP: + grp = BPF_GRP_JUMP; + if (EBPF_MODE(ud)) { + // TODO: use BPF_INSN_CALL / BPF_INSN_RETURN_R0 on MI to check + if (opcode == 0x85) + grp = BPF_GRP_CALL; + else if (opcode == 0x95) + grp = BPF_GRP_RETURN; + } + PUSH_GROUP(grp); + break; + case BPF_CLASS_RET: + PUSH_GROUP(BPF_GRP_RETURN); + break; + // BPF_CLASS_MISC and BPF_CLASS_ALU64 have exactly same value + case BPF_CLASS_MISC: + /* case BPF_CLASS_ALU64: */ + if (EBPF_MODE(ud)) { + // ALU64 in eBPF + id = op2insn_ALU(opcode); + PUSH_GROUP(BPF_GRP_ALU); + } + else { + if (opcode & 0x80) + id = BPF_INS_TXA; + else + id = BPF_INS_TAX; + PUSH_GROUP(BPF_GRP_MISC); + } + } + insn->id = id; +#undef PUSH_GROUP } diff --git a/tests/test_bpf.c b/tests/test_bpf.c index eb88a4231e..ce2756c7b4 100644 --- a/tests/test_bpf.c +++ b/tests/test_bpf.c @@ -56,7 +56,7 @@ static void print_insn_detail(csh cs_handle, cs_insn *ins) default: break; case BPF_OP_IMM: - printf("\t\toperands[%u].type: IMM = 0x%x\n", i, op->imm); + printf("\t\toperands[%u].type: IMM = 0x%lx\n", i, op->imm); break; } } @@ -64,8 +64,12 @@ static void print_insn_detail(csh cs_handle, cs_insn *ins) static void test() { -#define CBPF_CODE "\x87\x00\x00\x00\x00\x00\x00\x00\x07\x00\x00\x00\x00\x00\x00\x00" -#define EBPF_CODE "\x30\x00\x00\x00\x00\x00\x00\x00" +#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" +#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" struct platform platforms[] = { { CS_ARCH_BPF, From af47651a578e456f37089194c1c2f47f0cedfcbf Mon Sep 17 00:00:00 2001 From: david942j Date: Fri, 15 Feb 2019 01:09:28 -0800 Subject: [PATCH 07/35] decode return --- arch/ARM/ARMMapping.c | 1 + arch/BPF/BPFConstants.h | 3 +++ arch/BPF/BPFDisassembler.c | 19 ++++++++++++++++--- arch/BPF/BPFInstPrinter.c | 3 +++ arch/BPF/BPFMapping.c | 4 +++- tests/test_bpf.c | 16 +++++++++------- 6 files changed, 35 insertions(+), 11 deletions(-) diff --git a/arch/ARM/ARMMapping.c b/arch/ARM/ARMMapping.c index 5f065fcaa8..6043dfa08b 100644 --- a/arch/ARM/ARMMapping.c +++ b/arch/ARM/ARMMapping.c @@ -281,6 +281,7 @@ static const insn_map insns[] = { void ARM_get_insn_id(cs_struct *h, cs_insn *insn, unsigned int id) { int i = insn_find(insns, ARR_SIZE(insns), id, &h->insn_cache); + //printf(">> id = %u\n", id); if (i != 0) { insn->id = insns[i].mapid; diff --git a/arch/BPF/BPFConstants.h b/arch/BPF/BPFConstants.h index 69984f22b6..4511e0c6f2 100644 --- a/arch/BPF/BPFConstants.h +++ b/arch/BPF/BPFConstants.h @@ -54,9 +54,11 @@ #define BPF_JUMP_JSLE 0xd0 ///< eBPF only: signed '<=' #define BPF_SRC(code) ((code) & 0x08) +#define BPF_SRC_OLD(code) ((code) & 0x18) /* cBPF only */ ///< Source operand #define BPF_SRC_K 0x00 #define BPF_SRC_X 0x08 +#define BPF_SRC_A 0x10 /* cBPF only */ #define BPF_SRC_LITTLE BPF_SRC_K #define BPF_SRC_BIG BPF_SRC_X @@ -78,6 +80,7 @@ #define BPF_MODE_MSH 0xa0 ///< cBPF only, reserved in eBPF #define BPF_MODE_XADD 0xc0 ///< eBPF only: exclusive add +#define BPF_MISCOP(code) ((code) & 0x80) ///< Operation of misc #define BPF_MISCOP_TAX 0x00 #define BPF_MISCOP_TXA 0x80 diff --git a/arch/BPF/BPFDisassembler.c b/arch/BPF/BPFDisassembler.c index 71fa2b5af3..78a0de327e 100644 --- a/arch/BPF/BPFDisassembler.c +++ b/arch/BPF/BPFDisassembler.c @@ -198,7 +198,20 @@ static bool decodeJump(cs_struct *ud, MCInst *MI, bpf_internal *bpf) static bool decodeReturn(cs_struct *ud, MCInst *MI, bpf_internal *bpf) { - return true; + /* Here only handles the BPF_RET class in cBPF */ + switch (BPF_SRC_OLD(bpf->op)) { + default: + return false; + case BPF_SRC_K: + MCOperand_CreateImm0(MI, bpf->k); + return true; + case BPF_SRC_X: + MCOperand_CreateReg0(MI, BPF_REG_X); + return true; + case BPF_SRC_A: + MCOperand_CreateReg0(MI, BPF_REG_A); + return true; + } } static bool decodeMISC(cs_struct *ud, MCInst *MI, bpf_internal *bpf) @@ -244,8 +257,8 @@ static bool getInstruction(cs_struct *ud, MCInst *MI, bpf_internal *bpf) if (EBPF_MODE(ud)) return false; return decodeReturn(ud, MI, bpf); - /* case BPF_CLASS_MISC: */ - case BPF_CLASS_ALU64: + case BPF_CLASS_MISC: + /* case BPF_CLASS_ALU64: */ if (EBPF_MODE(ud)) return decodeALU(ud, MI, bpf); else diff --git a/arch/BPF/BPFInstPrinter.c b/arch/BPF/BPFInstPrinter.c index 9776c1a5fb..cccebbfdcf 100644 --- a/arch/BPF/BPFInstPrinter.c +++ b/arch/BPF/BPFInstPrinter.c @@ -21,4 +21,7 @@ void BPF_printInst(MCInst *MI, struct SStream *O, void *PrinterInfo) MCInst_setOpcodePub(MI, insn.id); SStream_concat(O, BPF_insn_name((csh)MI->csh, insn.id)); + if (MI->flat_insn->detail) { + MI->flat_insn->detail->bpf.op_count = MCInst_getNumOperands(MI); + } } diff --git a/arch/BPF/BPFMapping.c b/arch/BPF/BPFMapping.c index 006bdf1253..3e0ee8d727 100644 --- a/arch/BPF/BPFMapping.c +++ b/arch/BPF/BPFMapping.c @@ -70,6 +70,7 @@ static const name_map insn_name_maps[BPF_INS_ENDING] = { { BPF_INS_LDABSB, "ldabsb" }, { BPF_INS_RET, "ret" }, + { BPF_INS_TAX, "tax" }, { BPF_INS_TXA, "txa" }, }; @@ -212,6 +213,7 @@ void BPF_get_insn_id(cs_struct *ud, cs_insn *insn, unsigned int opcode) PUSH_GROUP(grp); break; case BPF_CLASS_RET: + id = BPF_INS_RET; PUSH_GROUP(BPF_GRP_RETURN); break; // BPF_CLASS_MISC and BPF_CLASS_ALU64 have exactly same value @@ -223,7 +225,7 @@ void BPF_get_insn_id(cs_struct *ud, cs_insn *insn, unsigned int opcode) PUSH_GROUP(BPF_GRP_ALU); } else { - if (opcode & 0x80) + if (BPF_MISCOP(opcode) == BPF_MISCOP_TXA) id = BPF_INS_TXA; else id = BPF_INS_TAX; diff --git a/tests/test_bpf.c b/tests/test_bpf.c index ce2756c7b4..85027de3c8 100644 --- a/tests/test_bpf.c +++ b/tests/test_bpf.c @@ -55,9 +55,9 @@ static void print_insn_detail(csh cs_handle, cs_insn *ins) switch (op->type) { default: break; - case BPF_OP_IMM: - printf("\t\toperands[%u].type: IMM = 0x%lx\n", i, op->imm); - break; + /* case BPF_OP_IMM: */ + /* printf("\t\toperands[%u].type: IMM = 0x%lx\n", i, op->imm); */ + /* break; */ } } } @@ -65,11 +65,13 @@ static void print_insn_detail(csh cs_handle, cs_insn *ins) 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" + "\x87\x00\x00\x00\x00\x00\x00\x00" \ + "\x07\x00\x00\x00\x00\x00\x00\x00" \ + "\x16\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" + "\xdc\x02\x00\x00\x20\x00\x00\x00" \ + "\x30\x00\x00\x00\x00\x00\x00\x00" struct platform platforms[] = { { CS_ARCH_BPF, From 9b7970aa9d252f67c812c3cbb6f1787b760fa611 Mon Sep 17 00:00:00 2001 From: david942j Date: Fri, 15 Feb 2019 02:28:31 -0800 Subject: [PATCH 08/35] Add suite/MC/BPF --- suite/MC/BPF/extended-be.cs | 2 ++ suite/MC/BPF/extended.cs | 2 ++ suite/cstest/include/capstone_test.h | 4 ++-- suite/cstest/include/factory.h | 1 + suite/cstest/include/helper.h | 2 ++ suite/cstest/src/bpf_detail.c | 16 ++++++++++++++++ suite/cstest/src/capstone_test.c | 11 ++++++++--- 7 files changed, 33 insertions(+), 5 deletions(-) create mode 100644 suite/MC/BPF/extended-be.cs create mode 100644 suite/MC/BPF/extended.cs create mode 100644 suite/cstest/src/bpf_detail.c diff --git a/suite/MC/BPF/extended-be.cs b/suite/MC/BPF/extended-be.cs new file mode 100644 index 0000000000..a93cdc5c37 --- /dev/null +++ b/suite/MC/BPF/extended-be.cs @@ -0,0 +1,2 @@ +# CS_ARCH_BPF, CS_MODE_BIG_ENDIAN+CS_MODE_BPF_EXTENDED, None +0x94,0x09,0x00,0x00,0x37,0x13,0x03,0x00 = mod r9, 0x37130300 diff --git a/suite/MC/BPF/extended.cs b/suite/MC/BPF/extended.cs new file mode 100644 index 0000000000..85ce8403d3 --- /dev/null +++ b/suite/MC/BPF/extended.cs @@ -0,0 +1,2 @@ +# CS_ARCH_BPF, CS_MODE_LITTLE_ENDIAN+CS_MODE_BPF_EXTENDED, None +0x94,0x09,0x00,0x00,0x37,0x13,0x03,0x00 = mod r9, 0x31337 diff --git a/suite/cstest/include/capstone_test.h b/suite/cstest/include/capstone_test.h index 1299190fbc..ae0eedce32 100644 --- a/suite/cstest/include/capstone_test.h +++ b/suite/cstest/include/capstone_test.h @@ -35,8 +35,8 @@ } \ } while (0) -#define NUMARCH 9 -#define NUMMODE 33 +#define NUMARCH 10 +#define NUMMODE 35 #define NUMOPTION 41 #define MAXMEM 1024 diff --git a/suite/cstest/include/factory.h b/suite/cstest/include/factory.h index 588fd73484..8ca6355821 100644 --- a/suite/cstest/include/factory.h +++ b/suite/cstest/include/factory.h @@ -21,5 +21,6 @@ char *get_detail_xcore(csh *handle, cs_mode mode, cs_insn *ins); char *get_detail_m68k(csh *handle, cs_mode mode, cs_insn *ins); char *get_detail_mos65xx(csh *handle, cs_mode mode, cs_insn *ins); char *get_detail_tms320c64x(csh *handle, cs_mode mode, cs_insn *ins); +char *get_detail_bpf(csh *handle, cs_mode mode, cs_insn *ins); #endif /* FACTORY_H */ diff --git a/suite/cstest/include/helper.h b/suite/cstest/include/helper.h index 1022303857..8ef092732f 100644 --- a/suite/cstest/include/helper.h +++ b/suite/cstest/include/helper.h @@ -17,6 +17,8 @@ #define X86_32 1 #define X86_64 2 +#define ARR_SIZE(a) (sizeof(a)/sizeof(a[0])) + char **split(char *str, char *delim, int *size); void print_strs(char **list_str, int size); void free_strs(char **list_str, int size); diff --git a/suite/cstest/src/bpf_detail.c b/suite/cstest/src/bpf_detail.c new file mode 100644 index 0000000000..41973664cc --- /dev/null +++ b/suite/cstest/src/bpf_detail.c @@ -0,0 +1,16 @@ +/* Capstone testing regression */ +/* By david942j , 2019 */ + +#include "factory.h" + +char *get_detail_bpf(csh *handle, cs_mode mode, cs_insn *ins) +{ + char *result; + + result = (char *)malloc(sizeof(char)); + result[0] = '\0'; + if (ins->detail == NULL) + return result; + + return result; +} diff --git a/suite/cstest/src/capstone_test.c b/suite/cstest/src/capstone_test.c index d966a12ab8..5a4645dfc6 100644 --- a/suite/cstest/src/capstone_test.c +++ b/suite/cstest/src/capstone_test.c @@ -13,7 +13,8 @@ single_dict arches[] = { {"CS_ARCH_SYSZ", CS_ARCH_SYSZ}, {"CS_ARCH_X86", CS_ARCH_X86}, {"CS_ARCH_XCORE", CS_ARCH_XCORE}, - {"CS_ARCH_M68K", CS_ARCH_M68K} + {"CS_ARCH_M68K", CS_ARCH_M68K}, + {"CS_ARCH_BPF", CS_ARCH_BPF}, }; single_dict modes[] = { @@ -49,7 +50,9 @@ single_dict modes[] = { {"CS_MODE_M680X_6809", CS_MODE_M680X_6809}, {"CS_MODE_M680X_6811", CS_MODE_M680X_6811}, {"CS_MODE_M680X_CPU12", CS_MODE_M680X_CPU12}, - {"CS_MODE_M680X_HCS08", CS_MODE_M680X_HCS08} + {"CS_MODE_M680X_HCS08", CS_MODE_M680X_HCS08}, + {"CS_MODE_BPF_CLASSIC", CS_MODE_BPF_CLASSIC}, + {"CS_MODE_BPF_EXTENDED", CS_MODE_BPF_EXTENDED}, }; double_dict options[] = { @@ -93,7 +96,7 @@ double_dict options[] = { {"CS_MODE_M680X_6811", CS_OPT_MODE, CS_MODE_M680X_6811}, {"CS_MODE_M680X_CPU12", CS_OPT_MODE, CS_MODE_M680X_CPU12}, {"CS_MODE_M680X_HCS08", CS_OPT_MODE, CS_MODE_M680X_HCS08}, - {"CS_OPT_UNSIGNED", CS_OPT_UNSIGNED, CS_OPT_ON} + {"CS_OPT_UNSIGNED", CS_OPT_UNSIGNED, CS_OPT_ON}, }; char *(*function)(csh *, cs_mode, cs_insn*) = NULL; @@ -265,6 +268,8 @@ int set_function(int arch) case CS_ARCH_TMS320C64X: function = get_detail_tms320c64x; break; + case CS_ARCH_BPF: + function = get_detail_bpf; default: return -1; } From fe683b4bead7a3fa426175682351f6b781c940c5 Mon Sep 17 00:00:00 2001 From: david942j Date: Fri, 15 Feb 2019 03:59:51 -0800 Subject: [PATCH 09/35] decode jump --- arch/BPF/BPFDisassembler.c | 63 ++++++++++++++++++++++++++++++++++---- arch/BPF/BPFMapping.c | 45 +++++++++++++++++++++++++-- include/capstone/bpf.h | 2 +- suite/MC/BPF/extended.cs | 4 +++ 4 files changed, 104 insertions(+), 10 deletions(-) diff --git a/arch/BPF/BPFDisassembler.c b/arch/BPF/BPFDisassembler.c index 78a0de327e..7380788905 100644 --- a/arch/BPF/BPFDisassembler.c +++ b/arch/BPF/BPFDisassembler.c @@ -108,6 +108,16 @@ static bpf_internal* fetch_ebpf(cs_struct *ud, const uint8_t *code, return false; \ } while (0) +#define CHECK_READABLE_AND_PUSH(ud, MI, r) do { \ + CHECK_READABLE_REG(ud, r + BPF_REG_R0); \ + MCOperand_CreateReg0(MI, r + BPF_REG_R0); \ + } while (0) + +#define CHECK_WRITABLE_AND_PUSH(ud, MI, r) do { \ + CHECK_WRITABLE_REG(ud, r + BPF_REG_R0); \ + MCOperand_CreateReg0(MI, r + BPF_REG_R0); \ + } while (0) + static bool decodeLoad(cs_struct *ud, MCInst *MI, bpf_internal *bpf) { return true; @@ -154,7 +164,7 @@ static bool decodeALU(cs_struct *ud, MCInst *MI, bpf_internal *bpf) /* cBPF */ if (!EBPF_MODE(ud)) { if (BPF_SRC(bpf->op) == BPF_SRC_K) - MCOperand_CreateImm0(MI, (int64_t)bpf->k); + MCOperand_CreateImm0(MI, bpf->k); else /* BPF_SRC_X */ MCOperand_CreateReg0(MI, BPF_REG_X); return true; @@ -168,8 +178,7 @@ static bool decodeALU(cs_struct *ud, MCInst *MI, bpf_internal *bpf) * - le dst */ /* every ALU instructions have dst op */ - CHECK_WRITABLE_REG(ud, bpf->dst + BPF_REG_R0); - MCOperand_CreateReg0(MI, bpf->dst + BPF_REG_R0); + CHECK_WRITABLE_AND_PUSH(ud, MI, bpf->dst); /* special cases */ if (BPF_OP(bpf->op) == BPF_ALU_NEG) @@ -182,17 +191,59 @@ static bool decodeALU(cs_struct *ud, MCInst *MI, bpf_internal *bpf) /* normal cases */ if (BPF_SRC(bpf->op) == BPF_SRC_K) { - MCOperand_CreateImm0(MI, (int64_t)bpf->k); + MCOperand_CreateImm0(MI, bpf->k); } else { /* BPF_SRC_X */ - CHECK_READABLE_REG(ud, bpf->src + BPF_REG_R0); - MCOperand_CreateReg0(MI, bpf->src + BPF_REG_R0); + CHECK_READABLE_AND_PUSH(ud, MI, bpf->src); } return true; } static bool decodeJump(cs_struct *ud, MCInst *MI, bpf_internal *bpf) { + /* cBPF and eBPF are very different in class jump */ + if (!EBPF_MODE(ud)) { + if (BPF_OP(bpf->op) > BPF_JUMP_JSET) + return false; + + if (BPF_SRC(bpf->op) == BPF_SRC_K) + MCOperand_CreateImm0(MI, bpf->k); + else /* BPF_SRC_X */ + MCOperand_CreateReg0(MI, BPF_REG_X); + MCOperand_CreateImm0(MI, bpf->jt); + MCOperand_CreateImm0(MI, bpf->jf); + } + else { + if (BPF_OP(bpf->op) > BPF_JUMP_JSLE) + return false; + + /* No operands for exit */ + if (BPF_OP(bpf->op) == BPF_JUMP_EXIT) { + return bpf->op == (BPF_CLASS_JMP | BPF_JUMP_EXIT); + } + if (BPF_OP(bpf->op) == BPF_JUMP_CALL) { + if (bpf->op != (BPF_CLASS_JMP | BPF_JUMP_CALL)) + return false; + MCOperand_CreateImm0(MI, bpf->k); + return true; + } + + /* ja is a special case of jumps */ + if (BPF_OP(bpf->op) == BPF_JUMP_JA) { + if (BPF_SRC(bpf->op) != BPF_SRC_K) + return false; + MCOperand_CreateImm0(MI, bpf->offset); + return true; + } + + /* dst, src, +off */ + CHECK_READABLE_AND_PUSH(ud, MI, bpf->dst); + if (BPF_SRC(bpf->op) == BPF_SRC_K) + MCOperand_CreateImm0(MI, bpf->k); + else + CHECK_READABLE_AND_PUSH(ud, MI, bpf->src); + MCOperand_CreateImm0(MI, bpf->offset); + } return true; } diff --git a/arch/BPF/BPFMapping.c b/arch/BPF/BPFMapping.c index 3e0ee8d727..a739811ae6 100644 --- a/arch/BPF/BPFMapping.c +++ b/arch/BPF/BPFMapping.c @@ -69,6 +69,21 @@ static const name_map insn_name_maps[BPF_INS_ENDING] = { { BPF_INS_LDABSB, "ldabsb" }, + { BPF_INS_JMP, "jmp" }, + { BPF_INS_JEQ, "jeq" }, + { BPF_INS_JGT, "jgt" }, + { BPF_INS_JGE, "jge" }, + { BPF_INS_JSET, "jset" }, + { BPF_INS_JNE, "jne" }, + { BPF_INS_JSGT, "jsgt" }, + { BPF_INS_JSGE, "jsge" }, + { BPF_INS_CALL, "call" }, + { BPF_INS_EXIT, "exit" }, + { BPF_INS_JLT, "jlt" }, + { BPF_INS_JLE, "jle" }, + { BPF_INS_JSLT, "jslt" }, + { BPF_INS_JSLE, "jsle" }, + { BPF_INS_RET, "ret" }, { BPF_INS_TAX, "tax" }, @@ -158,6 +173,30 @@ static bpf_insn op2insn_ALU(unsigned opcode) return BPF_INS_INVALID; } +static bpf_insn op2insn_JMP(unsigned opcode) +{ +#define CASE(c) case BPF_JUMP_##c: return BPF_INS_##c + switch (BPF_OP(opcode)) { + default: + return BPF_INS_INVALID; + case BPF_JUMP_JA: + return BPF_INS_JMP; + CASE(JEQ); + CASE(JGT); + CASE(JGE); + CASE(JSET); + CASE(JNE); + CASE(JSGT); + CASE(JSGE); + CASE(CALL); + CASE(EXIT); + CASE(JLT); + CASE(JLE); + CASE(JSLT); + CASE(JSLE); + } +} + /* * 1. Convert opcode(id) to BPF_INS_* * 2. Set regs_read/regs_write/groups @@ -203,11 +242,11 @@ void BPF_get_insn_id(cs_struct *ud, cs_insn *insn, unsigned int opcode) break; case BPF_CLASS_JMP: grp = BPF_GRP_JUMP; + id = op2insn_JMP(opcode); if (EBPF_MODE(ud)) { - // TODO: use BPF_INSN_CALL / BPF_INSN_RETURN_R0 on MI to check - if (opcode == 0x85) + if (id == BPF_INS_CALL) grp = BPF_GRP_CALL; - else if (opcode == 0x95) + else if (id == BPF_INS_EXIT) grp = BPF_GRP_RETURN; } PUSH_GROUP(grp); diff --git a/include/capstone/bpf.h b/include/capstone/bpf.h index c8921bf413..4f2af02fe1 100644 --- a/include/capstone/bpf.h +++ b/include/capstone/bpf.h @@ -138,7 +138,7 @@ typedef enum bpf_insn { BPF_INS_STXDW, ///< eBPF only ///< Jump - BPF_INS_JA, + BPF_INS_JMP, BPF_INS_JEQ, BPF_INS_JGT, BPF_INS_JGE, diff --git a/suite/MC/BPF/extended.cs b/suite/MC/BPF/extended.cs index 85ce8403d3..f4a7755deb 100644 --- a/suite/MC/BPF/extended.cs +++ b/suite/MC/BPF/extended.cs @@ -1,2 +1,6 @@ # CS_ARCH_BPF, CS_MODE_LITTLE_ENDIAN+CS_MODE_BPF_EXTENDED, None 0x94,0x09,0x00,0x00,0x37,0x13,0x03,0x00 = mod r9, 0x31337 +0xdc,0x02,0x00,0x00,0x20,0x00,0x00,0x00 = be32 r2 +0x30,0x00,0x00,0x00,0x00,0x00,0x00,0x00 = ldabsb 0x0 +0x05,0x00,0x00,0x00,0x08,0x00,0x00,0x00 = jmp +0x8 +0xdd,0x35,0x30,0x00,0x00,0x00,0x00,0x00 = jsle r5, r3, +0x30 From 1592c161dd5b40c29a3d5c4d6fefd0355884fa7b Mon Sep 17 00:00:00 2001 From: david942j Date: Fri, 15 Feb 2019 05:51:11 -0800 Subject: [PATCH 10/35] decode store --- arch/BPF/BPFConstants.h | 2 +- arch/BPF/BPFDisassembler.c | 60 ++++++++++++++++++++++++++++++++++++-- arch/BPF/BPFMapping.c | 58 +++++++++++++++++++++++++++++++++--- include/capstone/bpf.h | 16 ++++++---- suite/MC/BPF/classic.cs | 3 ++ suite/MC/BPF/extended.cs | 2 ++ 6 files changed, 128 insertions(+), 13 deletions(-) create mode 100644 suite/MC/BPF/classic.cs diff --git a/arch/BPF/BPFConstants.h b/arch/BPF/BPFConstants.h index 4511e0c6f2..d12590460c 100644 --- a/arch/BPF/BPFConstants.h +++ b/arch/BPF/BPFConstants.h @@ -54,7 +54,7 @@ #define BPF_JUMP_JSLE 0xd0 ///< eBPF only: signed '<=' #define BPF_SRC(code) ((code) & 0x08) -#define BPF_SRC_OLD(code) ((code) & 0x18) /* cBPF only */ +#define BPF_RVAL(code) ((code) & 0x18) /* cBPF only: for return types */ ///< Source operand #define BPF_SRC_K 0x00 #define BPF_SRC_X 0x08 diff --git a/arch/BPF/BPFDisassembler.c b/arch/BPF/BPFDisassembler.c index 7380788905..ede3f4375d 100644 --- a/arch/BPF/BPFDisassembler.c +++ b/arch/BPF/BPFDisassembler.c @@ -120,11 +120,67 @@ static bpf_internal* fetch_ebpf(cs_struct *ud, const uint8_t *code, static bool decodeLoad(cs_struct *ud, MCInst *MI, bpf_internal *bpf) { + /* + * +--------+--------+-------------------+ + * | 3 bits | 2 bits | 3 bits | + * | mode | size | instruction class | + * +--------+--------+-------------------+ + * (MSB) (LSB) + */ + if (!EBPF_MODE(ud) && BPF_SIZE(bpf->op) == BPF_SIZE_DW) + return false; + return true; } static bool decodeStore(cs_struct *ud, MCInst *MI, bpf_internal *bpf) { + /* + * +--------+--------+-------------------+ + * | 3 bits | 2 bits | 3 bits | + * | mode | size | instruction class | + * +--------+--------+-------------------+ + * (MSB) (LSB) + */ + + /* in cBPF, only BPF_ST* | BPF_MEM | BPF_W is valid + * while in eBPF: + * - BPF_STX | BPF_XADD | BPF_{W,DW} + * - BPF_ST* | BPF_MEM | BPF_{W,H,B,DW} + * are valid + */ + if (!EBPF_MODE(ud)) { + /* can only store to M[] */ + if (bpf->op != (BPF_CLASS(bpf->op) | BPF_MODE_MEM | BPF_SIZE_W)) + return false; + MCOperand_CreateImm0(MI, bpf->k); + return true; + } + + /* eBPF */ + + if (BPF_MODE(bpf->op) == BPF_MODE_XADD) { + if (BPF_CLASS(bpf->op) != BPF_CLASS_STX) + return false; + if (BPF_SIZE(bpf->op) != BPF_SIZE_W && BPF_SIZE(bpf->op) != BPF_SIZE_DW) + return false; + /* xadd [dst + off], src */ + CHECK_READABLE_AND_PUSH(ud, MI, bpf->dst); + MCOperand_CreateImm0(MI, bpf->offset); + CHECK_READABLE_AND_PUSH(ud, MI, bpf->src); + return true; + } + + if (BPF_MODE(bpf->op) != BPF_MODE_MEM) + return false; + + /* st [dst + off], src */ + CHECK_READABLE_AND_PUSH(ud, MI, bpf->dst); + MCOperand_CreateImm0(MI, bpf->offset); + if (BPF_CLASS(bpf->op) == BPF_CLASS_ST) + MCOperand_CreateImm0(MI, bpf->k); + else + CHECK_READABLE_AND_PUSH(ud, MI, bpf->src); return true; } @@ -132,7 +188,7 @@ static bool decodeALU(cs_struct *ud, MCInst *MI, bpf_internal *bpf) { /* * +----------------+--------+--------------------+ - * | 4 bits | 1 bit | 3 bits | + * | 4 bits | 1 bit | 3 bits | * | operation code | source | instruction class | * +----------------+--------+--------------------+ * (MSB) (LSB) @@ -250,7 +306,7 @@ static bool decodeJump(cs_struct *ud, MCInst *MI, bpf_internal *bpf) static bool decodeReturn(cs_struct *ud, MCInst *MI, bpf_internal *bpf) { /* Here only handles the BPF_RET class in cBPF */ - switch (BPF_SRC_OLD(bpf->op)) { + switch (BPF_RVAL(bpf->op)) { default: return false; case BPF_SRC_K: diff --git a/arch/BPF/BPFMapping.c b/arch/BPF/BPFMapping.c index a739811ae6..8f95a216b2 100644 --- a/arch/BPF/BPFMapping.c +++ b/arch/BPF/BPFMapping.c @@ -69,6 +69,17 @@ static const name_map insn_name_maps[BPF_INS_ENDING] = { { BPF_INS_LDABSB, "ldabsb" }, + { BPF_INS_STW, "stw" }, + { BPF_INS_STH, "sth" }, + { BPF_INS_STB, "stb" }, + { BPF_INS_STDW, "stdw" }, + { BPF_INS_STXW, "stxw" }, + { BPF_INS_STXH, "stxh" }, + { BPF_INS_STXB, "stxb" }, + { BPF_INS_STXDW, "stxdw" }, + { BPF_INS_XADDW, "xaddw" }, + { BPF_INS_XADDDW, "xadddw" }, + { BPF_INS_JMP, "jmp" }, { BPF_INS_JEQ, "jeq" }, { BPF_INS_JGT, "jgt" }, @@ -94,6 +105,13 @@ static const name_map insn_name_maps[BPF_INS_ENDING] = { const char *BPF_insn_name(csh handle, unsigned int id) { #ifndef CAPSTONE_DIET + /* handle some special cases in cBPF */ + if (!EBPF_MODE(handle)) { + switch (id) { + case BPF_INS_ST: return "st"; + case BPF_INS_STX: return "stx"; + } + } return id2name(insn_name_maps, ARR_SIZE(insn_name_maps), id); #else return NULL; @@ -116,9 +134,9 @@ const char *BPF_reg_name(csh handle, unsigned int reg) /* cBPF mode */ if (reg == BPF_REG_A) - return "A"; + return "a"; else if (reg == BPF_REG_X) - return "X"; + return "x"; else return NULL; #else @@ -173,12 +191,39 @@ static bpf_insn op2insn_ALU(unsigned opcode) return BPF_INS_INVALID; } +static bpf_insn op2insn_ST(unsigned opcode) +{ + /* + * - BPF_STX | BPF_XADD | BPF_{W,DW} + * - BPF_ST* | BPF_MEM | BPF_{W,H,B,DW} + */ + + if (opcode == (BPF_CLASS_STX | BPF_MODE_XADD | BPF_SIZE_W)) + return BPF_INS_XADDW; + if (opcode == (BPF_CLASS_STX | BPF_MODE_XADD | BPF_SIZE_DW)) + return BPF_INS_XADDDW; + + /* should be BPF_MEM */ +#define CASE(c) case BPF_SIZE_##c: \ + if (BPF_CLASS(opcode) == BPF_CLASS_ST) \ + return BPF_INS_ST##c; \ + else \ + return BPF_INS_STX##c; + switch (BPF_SIZE(opcode)) { + CASE(W); + CASE(H); + CASE(B); + CASE(DW); + } +#undef CASE + + return BPF_INS_INVALID; +} + static bpf_insn op2insn_JMP(unsigned opcode) { #define CASE(c) case BPF_JUMP_##c: return BPF_INS_##c switch (BPF_OP(opcode)) { - default: - return BPF_INS_INVALID; case BPF_JUMP_JA: return BPF_INS_JMP; CASE(JEQ); @@ -195,6 +240,9 @@ static bpf_insn op2insn_JMP(unsigned opcode) CASE(JSLT); CASE(JSLE); } +#undef CASE + + return BPF_INS_INVALID; } /* @@ -231,9 +279,11 @@ void BPF_get_insn_id(cs_struct *ud, cs_insn *insn, unsigned int opcode) PUSH_GROUP(BPF_GRP_LOAD); break; case BPF_CLASS_ST: + id = op2insn_ST(opcode); PUSH_GROUP(BPF_GRP_STORE); break; case BPF_CLASS_STX: + id = op2insn_ST(opcode); PUSH_GROUP(BPF_GRP_STORE); break; case BPF_CLASS_ALU: diff --git a/include/capstone/bpf.h b/include/capstone/bpf.h index 4f2af02fe1..2b45d77aa7 100644 --- a/include/capstone/bpf.h +++ b/include/capstone/bpf.h @@ -128,14 +128,18 @@ typedef enum bpf_insn { BPF_INS_LDXDW, ///< eBPF only ///< Store - BPF_INS_STW, - BPF_INS_STH, - BPF_INS_STB, + BPF_INS_STW, ///< eBPF only + BPF_INS_STH, ///< eBPF only + BPF_INS_STB, ///< eBPF only BPF_INS_STDW, ///< eBPF only - BPF_INS_STXW, - BPF_INS_STXH, - BPF_INS_STXB, + BPF_INS_STXW, ///< eBPF only + BPF_INS_STXH, ///< eBPF only + BPF_INS_STXB, ///< eBPF only BPF_INS_STXDW, ///< eBPF only + BPF_INS_XADDW, ///< eBPF only + BPF_INS_XADDDW, ///< eBPF only + BPF_INS_ST = BPF_INS_STW, ///< cBPF only + BPF_INS_STX = BPF_INS_STXW, ///< cBPF only ///< Jump BPF_INS_JMP, diff --git a/suite/MC/BPF/classic.cs b/suite/MC/BPF/classic.cs new file mode 100644 index 0000000000..ccfe3f1c0a --- /dev/null +++ b/suite/MC/BPF/classic.cs @@ -0,0 +1,3 @@ +# CS_ARCH_BPF, CS_MODE_LITTLE_ENDIAN+CS_MODE_BPF_CLASSIC, None +0x62,0x00,0x00,0x00,0x03,0x00,0x00,0x00 = st m[3] +0x63,0x00,0x00,0x00,0x0f,0x00,0x00,0x00 = stx m[15] diff --git a/suite/MC/BPF/extended.cs b/suite/MC/BPF/extended.cs index f4a7755deb..3f6522d306 100644 --- a/suite/MC/BPF/extended.cs +++ b/suite/MC/BPF/extended.cs @@ -4,3 +4,5 @@ 0x30,0x00,0x00,0x00,0x00,0x00,0x00,0x00 = ldabsb 0x0 0x05,0x00,0x00,0x00,0x08,0x00,0x00,0x00 = jmp +0x8 0xdd,0x35,0x30,0x00,0x00,0x00,0x00,0x00 = jsle r5, r3, +0x30 +0xc3,0x12,0x00,0x10,0x00,0x00,0x00,0x00 = xaddw [r2+0x1000], r1 +0xdb,0xa9,0x00,0x01,0x00,0x00,0x00,0x00 = xadddw [r9+0x100], r10 From 84d71224b56bb8d6c123cc7cc0cbde302c9c97e7 Mon Sep 17 00:00:00 2001 From: david942j Date: Fri, 15 Feb 2019 07:40:41 -0800 Subject: [PATCH 11/35] decode load --- arch/BPF/BPFDisassembler.c | 112 +++++++++++++++++++++++++++++++------ arch/BPF/BPFMapping.c | 98 ++++++++++++++++++++++---------- include/capstone/bpf.h | 28 +++++----- suite/MC/BPF/classic.cs | 10 +++- suite/MC/BPF/extended.cs | 5 +- 5 files changed, 187 insertions(+), 66 deletions(-) diff --git a/arch/BPF/BPFDisassembler.c b/arch/BPF/BPFDisassembler.c index ede3f4375d..2aab047b49 100644 --- a/arch/BPF/BPFDisassembler.c +++ b/arch/BPF/BPFDisassembler.c @@ -120,29 +120,108 @@ static bpf_internal* fetch_ebpf(cs_struct *ud, const uint8_t *code, static bool decodeLoad(cs_struct *ud, MCInst *MI, bpf_internal *bpf) { + if (!EBPF_MODE(ud)) { + /* + * +-----+-----------+--------------------+ + * | ldb | [k] | [x+k] | + * | ldh | [k] | [x+k] | + * +-----+----+------+------+-----+-------+ + */ + if (BPF_SIZE(bpf->op) == BPF_SIZE_DW) + return false; + if (BPF_SIZE(bpf->op) == BPF_SIZE_B || BPF_SIZE(bpf->op) == BPF_SIZE_H) { + /* no ldx */ + if (BPF_CLASS(bpf->op) != BPF_CLASS_LD) + return false; + /* can only be BPF_ABS and BPF_IND */ + if (BPF_MODE(bpf->op) == BPF_MODE_ABS) { + MCOperand_CreateImm0(MI, bpf->k); + return true; + } + else if (BPF_MODE(bpf->op) == BPF_MODE_IND) { + MCOperand_CreateReg0(MI, BPF_REG_X); + MCOperand_CreateImm0(MI, bpf->k); + return true; + } + return false; + } + /* + * +-----+----+------+------+-----+-------+ + * | ld | #k | #len | M[k] | [k] | [x+k] | + * +-----+----+------+------+-----+-------+ + * | ldx | #k | #len | M[k] | 4*([k]&0xf) | + * +-----+----+------+------+-------------+ + */ + switch (BPF_MODE(bpf->op)) { + default: + break; + case BPF_MODE_IMM: + MCOperand_CreateImm0(MI, bpf->k); + return true; + case BPF_MODE_LEN: + MCOperand_CreateImm0(MI, 0); // XXX(david942j) + return true; + case BPF_MODE_MEM: + MCOperand_CreateImm0(MI, bpf->k); + return true; + } + if (BPF_CLASS(bpf->op) == BPF_CLASS_LD) { + if (BPF_MODE(bpf->op) == BPF_MODE_ABS) { + MCOperand_CreateImm0(MI, bpf->k); + return true; + } + else if (BPF_MODE(bpf->op) == BPF_MODE_IND) { + MCOperand_CreateReg0(MI, BPF_REG_X); + MCOperand_CreateImm0(MI, bpf->k); + return true; + } + } + else { /* LDX */ + if (BPF_MODE(bpf->op) == BPF_MODE_MSH) { + MCOperand_CreateImm0(MI, bpf->k); + return true; + } + } + return false; + } + + /* eBPF mode */ /* - * +--------+--------+-------------------+ - * | 3 bits | 2 bits | 3 bits | - * | mode | size | instruction class | - * +--------+--------+-------------------+ - * (MSB) (LSB) + * - IMM: lddw imm64 + * - ABS: ld{w,h,b,dw} [k] + * - IND: ld{w,h,b,dw} [src+k] + * - MEM: ldx{w,h,b,dw} dst, [src+off] */ - if (!EBPF_MODE(ud) && BPF_SIZE(bpf->op) == BPF_SIZE_DW) + if (BPF_CLASS(bpf->op) == BPF_CLASS_LD) { + switch (BPF_MODE(bpf->op)) { + case BPF_MODE_IMM: + if (bpf->op != (BPF_CLASS_LD | BPF_SIZE_DW | BPF_MODE_IMM)) + return false; + MCOperand_CreateImm0(MI, bpf->k); + return true; + case BPF_MODE_ABS: + MCOperand_CreateImm0(MI, bpf->k); + return true; + case BPF_MODE_IND: + CHECK_READABLE_AND_PUSH(ud, MI, bpf->src); + MCOperand_CreateImm0(MI, bpf->k); + return true; + } return false; - return true; + } + /* LDX */ + if (BPF_MODE(bpf->op) == BPF_MODE_MEM) { + CHECK_WRITABLE_AND_PUSH(ud, MI, bpf->dst); + CHECK_READABLE_AND_PUSH(ud, MI, bpf->src); + MCOperand_CreateImm0(MI, bpf->offset); + return true; + } + return false; } static bool decodeStore(cs_struct *ud, MCInst *MI, bpf_internal *bpf) { - /* - * +--------+--------+-------------------+ - * | 3 bits | 2 bits | 3 bits | - * | mode | size | instruction class | - * +--------+--------+-------------------+ - * (MSB) (LSB) - */ - /* in cBPF, only BPF_ST* | BPF_MEM | BPF_W is valid * while in eBPF: * - BPF_STX | BPF_XADD | BPF_{W,DW} @@ -307,8 +386,6 @@ static bool decodeReturn(cs_struct *ud, MCInst *MI, bpf_internal *bpf) { /* Here only handles the BPF_RET class in cBPF */ switch (BPF_RVAL(bpf->op)) { - default: - return false; case BPF_SRC_K: MCOperand_CreateImm0(MI, bpf->k); return true; @@ -319,6 +396,7 @@ static bool decodeReturn(cs_struct *ud, MCInst *MI, bpf_internal *bpf) MCOperand_CreateReg0(MI, BPF_REG_A); return true; } + return false; } static bool decodeMISC(cs_struct *ud, MCInst *MI, bpf_internal *bpf) diff --git a/arch/BPF/BPFMapping.c b/arch/BPF/BPFMapping.c index 8f95a216b2..15a35d581b 100644 --- a/arch/BPF/BPFMapping.c +++ b/arch/BPF/BPFMapping.c @@ -67,7 +67,13 @@ static const name_map insn_name_maps[BPF_INS_ENDING] = { { BPF_INS_BE32, "be32" }, { BPF_INS_BE64, "be64" }, - { BPF_INS_LDABSB, "ldabsb" }, + { BPF_INS_LDW, "ldw" }, + { BPF_INS_LDH, "ldh" }, + { BPF_INS_LDB, "ldb" }, + { BPF_INS_LDDW, "lddw" }, + { BPF_INS_LDXW, "ldxw" }, + { BPF_INS_LDXH, "ldxh" }, + { BPF_INS_LDXB, "ldxb" }, { BPF_INS_STW, "stw" }, { BPF_INS_STH, "sth" }, @@ -105,9 +111,13 @@ static const name_map insn_name_maps[BPF_INS_ENDING] = { const char *BPF_insn_name(csh handle, unsigned int id) { #ifndef CAPSTONE_DIET - /* handle some special cases in cBPF */ + /* We have some special cases because 'ld' in cBPF is equivalent to 'ldw' + * in eBPF, and we don't want to see 'ldw' appears in cBPF mode. + */ if (!EBPF_MODE(handle)) { switch (id) { + case BPF_INS_LD: return "ld"; + case BPF_INS_LDX: return "ldx"; case BPF_INS_ST: return "st"; case BPF_INS_STX: return "stx"; } @@ -144,6 +154,59 @@ const char *BPF_reg_name(csh handle, unsigned int reg) #endif } +static bpf_insn op2insn_LD(unsigned opcode) +{ +#define CASE(c) case BPF_SIZE_##c: \ + if (BPF_CLASS(opcode) == BPF_CLASS_LD) \ + return BPF_INS_LD##c; \ + else \ + return BPF_INS_LDX##c; + + switch (BPF_SIZE(opcode)) { + case BPF_SIZE_DW: + /* ldxdw not exists */ + if (BPF_CLASS(opcode) == BPF_CLASS_LD) + return BPF_INS_LDDW; + else + break; + CASE(W); + CASE(H); + CASE(B); + } +#undef CASE + + return BPF_INS_INVALID; +} + +static bpf_insn op2insn_ST(unsigned opcode) +{ + /* + * - BPF_STX | BPF_XADD | BPF_{W,DW} + * - BPF_ST* | BPF_MEM | BPF_{W,H,B,DW} + */ + + if (opcode == (BPF_CLASS_STX | BPF_MODE_XADD | BPF_SIZE_W)) + return BPF_INS_XADDW; + if (opcode == (BPF_CLASS_STX | BPF_MODE_XADD | BPF_SIZE_DW)) + return BPF_INS_XADDDW; + + /* should be BPF_MEM */ +#define CASE(c) case BPF_SIZE_##c: \ + if (BPF_CLASS(opcode) == BPF_CLASS_ST) \ + return BPF_INS_ST##c; \ + else \ + return BPF_INS_STX##c; + switch (BPF_SIZE(opcode)) { + CASE(W); + CASE(H); + CASE(B); + CASE(DW); + } +#undef CASE + + return BPF_INS_INVALID; +} + static bpf_insn op2insn_ALU(unsigned opcode) { /* Endian is a special case */ @@ -191,35 +254,6 @@ static bpf_insn op2insn_ALU(unsigned opcode) return BPF_INS_INVALID; } -static bpf_insn op2insn_ST(unsigned opcode) -{ - /* - * - BPF_STX | BPF_XADD | BPF_{W,DW} - * - BPF_ST* | BPF_MEM | BPF_{W,H,B,DW} - */ - - if (opcode == (BPF_CLASS_STX | BPF_MODE_XADD | BPF_SIZE_W)) - return BPF_INS_XADDW; - if (opcode == (BPF_CLASS_STX | BPF_MODE_XADD | BPF_SIZE_DW)) - return BPF_INS_XADDDW; - - /* should be BPF_MEM */ -#define CASE(c) case BPF_SIZE_##c: \ - if (BPF_CLASS(opcode) == BPF_CLASS_ST) \ - return BPF_INS_ST##c; \ - else \ - return BPF_INS_STX##c; - switch (BPF_SIZE(opcode)) { - CASE(W); - CASE(H); - CASE(B); - CASE(DW); - } -#undef CASE - - return BPF_INS_INVALID; -} - static bpf_insn op2insn_JMP(unsigned opcode) { #define CASE(c) case BPF_JUMP_##c: return BPF_INS_##c @@ -273,9 +307,11 @@ void BPF_get_insn_id(cs_struct *ud, cs_insn *insn, unsigned int opcode) default: // will never happen break; case BPF_CLASS_LD: + id = op2insn_LD(opcode); PUSH_GROUP(BPF_GRP_LOAD); break; case BPF_CLASS_LDX: + id = op2insn_LD(opcode); PUSH_GROUP(BPF_GRP_LOAD); break; case BPF_CLASS_ST: diff --git a/include/capstone/bpf.h b/include/capstone/bpf.h index 2b45d77aa7..a62b3a56eb 100644 --- a/include/capstone/bpf.h +++ b/include/capstone/bpf.h @@ -113,19 +113,13 @@ typedef enum bpf_insn { BPF_INS_BE64, ///< Load - BPF_INS_LDDW, ///< eBPF only, load 64-bit imm - BPF_INS_LDABSW, - BPF_INS_LDABSH, - BPF_INS_LDABSB, - BPF_INS_LDABSDW, ///< eBPF only - BPF_INS_LDINDW, - BPF_INS_LDINDH, - BPF_INS_LDINDB, - BPF_INS_LDINDDW, ///< eBPF only - BPF_INS_LDXW, - BPF_INS_LDXH, - BPF_INS_LDXB, - BPF_INS_LDXDW, ///< eBPF only + BPF_INS_LDW, ///< eBPF only + BPF_INS_LDH, + BPF_INS_LDB, + BPF_INS_LDDW, ///< eBPF only: load 64-bit imm + BPF_INS_LDXW, ///< eBPF only + BPF_INS_LDXH, ///< eBPF only + BPF_INS_LDXB, ///< eBPF only ///< Store BPF_INS_STW, ///< eBPF only @@ -138,8 +132,6 @@ typedef enum bpf_insn { BPF_INS_STXDW, ///< eBPF only BPF_INS_XADDW, ///< eBPF only BPF_INS_XADDDW, ///< eBPF only - BPF_INS_ST = BPF_INS_STW, ///< cBPF only - BPF_INS_STX = BPF_INS_STXW, ///< cBPF only ///< Jump BPF_INS_JMP, @@ -165,6 +157,12 @@ typedef enum bpf_insn { BPF_INS_TXA, BPF_INS_ENDING, + + // alias instructions + BPF_INS_LD = BPF_INS_LDW, ///< cBPF only + BPF_INS_LDX = BPF_INS_LDXW, ///< cBPF only + BPF_INS_ST = BPF_INS_STW, ///< cBPF only + BPF_INS_STX = BPF_INS_STXW, ///< cBPF only } bpf_insn; /// Group of BPF instructions diff --git a/suite/MC/BPF/classic.cs b/suite/MC/BPF/classic.cs index ccfe3f1c0a..b710035059 100644 --- a/suite/MC/BPF/classic.cs +++ b/suite/MC/BPF/classic.cs @@ -1,3 +1,9 @@ # CS_ARCH_BPF, CS_MODE_LITTLE_ENDIAN+CS_MODE_BPF_CLASSIC, None -0x62,0x00,0x00,0x00,0x03,0x00,0x00,0x00 = st m[3] -0x63,0x00,0x00,0x00,0x0f,0x00,0x00,0x00 = stx m[15] +0x01,0x00,0x00,0x00,0x33,0x00,0x00,0x00 = ldx 0x33 +0x80,0x00,0x00,0x00,0x00,0x00,0x00,0x00 = ld #len +0xa1,0x00,0x00,0x00,0x10,0x00,0x00,0x00 = ldx 4*([0x10]&0xf) +0x60,0x00,0x00,0x00,0x09,0x00,0x00,0x00 = ld m[0x9] +0x30,0x00,0x00,0x00,0x37,0x13,0x03,0x00 = ldb [0x31337] +0x48,0x00,0x00,0x00,0x09,0x00,0x00,0x00 = ldh [x+0x9] +0x62,0x00,0x00,0x00,0x03,0x00,0x00,0x00 = st m[0x3] +0x63,0x00,0x00,0x00,0x0f,0x00,0x00,0x00 = stx m[0xf] diff --git a/suite/MC/BPF/extended.cs b/suite/MC/BPF/extended.cs index 3f6522d306..eae1ceb694 100644 --- a/suite/MC/BPF/extended.cs +++ b/suite/MC/BPF/extended.cs @@ -1,7 +1,10 @@ # CS_ARCH_BPF, CS_MODE_LITTLE_ENDIAN+CS_MODE_BPF_EXTENDED, None +0x28,0x00,0x00,0x00,0xfa,0x00,0x00,0xff = ldh [0xff0000fa] +0x40,0x10,0x00,0x00,0xcc,0x00,0x00,0x00 = ldw [r1+0xcc] +0x18,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0c,0xb0,0xce,0xfa,0xef,0xbe,0xad,0xde = lddw 0xdeadbeeffaceb00c +0x71,0x13,0x11,0x00,0x00,0x00,0x00,0x00 = ldxb r3, [r1+0x11] 0x94,0x09,0x00,0x00,0x37,0x13,0x03,0x00 = mod r9, 0x31337 0xdc,0x02,0x00,0x00,0x20,0x00,0x00,0x00 = be32 r2 -0x30,0x00,0x00,0x00,0x00,0x00,0x00,0x00 = ldabsb 0x0 0x05,0x00,0x00,0x00,0x08,0x00,0x00,0x00 = jmp +0x8 0xdd,0x35,0x30,0x00,0x00,0x00,0x00,0x00 = jsle r5, r3, +0x30 0xc3,0x12,0x00,0x10,0x00,0x00,0x00,0x00 = xaddw [r2+0x1000], r1 From 5041285ead4110bb3d429b2578fb535ff5ee31e5 Mon Sep 17 00:00:00 2001 From: david942j Date: Fri, 15 Feb 2019 09:21:37 -0800 Subject: [PATCH 12/35] print instruction done --- CMakeLists.txt | 1 - arch/BPF/BPFDisassembler.c | 1 - arch/BPF/BPFInstPrinter.c | 188 ++++++++++++++++++++++++++++++++++++- include/capstone/bpf.h | 13 ++- suite/MC/BPF/extended.cs | 2 +- 5 files changed, 199 insertions(+), 6 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 7dc626a0f5..49a1cf9947 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -476,7 +476,6 @@ if (NOT CAPSTONE_X86_ONLY AND CAPSTONE_MOS65XX_SUPPORT) set(TEST_SOURCES ${TEST_SOURCES} test_mos65xx.c) endif () -# TODO(david942j): check if all sources and headers are included if (NOT CAPSTONE_X86_ONLY AND CAPSTONE_BPF_SUPPORT) add_definitions(-DCAPSTONE_HAS_BPF) set(SOURCES_BPF diff --git a/arch/BPF/BPFDisassembler.c b/arch/BPF/BPFDisassembler.c index 2aab047b49..1f1b85b54d 100644 --- a/arch/BPF/BPFDisassembler.c +++ b/arch/BPF/BPFDisassembler.c @@ -159,7 +159,6 @@ static bool decodeLoad(cs_struct *ud, MCInst *MI, bpf_internal *bpf) MCOperand_CreateImm0(MI, bpf->k); return true; case BPF_MODE_LEN: - MCOperand_CreateImm0(MI, 0); // XXX(david942j) return true; case BPF_MODE_MEM: MCOperand_CreateImm0(MI, bpf->k); diff --git a/arch/BPF/BPFInstPrinter.c b/arch/BPF/BPFInstPrinter.c index cccebbfdcf..414f036a66 100644 --- a/arch/BPF/BPFInstPrinter.c +++ b/arch/BPF/BPFInstPrinter.c @@ -5,6 +5,179 @@ #include "BPFInstPrinter.h" #include "BPFMapping.h" +static cs_bpf_op *expand_bpf_operands(cs_bpf *bpf) +{ + bpf->op_count++; + bpf->operands = cs_mem_realloc(bpf->operands, bpf->op_count * sizeof(cs_bpf_op)); + return &bpf->operands[bpf->op_count - 1]; +} + +static void push_bpf_imm(cs_bpf *bpf, uint64_t val) { + cs_bpf_op *op = expand_bpf_operands(bpf); + + op->type = BPF_OP_IMM; + op->imm = val; +} + +static void push_bpf_reg(cs_bpf *bpf, unsigned val) { + cs_bpf_op *op = expand_bpf_operands(bpf); + + op->type = BPF_OP_REG; + op->reg = val; +} + +static void push_bpf_mem(cs_bpf *bpf, bpf_reg reg, uint64_t val) { + cs_bpf_op *op = expand_bpf_operands(bpf); + + op->type = BPF_OP_MEM; + op->mem.base = reg; + op->mem.disp = val; +} + +static void push_bpf_mmem(cs_bpf *bpf, uint64_t val) { + cs_bpf_op *op = expand_bpf_operands(bpf); + + op->type = BPF_OP_MMEM; + op->imm = val; +} + +static void push_bpf_msh(cs_bpf *bpf, uint64_t val) { + cs_bpf_op *op = expand_bpf_operands(bpf); + + op->type = BPF_OP_MSH; + op->imm = val; +} + +static void push_bpf_ext(cs_bpf *bpf, bpf_ext_type val) { + cs_bpf_op *op = expand_bpf_operands(bpf); + + op->type = BPF_OP_EXT; + op->imm = val; +} + +static void BPF_convertOperands(MCInst *MI, cs_bpf *bpf) +{ + unsigned opcode = MCInst_getOpcode(MI); + unsigned mc_op_count = MCInst_getNumOperands(MI); + MCOperand *op; + MCOperand *op2; + unsigned i; + + bpf->op_count = 0; + bpf->operands = NULL; + /* so sad cBPF and eBPF are very different in these case.. */ + if (BPF_CLASS(opcode) == BPF_CLASS_LD || BPF_CLASS(opcode) == BPF_CLASS_LDX) { + switch (BPF_MODE(opcode)) { + case BPF_MODE_IMM: + push_bpf_imm(bpf, (uint64_t)MCOperand_getImm(MCInst_getOperand(MI, 0))); + break; + case BPF_MODE_ABS: + op = MCInst_getOperand(MI, 0); + push_bpf_mem(bpf, BPF_REG_INVALID, (uint64_t)MCOperand_getImm(op)); + break; + case BPF_MODE_IND: + op = MCInst_getOperand(MI, 0); + op2 = MCInst_getOperand(MI, 1); + push_bpf_mem(bpf, MCOperand_getReg(op), (uint64_t)MCOperand_getImm(op2)); + break; + case BPF_MODE_MEM: + if (EBPF_MODE(MI->csh)) { + /* ldx{w,h,b,dw} dst, [src+off] */ + push_bpf_reg(bpf, MCOperand_getReg(MCInst_getOperand(MI, 0))); + op = MCInst_getOperand(MI, 1); + op2 = MCInst_getOperand(MI, 2); + push_bpf_mem(bpf, MCOperand_getReg(op), (uint64_t)MCOperand_getImm(op2)); + } + else { + push_bpf_mmem(bpf, (uint64_t)MCOperand_getImm(MCInst_getOperand(MI, 0))); + } + break; + case BPF_MODE_LEN: + push_bpf_ext(bpf, BPF_EXT_LEN); + break; + case BPF_MODE_MSH: + op = MCInst_getOperand(MI, 0); + push_bpf_msh(bpf, (uint64_t)MCOperand_getImm(op)); + break; + /* case BPF_MODE_XADD: // not exists */ + } + return; + } + if (BPF_CLASS(opcode) == BPF_CLASS_ST || BPF_CLASS(opcode) == BPF_CLASS_STX) { + if (!EBPF_MODE(MI->csh)) { + // cBPF has only one case - st* M[k] + push_bpf_mmem(bpf, (uint64_t)MCOperand_getImm(MCInst_getOperand(MI, 0))); + return; + } + /* eBPF has two cases: + * - st [dst + off], src + * - xadd [dst + off], src + */ + op = MCInst_getOperand(MI, 0); + op2 = MCInst_getOperand(MI, 1); + push_bpf_mem(bpf, MCOperand_getReg(op), (uint64_t)MCOperand_getImm(op2)); + op = MCInst_getOperand(MI, 2); + if (MCOperand_isImm(op)) + push_bpf_imm(bpf, (uint64_t)MCOperand_getImm(op)); + else if (MCOperand_isReg(op)) + push_bpf_reg(bpf, MCOperand_getReg(op)); + return; + } + /* convert 1-to-1 */ + for (i = 0; i < mc_op_count; i++) { + op = MCInst_getOperand(MI, i); + if (MCOperand_isImm(op)) + push_bpf_imm(bpf, (uint64_t)MCOperand_getImm(op)); + else if (MCOperand_isReg(op)) + push_bpf_reg(bpf, MCOperand_getReg(op)); + } +} + +static void BPF_printOperand(MCInst *MI, struct SStream *O, const cs_bpf_op *op) +{ + char buf[32]; + unsigned opcode = MCInst_getOpcode(MI); + + if (op->type == BPF_OP_IMM) { + if (BPF_CLASS(opcode) == BPF_CLASS_JMP) + SStream_concat(O, "+"); + sprintf(buf, "0x%lx", op->imm); + SStream_concat(O, buf); + } + else if (op->type == BPF_OP_REG) { + SStream_concat(O, BPF_reg_name((csh)MI->csh, op->reg)); + } + else if (op->type == BPF_OP_MEM) { + SStream_concat(O, "["); + if (op->mem.base != BPF_REG_INVALID) + SStream_concat(O, BPF_reg_name((csh)MI->csh, op->mem.base)); + if (op->mem.disp != 0) { + if (op->mem.base != BPF_REG_INVALID) + SStream_concat(O, "+"); + sprintf(buf, "%#x", op->mem.disp); + SStream_concat(O, buf); + } + SStream_concat(O, "]"); + } + else if (op->type == BPF_OP_MMEM) { + SStream_concat(O, "m["); + sprintf(buf, "0x%lx", op->imm); + SStream_concat(O, buf); + SStream_concat(O, "]"); + } + else if (op->type == BPF_OP_MSH) { + sprintf(buf, "4*([0x%lx]&0xf)", op->imm); + SStream_concat(O, buf); + } + else if (op->type == BPF_OP_EXT) { + switch (op->imm) { + case BPF_EXT_LEN: + SStream_concat(O, "#len"); + break; + } + } +} + /* * 1. human readable mnemonic * 2. set pubOpcode (BPF_INSN_*) @@ -14,6 +187,7 @@ void BPF_printInst(MCInst *MI, struct SStream *O, void *PrinterInfo) { int i; cs_insn insn; + cs_bpf bpf; /* set pubOpcode */ insn.detail = NULL; @@ -21,7 +195,19 @@ void BPF_printInst(MCInst *MI, struct SStream *O, void *PrinterInfo) MCInst_setOpcodePub(MI, insn.id); SStream_concat(O, BPF_insn_name((csh)MI->csh, insn.id)); + BPF_convertOperands(MI, &bpf); + for (i = 0; i < bpf.op_count; i++) { + if (i == 0) + SStream_concat(O, "\t"); + else + SStream_concat(O, ", "); + BPF_printOperand(MI, O, &bpf.operands[i]); + } + +#ifndef CAPSTONE_DIET if (MI->flat_insn->detail) { - MI->flat_insn->detail->bpf.op_count = MCInst_getNumOperands(MI); + /* MI->flat_insn->detail->bpf.op_count = MCInst_getNumOperands(MI); */ + MI->flat_insn->detail->bpf = bpf; } +#endif } diff --git a/include/capstone/bpf.h b/include/capstone/bpf.h index a62b3a56eb..a642c57d45 100644 --- a/include/capstone/bpf.h +++ b/include/capstone/bpf.h @@ -20,7 +20,10 @@ typedef enum bpf_op_type { BPF_OP_REG, BPF_OP_IMM, - BPF_OP_MEM + BPF_OP_MEM, + BPF_OP_MMEM, ///< M[k] in cBPF + BPF_OP_MSH, ///< corresponds to cBPF's BPF_MSH mode + BPF_OP_EXT, ///< cBPF's extension (not eBPF) } bpf_op_type; /// BPF registers @@ -51,9 +54,15 @@ typedef enum bpf_reg { /// This is associated with BPF_OP_MEM operand type above typedef struct bpf_op_mem { bpf_reg base; ///< base register - int32_t disp; ///< offset value + uint32_t disp; ///< offset value } bpf_op_mem; +typedef enum bpf_ext_type { + BPF_EXT_INVALID = 0, + + BPF_EXT_LEN, +} bpf_ext_type; + /// Instruction operand typedef struct cs_bpf_op { bpf_op_type type; diff --git a/suite/MC/BPF/extended.cs b/suite/MC/BPF/extended.cs index eae1ceb694..ffc1583b34 100644 --- a/suite/MC/BPF/extended.cs +++ b/suite/MC/BPF/extended.cs @@ -5,7 +5,7 @@ 0x71,0x13,0x11,0x00,0x00,0x00,0x00,0x00 = ldxb r3, [r1+0x11] 0x94,0x09,0x00,0x00,0x37,0x13,0x03,0x00 = mod r9, 0x31337 0xdc,0x02,0x00,0x00,0x20,0x00,0x00,0x00 = be32 r2 -0x05,0x00,0x00,0x00,0x08,0x00,0x00,0x00 = jmp +0x8 +0x05,0x00,0x08,0x00,0x00,0x00,0x00,0x00 = jmp +0x8 0xdd,0x35,0x30,0x00,0x00,0x00,0x00,0x00 = jsle r5, r3, +0x30 0xc3,0x12,0x00,0x10,0x00,0x00,0x00,0x00 = xaddw [r2+0x1000], r1 0xdb,0xa9,0x00,0x01,0x00,0x00,0x00,0x00 = xadddw [r9+0x100], r10 From ef0732d99ed74dc8753cafc4730feacec56196ed Mon Sep 17 00:00:00 2001 From: david942j Date: Fri, 15 Feb 2019 10:25:10 -0800 Subject: [PATCH 13/35] try to implement BPF_reg_access --- arch/BPF/BPFDisassembler.c | 6 ++--- arch/BPF/BPFInstPrinter.c | 22 ++++++++++++------ arch/BPF/BPFMapping.c | 46 +++++++++++++++++++++++++++++++++++++ arch/BPF/BPFMapping.h | 3 +++ arch/BPF/BPFModule.c | 4 +--- include/capstone/bpf.h | 5 ++++ include/capstone/capstone.h | 2 +- suite/MC/BPF/classic.cs | 1 + suite/MC/BPF/extended.cs | 3 +++ tests/test_bpf.c | 41 +++++++++++++++++++++++++++++---- 10 files changed, 114 insertions(+), 19 deletions(-) diff --git a/arch/BPF/BPFDisassembler.c b/arch/BPF/BPFDisassembler.c index 1f1b85b54d..d30d796bb0 100644 --- a/arch/BPF/BPFDisassembler.c +++ b/arch/BPF/BPFDisassembler.c @@ -281,9 +281,6 @@ static bool decodeALU(cs_struct *ud, MCInst *MI, bpf_internal *bpf) return false; } - /* NEG's source must be BPF_SRC_X */ - if (BPF_OP(bpf->op) == BPF_ALU_NEG && BPF_SRC(bpf->op) != BPF_SRC_X) - return false; /* ALU64 class doesn't have ENDian */ /* ENDian's imm must be one of 16, 32, 64 */ if (BPF_OP(bpf->op) == BPF_ALU_END) { @@ -297,6 +294,9 @@ static bool decodeALU(cs_struct *ud, MCInst *MI, bpf_internal *bpf) /* cBPF */ if (!EBPF_MODE(ud)) { + /* cBPF's NEG has no operands */ + if (BPF_OP(bpf->op) == BPF_ALU_NEG) + return true; if (BPF_SRC(bpf->op) == BPF_SRC_K) MCOperand_CreateImm0(MI, bpf->k); else /* BPF_SRC_X */ diff --git a/arch/BPF/BPFInstPrinter.c b/arch/BPF/BPFInstPrinter.c index 414f036a66..08e3974aee 100644 --- a/arch/BPF/BPFInstPrinter.c +++ b/arch/BPF/BPFInstPrinter.c @@ -19,11 +19,12 @@ static void push_bpf_imm(cs_bpf *bpf, uint64_t val) { op->imm = val; } -static void push_bpf_reg(cs_bpf *bpf, unsigned val) { +static void push_bpf_reg(cs_bpf *bpf, unsigned val, uint8_t ac_mode) { cs_bpf_op *op = expand_bpf_operands(bpf); op->type = BPF_OP_REG; op->reg = val; + op->access = ac_mode; } static void push_bpf_mem(cs_bpf *bpf, bpf_reg reg, uint64_t val) { @@ -83,7 +84,7 @@ static void BPF_convertOperands(MCInst *MI, cs_bpf *bpf) case BPF_MODE_MEM: if (EBPF_MODE(MI->csh)) { /* ldx{w,h,b,dw} dst, [src+off] */ - push_bpf_reg(bpf, MCOperand_getReg(MCInst_getOperand(MI, 0))); + push_bpf_reg(bpf, MCOperand_getReg(MCInst_getOperand(MI, 0)), CS_AC_WRITE); op = MCInst_getOperand(MI, 1); op2 = MCInst_getOperand(MI, 2); push_bpf_mem(bpf, MCOperand_getReg(op), (uint64_t)MCOperand_getImm(op2)); @@ -112,6 +113,7 @@ static void BPF_convertOperands(MCInst *MI, cs_bpf *bpf) /* eBPF has two cases: * - st [dst + off], src * - xadd [dst + off], src + * they have same form of operands. */ op = MCInst_getOperand(MI, 0); op2 = MCInst_getOperand(MI, 1); @@ -120,16 +122,21 @@ static void BPF_convertOperands(MCInst *MI, cs_bpf *bpf) if (MCOperand_isImm(op)) push_bpf_imm(bpf, (uint64_t)MCOperand_getImm(op)); else if (MCOperand_isReg(op)) - push_bpf_reg(bpf, MCOperand_getReg(op)); + push_bpf_reg(bpf, MCOperand_getReg(op), CS_AC_READ); return; } /* convert 1-to-1 */ for (i = 0; i < mc_op_count; i++) { op = MCInst_getOperand(MI, i); - if (MCOperand_isImm(op)) + if (MCOperand_isImm(op)) { push_bpf_imm(bpf, (uint64_t)MCOperand_getImm(op)); - else if (MCOperand_isReg(op)) - push_bpf_reg(bpf, MCOperand_getReg(op)); + } + else if (MCOperand_isReg(op)) { + // TODO(david942j): decide this register is read and/or written. + uint8_t ac = 0; + + push_bpf_reg(bpf, MCOperand_getReg(op), ac); + } } } @@ -157,6 +164,8 @@ static void BPF_printOperand(MCInst *MI, struct SStream *O, const cs_bpf_op *op) sprintf(buf, "%#x", op->mem.disp); SStream_concat(O, buf); } + if (op->mem.base == BPF_REG_INVALID && op->mem.disp == 0) // special case + SStream_concat(O, "0x0"); SStream_concat(O, "]"); } else if (op->type == BPF_OP_MMEM) { @@ -206,7 +215,6 @@ void BPF_printInst(MCInst *MI, struct SStream *O, void *PrinterInfo) #ifndef CAPSTONE_DIET if (MI->flat_insn->detail) { - /* MI->flat_insn->detail->bpf.op_count = MCInst_getNumOperands(MI); */ MI->flat_insn->detail->bpf = bpf; } #endif diff --git a/arch/BPF/BPFMapping.c b/arch/BPF/BPFMapping.c index 15a35d581b..821ecae505 100644 --- a/arch/BPF/BPFMapping.c +++ b/arch/BPF/BPFMapping.c @@ -1,6 +1,8 @@ /* Capstone Disassembly Engine */ /* BPF Backend by david942j , 2019 */ +#include + #include "BPFConstants.h" #include "BPFMapping.h" #include "../../utils.h" @@ -361,3 +363,47 @@ void BPF_get_insn_id(cs_struct *ud, cs_insn *insn, unsigned int opcode) insn->id = id; #undef PUSH_GROUP } + +void BPF_reg_access(const cs_insn *insn, + cs_regs regs_read, uint8_t *regs_read_count, + cs_regs regs_write, uint8_t *regs_write_count) +{ + //... I need bpf mode..? + unsigned i; + uint8_t read_count, write_count; + cs_bpf *bpf = &(insn->detail->bpf); + + read_count = insn->detail->regs_read_count; + write_count = insn->detail->regs_write_count; + + // implicit registers + memcpy(regs_read, insn->detail->regs_read, read_count * sizeof(insn->detail->regs_read[0])); + memcpy(regs_write, insn->detail->regs_write, write_count * sizeof(insn->detail->regs_write[0])); + + for (i = 0; i < bpf->op_count; i++) { + cs_bpf_op *op = &(bpf->operands[i]); + switch (op->type) { + default: + break; + case BPF_OP_REG: + if (op->access & CS_AC_READ) { + regs_read[read_count] = (uint16_t)op->mem.base; + read_count++; + } + if (op->access & CS_AC_WRITE) { + regs_write[write_count] = (uint16_t)op->mem.base; + write_count++; + } + break; + case BPF_OP_MEM: + if (op->mem.base != BPF_REG_INVALID) { + regs_read[read_count] = (uint16_t)op->mem.base; + read_count++; + } + break; + } + } + + *regs_read_count = read_count; + *regs_write_count = write_count; +} diff --git a/arch/BPF/BPFMapping.h b/arch/BPF/BPFMapping.h index 828f2270ef..1401ee8655 100644 --- a/arch/BPF/BPFMapping.h +++ b/arch/BPF/BPFMapping.h @@ -14,5 +14,8 @@ const char *BPF_group_name(csh handle, unsigned int id); const char *BPF_insn_name(csh handle, unsigned int id); const char *BPF_reg_name(csh handle, unsigned int reg); void BPF_get_insn_id(cs_struct *h, cs_insn *insn, unsigned int id); +void BPF_reg_access(const cs_insn *insn, + cs_regs regs_read, uint8_t *regs_read_count, + cs_regs regs_write, uint8_t *regs_write_count); #endif diff --git a/arch/BPF/BPFModule.c b/arch/BPF/BPFModule.c index f6d56bb51c..9ad9461585 100644 --- a/arch/BPF/BPFModule.c +++ b/arch/BPF/BPFModule.c @@ -11,14 +11,12 @@ cs_err BPF_global_init(cs_struct *ud) { ud->printer = BPF_printInst; - ud->printer_info = NULL; ud->reg_name = BPF_reg_name; ud->insn_id = BPF_get_insn_id; ud->insn_name = BPF_insn_name; ud->group_name = BPF_group_name; - /* ud->post_printer = BPF_post_printer; */ #ifndef CAPSTONE_DIET - /* ud->reg_access = BPF_reg_access; */ + ud->reg_access = BPF_reg_access; #endif ud->disasm = BPF_getInstruction; diff --git a/include/capstone/bpf.h b/include/capstone/bpf.h index a642c57d45..eb6fd294b7 100644 --- a/include/capstone/bpf.h +++ b/include/capstone/bpf.h @@ -71,6 +71,11 @@ typedef struct cs_bpf_op { uint64_t imm; ///< immediate value IMM operand bpf_op_mem mem; ///< base/index/scale/disp value for MEM operand }; + + /// How is this operand accessed? (READ, WRITE or READ|WRITE) + /// This field is combined of cs_ac_type. + /// NOTE: this field is irrelevant if engine is compiled in DIET mode. + uint8_t access; } cs_bpf_op; /// Instruction structure diff --git a/include/capstone/capstone.h b/include/capstone/capstone.h index a32f847131..5bc8e72e4d 100644 --- a/include/capstone/capstone.h +++ b/include/capstone/capstone.h @@ -319,7 +319,7 @@ typedef struct cs_detail { cs_evm evm; ///< Ethereum architecture cs_mos65xx mos65xx; ///< MOS65XX architecture (including MOS6502) cs_wasm wasm; ///< Web Assembly architecture - cs_bpf bpf; ///< Berkeley Packet Filter architecture (including eBPF) + cs_bpf bpf; ///< Berkeley Packet Filter architecture (including eBPF) }; } cs_detail; diff --git a/suite/MC/BPF/classic.cs b/suite/MC/BPF/classic.cs index b710035059..6dfa27ad0a 100644 --- a/suite/MC/BPF/classic.cs +++ b/suite/MC/BPF/classic.cs @@ -7,3 +7,4 @@ 0x48,0x00,0x00,0x00,0x09,0x00,0x00,0x00 = ldh [x+0x9] 0x62,0x00,0x00,0x00,0x03,0x00,0x00,0x00 = st m[0x3] 0x63,0x00,0x00,0x00,0x0f,0x00,0x00,0x00 = stx m[0xf] +0x84,0x00,0x00,0x00,0x00,0x00,0x00,0x00 = neg diff --git a/suite/MC/BPF/extended.cs b/suite/MC/BPF/extended.cs index ffc1583b34..634cc70426 100644 --- a/suite/MC/BPF/extended.cs +++ b/suite/MC/BPF/extended.cs @@ -1,9 +1,12 @@ # CS_ARCH_BPF, CS_MODE_LITTLE_ENDIAN+CS_MODE_BPF_EXTENDED, None +0x30,0x00,0x00,0x00,0x00,0x00,0x00,0x00 = ldb [0x0] 0x28,0x00,0x00,0x00,0xfa,0x00,0x00,0xff = ldh [0xff0000fa] 0x40,0x10,0x00,0x00,0xcc,0x00,0x00,0x00 = ldw [r1+0xcc] 0x18,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0c,0xb0,0xce,0xfa,0xef,0xbe,0xad,0xde = lddw 0xdeadbeeffaceb00c 0x71,0x13,0x11,0x00,0x00,0x00,0x00,0x00 = ldxb r3, [r1+0x11] 0x94,0x09,0x00,0x00,0x37,0x13,0x03,0x00 = mod r9, 0x31337 +0x84,0x03,0x00,0x00,0x00,0x00,0x00,0x00 = neg r3 +0x87,0x00,0x00,0x00,0x00,0x00,0x00,0x00 = neg64 r0 0xdc,0x02,0x00,0x00,0x20,0x00,0x00,0x00 = be32 r2 0x05,0x00,0x08,0x00,0x00,0x00,0x00,0x00 = jmp +0x8 0xdd,0x35,0x30,0x00,0x00,0x00,0x00,0x00 = jsle r5, r3, +0x30 diff --git a/tests/test_bpf.c b/tests/test_bpf.c index 85027de3c8..e335fdb127 100644 --- a/tests/test_bpf.c +++ b/tests/test_bpf.c @@ -29,6 +29,8 @@ static void print_string_hex(const char *comment, unsigned char *str, size_t 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; // detail can be NULL on "data" instruction if SKIPDATA option is turned ON if (ins->detail == NULL) @@ -53,11 +55,39 @@ static void print_insn_detail(csh cs_handle, cs_insn *ins) for (i = 0; i < bpf->op_count; i++) { cs_bpf_op *op = &(bpf->operands[i]); switch (op->type) { - default: + case BPF_OP_IMM: + printf("\t\toperands[%u].type: IMM = 0x%lx\n", i, op->imm); break; - /* case BPF_OP_IMM: */ - /* printf("\t\toperands[%u].type: IMM = 0x%lx\n", i, op->imm); */ - /* break; */ + case BPF_OP_REG: + printf("\t\toperands[%u].type: REG = %s\n", i, cs_reg_name(cs_handle, op->reg)); + break; + case BPF_OP_MEM: + printf("\t\toperands[%u].type: MEM\n", i); + if (op->mem.base != BPF_REG_INVALID) + printf("\t\t\toperands[%u].mem.base: REG = %s\n", + i, cs_reg_name(cs_handle, op->mem.base)); + printf("\t\t\toperands[%u].mem.disp: 0x%x\n", i, op->mem.disp); + } + } + + /* 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"); } } } @@ -71,7 +101,8 @@ static void test() #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" + "\x30\x00\x00\x00\x00\x00\x00\x00" \ + "\xdb\xa9\x00\x01\x00\x00\x00\x00" struct platform platforms[] = { { CS_ARCH_BPF, From b607b574f4367d18400d5370ff20cf6976fcbd38 Mon Sep 17 00:00:00 2001 From: david942j Date: Sat, 16 Feb 2019 07:47:42 -0800 Subject: [PATCH 14/35] Implements explicit accessed registers and fix some tiny bugs --- arch/BPF/BPFInstPrinter.c | 79 ++++++++++++++++++++++++++------------ arch/BPF/BPFMapping.c | 80 +++++++++++++++++++++++++-------------- include/capstone/bpf.h | 4 ++ tests/test_bpf.c | 38 ++++++++++++++----- 4 files changed, 139 insertions(+), 62 deletions(-) diff --git a/arch/BPF/BPFInstPrinter.c b/arch/BPF/BPFInstPrinter.c index 08e3974aee..48bc3234e2 100644 --- a/arch/BPF/BPFInstPrinter.c +++ b/arch/BPF/BPFInstPrinter.c @@ -39,21 +39,21 @@ static void push_bpf_mmem(cs_bpf *bpf, uint64_t val) { cs_bpf_op *op = expand_bpf_operands(bpf); op->type = BPF_OP_MMEM; - op->imm = val; + op->mmem = val; } static void push_bpf_msh(cs_bpf *bpf, uint64_t val) { cs_bpf_op *op = expand_bpf_operands(bpf); op->type = BPF_OP_MSH; - op->imm = val; + op->msh = val; } static void push_bpf_ext(cs_bpf *bpf, bpf_ext_type val) { cs_bpf_op *op = expand_bpf_operands(bpf); op->type = BPF_OP_EXT; - op->imm = val; + op->ext = val; } static void BPF_convertOperands(MCInst *MI, cs_bpf *bpf) @@ -66,7 +66,6 @@ static void BPF_convertOperands(MCInst *MI, cs_bpf *bpf) bpf->op_count = 0; bpf->operands = NULL; - /* so sad cBPF and eBPF are very different in these case.. */ if (BPF_CLASS(opcode) == BPF_CLASS_LD || BPF_CLASS(opcode) == BPF_CLASS_LDX) { switch (BPF_MODE(opcode)) { case BPF_MODE_IMM: @@ -125,18 +124,43 @@ static void BPF_convertOperands(MCInst *MI, cs_bpf *bpf) push_bpf_reg(bpf, MCOperand_getReg(op), CS_AC_READ); return; } - /* convert 1-to-1 */ - for (i = 0; i < mc_op_count; i++) { - op = MCInst_getOperand(MI, i); - if (MCOperand_isImm(op)) { - push_bpf_imm(bpf, (uint64_t)MCOperand_getImm(op)); + if (!EBPF_MODE(MI->csh) || BPF_CLASS(opcode) == BPF_CLASS_JMP) { + /* In cBPF mode, all registers in operands are accessed as read */ + /* or, eBPF's jmp class also contains no write-acceseed registers */ + for (i = 0; i < mc_op_count; i++) { + op = MCInst_getOperand(MI, i); + if (MCOperand_isImm(op)) + push_bpf_imm(bpf, (uint64_t)MCOperand_getImm(op)); + else if (MCOperand_isReg(op)) + push_bpf_reg(bpf, MCOperand_getReg(op), CS_AC_READ); } - else if (MCOperand_isReg(op)) { - // TODO(david942j): decide this register is read and/or written. - uint8_t ac = 0; + return; + } - push_bpf_reg(bpf, MCOperand_getReg(op), ac); - } + /* remain cases are: eBPF mode && ALU */ + /* if (BPF_CLASS(opcode) == BPF_CLASS_ALU || BPF_CLASS(opcode) == BPF_CLASS_ALU64) */ + + /* We have three types: + * 1. {l,b}e dst // dst = byteswap(dst) + * 2. neg dst // dst = -dst + * 3. op dst, {src_reg, imm} + * so we can simply check the number of operands, + * only one operand means we are in case 1. and 2., + * otherwise in case 3. + */ + if (mc_op_count == 1) { + op = MCInst_getOperand(MI, 0); + push_bpf_reg(bpf, MCOperand_getReg(op), CS_AC_READ | CS_AC_WRITE); + } + else { // if (mc_op_count == 2) + op = MCInst_getOperand(MI, 0); + push_bpf_reg(bpf, MCOperand_getReg(op), CS_AC_WRITE); + + op = MCInst_getOperand(MI, 1); + if (MCOperand_isImm(op)) + push_bpf_imm(bpf, (uint64_t)MCOperand_getImm(op)); + else if (MCOperand_isReg(op)) + push_bpf_reg(bpf, MCOperand_getReg(op), CS_AC_READ); } } @@ -145,16 +169,20 @@ static void BPF_printOperand(MCInst *MI, struct SStream *O, const cs_bpf_op *op) char buf[32]; unsigned opcode = MCInst_getOpcode(MI); - if (op->type == BPF_OP_IMM) { + switch (op->type) { + case BPF_OP_INVALID: + SStream_concat(O, "invalid"); + break; + case BPF_OP_IMM: if (BPF_CLASS(opcode) == BPF_CLASS_JMP) SStream_concat(O, "+"); sprintf(buf, "0x%lx", op->imm); SStream_concat(O, buf); - } - else if (op->type == BPF_OP_REG) { + break; + case BPF_OP_REG: SStream_concat(O, BPF_reg_name((csh)MI->csh, op->reg)); - } - else if (op->type == BPF_OP_MEM) { + break; + case BPF_OP_MEM: SStream_concat(O, "["); if (op->mem.base != BPF_REG_INVALID) SStream_concat(O, BPF_reg_name((csh)MI->csh, op->mem.base)); @@ -167,23 +195,24 @@ static void BPF_printOperand(MCInst *MI, struct SStream *O, const cs_bpf_op *op) if (op->mem.base == BPF_REG_INVALID && op->mem.disp == 0) // special case SStream_concat(O, "0x0"); SStream_concat(O, "]"); - } - else if (op->type == BPF_OP_MMEM) { + break; + case BPF_OP_MMEM: SStream_concat(O, "m["); sprintf(buf, "0x%lx", op->imm); SStream_concat(O, buf); SStream_concat(O, "]"); - } - else if (op->type == BPF_OP_MSH) { + break; + case BPF_OP_MSH: sprintf(buf, "4*([0x%lx]&0xf)", op->imm); SStream_concat(O, buf); - } - else if (op->type == BPF_OP_EXT) { + break; + case BPF_OP_EXT: switch (op->imm) { case BPF_EXT_LEN: SStream_concat(O, "#len"); break; } + break; } } diff --git a/arch/BPF/BPFMapping.c b/arch/BPF/BPFMapping.c index 821ecae505..d1ac105f83 100644 --- a/arch/BPF/BPFMapping.c +++ b/arch/BPF/BPFMapping.c @@ -9,8 +9,8 @@ #ifndef CAPSTONE_DIET static const name_map group_name_maps[] = { - // generic groups { BPF_GRP_INVALID, NULL }, + { BPF_GRP_LOAD, "load" }, { BPF_GRP_STORE, "store" }, { BPF_GRP_ALU, "alu" }, @@ -156,7 +156,7 @@ const char *BPF_reg_name(csh handle, unsigned int reg) #endif } -static bpf_insn op2insn_LD(unsigned opcode) +static bpf_insn op2insn_ld(unsigned opcode) { #define CASE(c) case BPF_SIZE_##c: \ if (BPF_CLASS(opcode) == BPF_CLASS_LD) \ @@ -180,7 +180,7 @@ static bpf_insn op2insn_LD(unsigned opcode) return BPF_INS_INVALID; } -static bpf_insn op2insn_ST(unsigned opcode) +static bpf_insn op2insn_st(unsigned opcode) { /* * - BPF_STX | BPF_XADD | BPF_{W,DW} @@ -209,7 +209,7 @@ static bpf_insn op2insn_ST(unsigned opcode) return BPF_INS_INVALID; } -static bpf_insn op2insn_ALU(unsigned opcode) +static bpf_insn op2insn_alu(unsigned opcode) { /* Endian is a special case */ if (BPF_OP(opcode) == BPF_ALU_END) { @@ -256,7 +256,7 @@ static bpf_insn op2insn_ALU(unsigned opcode) return BPF_INS_INVALID; } -static bpf_insn op2insn_JMP(unsigned opcode) +static bpf_insn op2insn_jmp(unsigned opcode) { #define CASE(c) case BPF_JUMP_##c: return BPF_INS_##c switch (BPF_OP(opcode)) { @@ -309,34 +309,26 @@ void BPF_get_insn_id(cs_struct *ud, cs_insn *insn, unsigned int opcode) default: // will never happen break; case BPF_CLASS_LD: - id = op2insn_LD(opcode); - PUSH_GROUP(BPF_GRP_LOAD); - break; case BPF_CLASS_LDX: - id = op2insn_LD(opcode); + id = op2insn_ld(opcode); PUSH_GROUP(BPF_GRP_LOAD); break; case BPF_CLASS_ST: - id = op2insn_ST(opcode); - PUSH_GROUP(BPF_GRP_STORE); - break; case BPF_CLASS_STX: - id = op2insn_ST(opcode); + id = op2insn_st(opcode); PUSH_GROUP(BPF_GRP_STORE); break; case BPF_CLASS_ALU: - id = op2insn_ALU(opcode); + id = op2insn_alu(opcode); PUSH_GROUP(BPF_GRP_ALU); break; case BPF_CLASS_JMP: grp = BPF_GRP_JUMP; - id = op2insn_JMP(opcode); - if (EBPF_MODE(ud)) { - if (id == BPF_INS_CALL) - grp = BPF_GRP_CALL; - else if (id == BPF_INS_EXIT) - grp = BPF_GRP_RETURN; - } + id = op2insn_jmp(opcode); + if (id == BPF_INS_CALL) + grp = BPF_GRP_CALL; + else if (id == BPF_INS_EXIT) + grp = BPF_GRP_RETURN; PUSH_GROUP(grp); break; case BPF_CLASS_RET: @@ -348,7 +340,7 @@ void BPF_get_insn_id(cs_struct *ud, cs_insn *insn, unsigned int opcode) /* case BPF_CLASS_ALU64: */ if (EBPF_MODE(ud)) { // ALU64 in eBPF - id = op2insn_ALU(opcode); + id = op2insn_alu(opcode); PUSH_GROUP(BPF_GRP_ALU); } else { @@ -358,20 +350,50 @@ void BPF_get_insn_id(cs_struct *ud, cs_insn *insn, unsigned int opcode) id = BPF_INS_TAX; PUSH_GROUP(BPF_GRP_MISC); } + break; } insn->id = id; #undef PUSH_GROUP } +static void sort_and_uniq(cs_regs arr, uint8_t n, uint8_t *new_n) +{ + /* arr is always a tiny (usually n < 3) array, + * a simple O(n^2) sort is efficient enough. */ + int i; + int j; + int iMin; + typeof(arr[0]) tmp; + + /* a modified selection sort for sorting and making unique */ + for (j = 0; j < n; j++) { + /* arr[iMin] will be min(arr[j .. n-1]) */ + iMin = j; + for (i = j + 1; i < n; i++) { + if (arr[i] < arr[iMin]) + iMin = i; + } + if (j != 0 && arr[iMin] == arr[j - 1]) { // duplicate ele found + arr[iMin] = arr[n - 1]; + --n; + } + else { + tmp = arr[iMin]; + arr[iMin] = arr[j]; + arr[j] = tmp; + } + } + + *new_n = n; +} void BPF_reg_access(const cs_insn *insn, cs_regs regs_read, uint8_t *regs_read_count, cs_regs regs_write, uint8_t *regs_write_count) { - //... I need bpf mode..? unsigned i; uint8_t read_count, write_count; - cs_bpf *bpf = &(insn->detail->bpf); + const cs_bpf *bpf = &(insn->detail->bpf); read_count = insn->detail->regs_read_count; write_count = insn->detail->regs_write_count; @@ -381,29 +403,31 @@ void BPF_reg_access(const cs_insn *insn, memcpy(regs_write, insn->detail->regs_write, write_count * sizeof(insn->detail->regs_write[0])); for (i = 0; i < bpf->op_count; i++) { - cs_bpf_op *op = &(bpf->operands[i]); + const cs_bpf_op *op = &(bpf->operands[i]); switch (op->type) { default: break; case BPF_OP_REG: if (op->access & CS_AC_READ) { - regs_read[read_count] = (uint16_t)op->mem.base; + regs_read[read_count] = op->reg; read_count++; } if (op->access & CS_AC_WRITE) { - regs_write[write_count] = (uint16_t)op->mem.base; + regs_write[write_count] = op->reg; write_count++; } break; case BPF_OP_MEM: if (op->mem.base != BPF_REG_INVALID) { - regs_read[read_count] = (uint16_t)op->mem.base; + regs_read[read_count] = op->mem.base; read_count++; } break; } } + sort_and_uniq(regs_read, read_count, &read_count); + sort_and_uniq(regs_write, write_count, &write_count); *regs_read_count = read_count; *regs_write_count = write_count; } diff --git a/include/capstone/bpf.h b/include/capstone/bpf.h index eb6fd294b7..db111d1811 100644 --- a/include/capstone/bpf.h +++ b/include/capstone/bpf.h @@ -70,6 +70,10 @@ typedef struct cs_bpf_op { uint8_t reg; ///< register value for REG operand uint64_t imm; ///< immediate value IMM operand bpf_op_mem mem; ///< base/index/scale/disp value for MEM operand + /* cBPF only */ + uint32_t mmem; ///< M[k] in cBPF + uint32_t msh; ///< corresponds to cBPF's BPF_MSH mode + uint32_t ext; ///< cBPF's extension (not eBPF) }; /// How is this operand accessed? (READ, WRITE or READ|WRITE) diff --git a/tests/test_bpf.c b/tests/test_bpf.c index e335fdb127..71d2b12a0a 100644 --- a/tests/test_bpf.c +++ b/tests/test_bpf.c @@ -26,6 +26,10 @@ static void print_string_hex(const char *comment, unsigned char *str, size_t len printf("\n"); } +static char * ext_name[] = { + [BPF_EXT_LEN] = "#len", +}; + static void print_insn_detail(csh cs_handle, cs_insn *ins) { cs_bpf *bpf; @@ -55,6 +59,9 @@ static void print_insn_detail(csh cs_handle, cs_insn *ins) for (i = 0; i < bpf->op_count; i++) { cs_bpf_op *op = &(bpf->operands[i]); switch (op->type) { + case BPF_OP_INVALID: + printf("\t\toperands[%u].type: INVALID\n", i); + break; case BPF_OP_IMM: printf("\t\toperands[%u].type: IMM = 0x%lx\n", i, op->imm); break; @@ -67,6 +74,16 @@ static void print_insn_detail(csh cs_handle, cs_insn *ins) printf("\t\t\toperands[%u].mem.base: REG = %s\n", i, cs_reg_name(cs_handle, op->mem.base)); printf("\t\t\toperands[%u].mem.disp: 0x%x\n", i, op->mem.disp); + break; + case BPF_OP_MMEM: + printf("\t\toperands[%u].type: MMEM = M[0x%x]\n", i, op->mmem); + break; + case BPF_OP_MSH: + printf("\t\toperands[%u].type: MSH = 4*([0x%x]&0xf)\n", i, op->msh); + break; + case BPF_OP_EXT: + printf("\t\toperands[%u].type: EXT = %s\n", i, ext_name[op->ext]); + break; } } @@ -97,20 +114,16 @@ 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" + "\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\xa9\x00\x01\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_EXTENDED, - (unsigned char *)EBPF_CODE, - sizeof(EBPF_CODE) - 1, - "eBPF Le" - }, { CS_ARCH_BPF, CS_MODE_LITTLE_ENDIAN | CS_MODE_BPF_CLASSIC, @@ -118,6 +131,13 @@ static void test() 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; From 763d5e7ecb1693ade4f14230fb75234b5f03b7e0 Mon Sep 17 00:00:00 2001 From: david942j Date: Sat, 16 Feb 2019 08:32:37 -0800 Subject: [PATCH 15/35] Fix unhandled ja case --- arch/BPF/BPFDisassembler.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/arch/BPF/BPFDisassembler.c b/arch/BPF/BPFDisassembler.c index d30d796bb0..63b1a9e6ad 100644 --- a/arch/BPF/BPFDisassembler.c +++ b/arch/BPF/BPFDisassembler.c @@ -340,6 +340,12 @@ static bool decodeJump(cs_struct *ud, MCInst *MI, bpf_internal *bpf) if (BPF_OP(bpf->op) > BPF_JUMP_JSET) return false; + /* ja is a special case of jumps */ + if (BPF_OP(bpf->op) == BPF_JUMP_JA) { + MCOperand_CreateImm0(MI, bpf->k); + return true; + } + if (BPF_SRC(bpf->op) == BPF_SRC_K) MCOperand_CreateImm0(MI, bpf->k); else /* BPF_SRC_X */ From 4acdfe3be911829368cd7cf43b981f8404b49e97 Mon Sep 17 00:00:00 2001 From: david942j Date: Sat, 16 Feb 2019 08:59:39 -0800 Subject: [PATCH 16/35] Added BPF_REG_OFF do fix wrong display in jump class --- arch/BPF/BPFInstPrinter.c | 65 ++++++++++++++++++++++++++++++--------- include/capstone/bpf.h | 2 ++ suite/MC/BPF/extended.cs | 1 + tests/test_bpf.c | 7 +++-- 4 files changed, 58 insertions(+), 17 deletions(-) diff --git a/arch/BPF/BPFInstPrinter.c b/arch/BPF/BPFInstPrinter.c index 48bc3234e2..8fb3225528 100644 --- a/arch/BPF/BPFInstPrinter.c +++ b/arch/BPF/BPFInstPrinter.c @@ -12,6 +12,14 @@ static cs_bpf_op *expand_bpf_operands(cs_bpf *bpf) return &bpf->operands[bpf->op_count - 1]; } +static void push_bpf_reg(cs_bpf *bpf, unsigned val, uint8_t ac_mode) { + cs_bpf_op *op = expand_bpf_operands(bpf); + + op->type = BPF_OP_REG; + op->reg = val; + op->access = ac_mode; +} + static void push_bpf_imm(cs_bpf *bpf, uint64_t val) { cs_bpf_op *op = expand_bpf_operands(bpf); @@ -19,12 +27,12 @@ static void push_bpf_imm(cs_bpf *bpf, uint64_t val) { op->imm = val; } -static void push_bpf_reg(cs_bpf *bpf, unsigned val, uint8_t ac_mode) { +static void push_bpf_off(cs_bpf *bpf, uint32_t val) { + cs_bpf_op *op = expand_bpf_operands(bpf); - op->type = BPF_OP_REG; - op->reg = val; - op->access = ac_mode; + op->type = BPF_OP_OFF; + op->off = val; } static void push_bpf_mem(cs_bpf *bpf, bpf_reg reg, uint64_t val) { @@ -56,7 +64,7 @@ static void push_bpf_ext(cs_bpf *bpf, bpf_ext_type val) { op->ext = val; } -static void BPF_convertOperands(MCInst *MI, cs_bpf *bpf) +static void convert_operands(MCInst *MI, cs_bpf *bpf) { unsigned opcode = MCInst_getOpcode(MI); unsigned mc_op_count = MCInst_getNumOperands(MI); @@ -124,9 +132,35 @@ static void BPF_convertOperands(MCInst *MI, cs_bpf *bpf) push_bpf_reg(bpf, MCOperand_getReg(op), CS_AC_READ); return; } - if (!EBPF_MODE(MI->csh) || BPF_CLASS(opcode) == BPF_CLASS_JMP) { + + if (BPF_CLASS(opcode) == BPF_CLASS_JMP) { + for (i = 0; i < mc_op_count; i++) { + op = MCInst_getOperand(MI, i); + if (MCOperand_isImm(op)) { + /* decide the imm is BPF_OP_IMM or BPF_OP_OFF type here */ + /* + * 1. ja +off + * 2. call +off // eBPF + * 3. j {x,k}, +jt, +jf // cBPF + * 4. j dst_reg, {src_reg, k}, +off // eBPF + */ + if (BPF_OP(opcode) == BPF_JUMP_JA || + BPF_OP(opcode) == BPF_JUMP_CALL || + (!EBPF_MODE(MI->csh) && i >= 1) || + (EBPF_MODE(MI->csh) && i == 2)) + push_bpf_off(bpf, MCOperand_getImm(op)); + else + push_bpf_imm(bpf, (uint64_t)MCOperand_getImm(op)); + } + else if (MCOperand_isReg(op)) { + push_bpf_reg(bpf, MCOperand_getReg(op), CS_AC_READ); + } + } + return; + } + + if (!EBPF_MODE(MI->csh)) { /* In cBPF mode, all registers in operands are accessed as read */ - /* or, eBPF's jmp class also contains no write-acceseed registers */ for (i = 0; i < mc_op_count; i++) { op = MCInst_getOperand(MI, i); if (MCOperand_isImm(op)) @@ -164,23 +198,24 @@ static void BPF_convertOperands(MCInst *MI, cs_bpf *bpf) } } -static void BPF_printOperand(MCInst *MI, struct SStream *O, const cs_bpf_op *op) +static void print_operand(MCInst *MI, struct SStream *O, const cs_bpf_op *op) { char buf[32]; - unsigned opcode = MCInst_getOpcode(MI); switch (op->type) { case BPF_OP_INVALID: SStream_concat(O, "invalid"); break; + case BPF_OP_REG: + SStream_concat(O, BPF_reg_name((csh)MI->csh, op->reg)); + break; case BPF_OP_IMM: - if (BPF_CLASS(opcode) == BPF_CLASS_JMP) - SStream_concat(O, "+"); sprintf(buf, "0x%lx", op->imm); SStream_concat(O, buf); break; - case BPF_OP_REG: - SStream_concat(O, BPF_reg_name((csh)MI->csh, op->reg)); + case BPF_OP_OFF: + sprintf(buf, "+0x%x", op->off); + SStream_concat(O, buf); break; case BPF_OP_MEM: SStream_concat(O, "["); @@ -233,13 +268,13 @@ void BPF_printInst(MCInst *MI, struct SStream *O, void *PrinterInfo) MCInst_setOpcodePub(MI, insn.id); SStream_concat(O, BPF_insn_name((csh)MI->csh, insn.id)); - BPF_convertOperands(MI, &bpf); + convert_operands(MI, &bpf); for (i = 0; i < bpf.op_count; i++) { if (i == 0) SStream_concat(O, "\t"); else SStream_concat(O, ", "); - BPF_printOperand(MI, O, &bpf.operands[i]); + print_operand(MI, O, &bpf.operands[i]); } #ifndef CAPSTONE_DIET diff --git a/include/capstone/bpf.h b/include/capstone/bpf.h index db111d1811..a4be4059d4 100644 --- a/include/capstone/bpf.h +++ b/include/capstone/bpf.h @@ -20,6 +20,7 @@ typedef enum bpf_op_type { BPF_OP_REG, BPF_OP_IMM, + BPF_OP_OFF, BPF_OP_MEM, BPF_OP_MMEM, ///< M[k] in cBPF BPF_OP_MSH, ///< corresponds to cBPF's BPF_MSH mode @@ -69,6 +70,7 @@ typedef struct cs_bpf_op { union { uint8_t reg; ///< register value for REG operand uint64_t imm; ///< immediate value IMM operand + uint32_t off; ///< offset value, used in jump class bpf_op_mem mem; ///< base/index/scale/disp value for MEM operand /* cBPF only */ uint32_t mmem; ///< M[k] in cBPF diff --git a/suite/MC/BPF/extended.cs b/suite/MC/BPF/extended.cs index 634cc70426..c93bd2f4c7 100644 --- a/suite/MC/BPF/extended.cs +++ b/suite/MC/BPF/extended.cs @@ -10,5 +10,6 @@ 0xdc,0x02,0x00,0x00,0x20,0x00,0x00,0x00 = be32 r2 0x05,0x00,0x08,0x00,0x00,0x00,0x00,0x00 = jmp +0x8 0xdd,0x35,0x30,0x00,0x00,0x00,0x00,0x00 = jsle r5, r3, +0x30 +0xa5,0x35,0x30,0x00,0x10,0x00,0x00,0x00 = jlt r5, 0x10, +0x30 0xc3,0x12,0x00,0x10,0x00,0x00,0x00,0x00 = xaddw [r2+0x1000], r1 0xdb,0xa9,0x00,0x01,0x00,0x00,0x00,0x00 = xadddw [r9+0x100], r10 diff --git a/tests/test_bpf.c b/tests/test_bpf.c index 71d2b12a0a..d335cfd908 100644 --- a/tests/test_bpf.c +++ b/tests/test_bpf.c @@ -62,11 +62,14 @@ static void print_insn_detail(csh cs_handle, cs_insn *ins) case BPF_OP_INVALID: printf("\t\toperands[%u].type: INVALID\n", i); break; + case BPF_OP_REG: + printf("\t\toperands[%u].type: REG = %s\n", i, cs_reg_name(cs_handle, op->reg)); + break; case BPF_OP_IMM: printf("\t\toperands[%u].type: IMM = 0x%lx\n", i, op->imm); break; - case BPF_OP_REG: - printf("\t\toperands[%u].type: REG = %s\n", i, cs_reg_name(cs_handle, op->reg)); + case BPF_OP_OFF: + printf("\t\toperands[%u].type: OFF = +0x%x\n", i, op->off); break; case BPF_OP_MEM: printf("\t\toperands[%u].type: MEM\n", i); From 8cb68e92a5883591d1dec319d1943e07a101dfff Mon Sep 17 00:00:00 2001 From: david942j Date: Sat, 16 Feb 2019 09:18:36 -0800 Subject: [PATCH 17/35] Great I'm able to decode cBPF with eyes --- suite/MC/BPF/classic-all.cs | 51 +++++++++++++++++++++++++++++++++++++ 1 file changed, 51 insertions(+) create mode 100644 suite/MC/BPF/classic-all.cs diff --git a/suite/MC/BPF/classic-all.cs b/suite/MC/BPF/classic-all.cs new file mode 100644 index 0000000000..92d4c09653 --- /dev/null +++ b/suite/MC/BPF/classic-all.cs @@ -0,0 +1,51 @@ +# CS_ARCH_BPF, CS_MODE_LITTLE_ENDIAN+CS_MODE_BPF_CLASSIC, None +0x00,0x00,0x98,0xab,0x08,0x02,0x0e,0x45 = ld 0x450e0208 +0x01,0x00,0x44,0x49,0x1f,0xfe,0xd3,0x93 = ldx 0x93d3fe1f +0x04,0x00,0xda,0x23,0x71,0xc5,0x51,0x42 = add 0x4251c571 +0x05,0x00,0xd4,0xbd,0x37,0xc8,0x2c,0xd5 = jmp +0xd52cc837 +0x06,0x00,0xa7,0x84,0x25,0x40,0x28,0x1c = ret 0x1c284025 +0x07,0x00,0xe8,0xe8,0x48,0xe2,0x84,0x2a = tax +0x0c,0x00,0x55,0x8c,0x32,0xd8,0x21,0xe8 = add x +0x0e,0x00,0xd4,0x24,0x96,0xf7,0xa1,0x49 = ret x +0x14,0x00,0x6a,0xc8,0x14,0x50,0x2d,0x69 = sub 0x692d5014 +0x15,0x00,0xc3,0x39,0x6e,0x4f,0x37,0x18 = jeq 0x18374f6e, +0xc3, +0x39 +0x16,0x00,0x57,0xd2,0xc4,0xd4,0x8a,0x51 = ret a +0x1c,0x00,0xd1,0x51,0x90,0x8a,0x8d,0xea = sub x +0x1d,0x00,0x2e,0xa8,0xbc,0xa7,0xd5,0x3a = jeq x, +0x2e, +0xa8 +0x20,0x00,0x9a,0x43,0x93,0x27,0xec,0xf7 = ld [0xf7ec2793] +0x24,0x00,0x0f,0x46,0xbe,0xe5,0xd2,0x4a = mul 0x4ad2e5be +0x25,0x00,0x8c,0x80,0xc1,0x03,0x38,0x61 = jgt 0x613803c1, +0x8c, +0x80 +0x28,0x00,0xc3,0x05,0x73,0x01,0x39,0xbd = ldh [0xbd390173] +0x2c,0x00,0x7a,0x3d,0xad,0x19,0xe7,0xcc = mul x +0x2d,0x00,0xd9,0xc6,0xf7,0x72,0x9a,0x9d = jgt x, +0xd9, +0xc6 +0x30,0x00,0x22,0x29,0x29,0x5b,0xb5,0x87 = ldb [0x87b55b29] +0x34,0x00,0xa8,0xfa,0x6a,0x92,0xa2,0xa8 = div 0xa8a2926a +0x35,0x00,0x24,0xdb,0x58,0x41,0xa8,0x58 = jge 0x58a84158, +0x24, +0xdb +0x3c,0x00,0x41,0xa6,0xd5,0x66,0x8a,0xdd = div x +0x3d,0x00,0xe4,0xbc,0x40,0xb3,0x4d,0x84 = jge x, +0xe4, +0xbc +0x40,0x00,0xf1,0xa0,0xd9,0x89,0x72,0x25 = ld [x+0x257289d9] +0x44,0x00,0x8d,0xf8,0x49,0xdb,0x10,0x82 = or 0x8210db49 +0x45,0x00,0x43,0xfc,0x7d,0xa1,0x34,0xed = jset 0xed34a17d, +0x43, +0xfc +0x48,0x00,0x6b,0x89,0x0b,0xca,0xfb,0x1b = ldh [x+0x1bfbca0b] +0x4c,0x00,0xc9,0xff,0x36,0xe9,0x2a,0xe7 = or x +0x4d,0x00,0x0d,0xaa,0xc3,0x50,0xea,0x40 = jset x, +0xd, +0xaa +0x50,0x00,0xd9,0xf3,0xda,0xa7,0xd9,0xb1 = ldb [x+0xb1d9a7da] +0x54,0x00,0x14,0x82,0x29,0x82,0x6c,0x06 = and 0x66c8229 +0x5c,0x00,0x80,0x37,0x5f,0x52,0xc0,0x84 = and x +0x60,0x00,0xba,0x4e,0xb5,0x3f,0xdc,0xd8 = ld m[0xd8dc3fb5] +0x61,0x00,0x06,0xd9,0xcd,0x84,0x58,0x94 = ldx m[0x945884cd] +0x62,0x00,0x2c,0x44,0xdf,0x71,0x48,0x1b = st m[0x1b4871df] +0x63,0x00,0xc9,0x53,0x7f,0x80,0x89,0x2d = stx m[0x2d89807f] +0x64,0x00,0x8a,0xe5,0xf0,0x0c,0xca,0xfd = lsh 0xfdca0cf0 +0x6c,0x00,0xd3,0x85,0xc1,0x96,0xb1,0x48 = lsh x +0x74,0x00,0xfa,0x6f,0xe9,0xbe,0xde,0x7e = rsh 0x7edebee9 +0x7c,0x00,0x0d,0x89,0xed,0x17,0x7d,0xcd = rsh x +0x80,0x00,0x70,0x62,0x0e,0x61,0x1b,0x94 = ld #len +0x81,0x00,0xa0,0x03,0xa2,0x5c,0x1f,0x2a = ldx #len +0x84,0x00,0x4f,0x0f,0xc9,0x4a,0x72,0xff = neg +0x87,0x00,0x17,0x2a,0x9a,0xd6,0xb6,0x8f = txa +0x94,0x00,0x85,0x0c,0x29,0xb2,0xbe,0x83 = mod 0x83beb229 +0x9c,0x00,0x30,0x3f,0x9d,0x33,0x89,0x50 = mod x +0xa1,0x00,0x53,0x03,0xdd,0xdf,0xd4,0xe3 = ldx 4*([0xe3d4dfdd]&0xf) +0xa4,0x00,0x66,0x8f,0x3c,0xde,0xe2,0x4d = xor 0x4de2de3c +0xac,0x00,0x02,0x2f,0x1e,0xe3,0x2e,0x84 = xor x From f6438cc64136d26220b7bb7d0e52a681341b3828 Mon Sep 17 00:00:00 2001 From: david942j Date: Sat, 16 Feb 2019 10:49:56 -0800 Subject: [PATCH 18/35] Fix: misunderstood the 16-byte instruction's imm --- arch/BPF/BPFDisassembler.c | 12 ++---------- suite/MC/BPF/extended.cs | 2 +- 2 files changed, 3 insertions(+), 11 deletions(-) diff --git a/arch/BPF/BPFDisassembler.c b/arch/BPF/BPFDisassembler.c index 63b1a9e6ad..4636c5eacd 100644 --- a/arch/BPF/BPFDisassembler.c +++ b/arch/BPF/BPFDisassembler.c @@ -27,14 +27,6 @@ static uint32_t read_u32(cs_struct *ud, const uint8_t *code) return ((uint32_t)read_u16(ud, code + 2) << 16) | read_u16(ud, code); } -static uint64_t read_u64(cs_struct *ud, const uint8_t *code) -{ - if (MODE_IS_BIG_ENDIAN(ud->mode)) - return ((uint64_t)read_u32(ud, code) << 32) | read_u32(ud, code + 4); - else - return ((uint64_t)read_u32(ud, code + 4) << 32) | read_u32(ud, code); -} - ///< Malloc bpf_internal, also checks if code_len is large enough. static bpf_internal *alloc_bpf_internal(size_t code_len) { @@ -80,13 +72,13 @@ static bpf_internal* fetch_ebpf(cs_struct *ud, const uint8_t *code, bpf->op = (uint16_t)code[0]; // eBPF has one 16-byte instruction: BPF_LD | BPF_DW | BPF_IMM, - // in this case imm is fetched from the next 8-byte block. + // in this case imm is combined with next 8-byte block's imm. if (bpf->op == (BPF_CLASS_LD | BPF_SIZE_DW | BPF_MODE_IMM)) { if (code_len < 16) { cs_mem_free(bpf); return NULL; } - bpf->k = read_u64(ud, code + 8); + bpf->k = read_u32(ud, code + 4) | (((uint64_t)read_u32(ud, code + 12)) << 32); bpf->insn_size = 16; } else { diff --git a/suite/MC/BPF/extended.cs b/suite/MC/BPF/extended.cs index c93bd2f4c7..c512a335bc 100644 --- a/suite/MC/BPF/extended.cs +++ b/suite/MC/BPF/extended.cs @@ -2,7 +2,7 @@ 0x30,0x00,0x00,0x00,0x00,0x00,0x00,0x00 = ldb [0x0] 0x28,0x00,0x00,0x00,0xfa,0x00,0x00,0xff = ldh [0xff0000fa] 0x40,0x10,0x00,0x00,0xcc,0x00,0x00,0x00 = ldw [r1+0xcc] -0x18,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0c,0xb0,0xce,0xfa,0xef,0xbe,0xad,0xde = lddw 0xdeadbeeffaceb00c +0x18,0x00,0x00,0x00,0x0c,0xb0,0xce,0xfa,0x00,0x00,0x00,0x00,0xef,0xbe,0xad,0xde = lddw 0xdeadbeeffaceb00c 0x71,0x13,0x11,0x00,0x00,0x00,0x00,0x00 = ldxb r3, [r1+0x11] 0x94,0x09,0x00,0x00,0x37,0x13,0x03,0x00 = mod r9, 0x31337 0x84,0x03,0x00,0x00,0x00,0x00,0x00,0x00 = neg r3 From 546cf1d0d6ff0d7005f284a97d14f15a7ca54ca6 Mon Sep 17 00:00:00 2001 From: david942j Date: Sat, 16 Feb 2019 10:52:37 -0800 Subject: [PATCH 19/35] Add ldxdw --- arch/BPF/BPFMapping.c | 8 ++------ include/capstone/bpf.h | 1 + 2 files changed, 3 insertions(+), 6 deletions(-) diff --git a/arch/BPF/BPFMapping.c b/arch/BPF/BPFMapping.c index d1ac105f83..41f024be38 100644 --- a/arch/BPF/BPFMapping.c +++ b/arch/BPF/BPFMapping.c @@ -76,6 +76,7 @@ static const name_map insn_name_maps[BPF_INS_ENDING] = { { BPF_INS_LDXW, "ldxw" }, { BPF_INS_LDXH, "ldxh" }, { BPF_INS_LDXB, "ldxb" }, + { BPF_INS_LDXDW, "ldxdw" }, { BPF_INS_STW, "stw" }, { BPF_INS_STH, "sth" }, @@ -165,15 +166,10 @@ static bpf_insn op2insn_ld(unsigned opcode) return BPF_INS_LDX##c; switch (BPF_SIZE(opcode)) { - case BPF_SIZE_DW: - /* ldxdw not exists */ - if (BPF_CLASS(opcode) == BPF_CLASS_LD) - return BPF_INS_LDDW; - else - break; CASE(W); CASE(H); CASE(B); + CASE(DW); } #undef CASE diff --git a/include/capstone/bpf.h b/include/capstone/bpf.h index a4be4059d4..d3a6048b69 100644 --- a/include/capstone/bpf.h +++ b/include/capstone/bpf.h @@ -140,6 +140,7 @@ typedef enum bpf_insn { BPF_INS_LDXW, ///< eBPF only BPF_INS_LDXH, ///< eBPF only BPF_INS_LDXB, ///< eBPF only + BPF_INS_LDXDW, ///< eBPF only ///< Store BPF_INS_STW, ///< eBPF only From 501e99aa5e6d96fd0dc1f6680b47a69729740186 Mon Sep 17 00:00:00 2001 From: david942j Date: Sat, 16 Feb 2019 10:52:52 -0800 Subject: [PATCH 20/35] Add extended-all.cs --- suite/MC/BPF/extended-all.cs | 97 ++++++++++++++++++++++++++++++++++++ 1 file changed, 97 insertions(+) create mode 100644 suite/MC/BPF/extended-all.cs diff --git a/suite/MC/BPF/extended-all.cs b/suite/MC/BPF/extended-all.cs new file mode 100644 index 0000000000..d320fae8c3 --- /dev/null +++ b/suite/MC/BPF/extended-all.cs @@ -0,0 +1,97 @@ +# CS_ARCH_BPF, CS_MODE_LITTLE_ENDIAN+CS_MODE_BPF_EXTENDED, None +0x04,0xb4,0x97,0xa8,0xe8,0x60,0x56,0xe1 = add r4, 0xe15660e8 +0x05,0xc7,0x71,0xb0,0x43,0x1f,0xb9,0xf5 = jmp +0xb071 +0x07,0x76,0x01,0x28,0xc4,0x09,0xfe,0x8b = add64 r6, 0x8bfe09c4 +0x0c,0x42,0x0a,0x48,0x58,0xc4,0xef,0x37 = add r2, r4 +0x0f,0x09,0x40,0x54,0x67,0x24,0x2f,0x88 = add64 r9, r0 +0x14,0xd9,0xba,0xb8,0x6f,0x07,0x93,0x2a = sub r9, 0x2a93076f +0x15,0x6a,0x9f,0x38,0x1a,0x9d,0xb7,0x4d = jeq r10, 0x4db79d1a, +0x389f +0x17,0xc5,0x60,0xed,0x0b,0xdc,0xe6,0x22 = sub64 r5, 0x22e6dc0b +0x18,0xa3,0x5c,0x14,0xde,0xf0,0xa5,0xff,0x9a,0x7e,0x10,0xee,0xd8,0xa4,0x2b,0x2f = lddw 0x2f2ba4d8ffa5f0de +0x1c,0x73,0x68,0xa4,0x8b,0x5b,0x93,0x1f = sub r3, r7 +0x1d,0x21,0x20,0x4d,0xe3,0x47,0xaf,0x1b = jeq r1, r2, +0x4d20 +0x1f,0x06,0x51,0x5a,0x39,0xb2,0x10,0x10 = sub64 r6, r0 +0x20,0xc7,0x0c,0x70,0xda,0x41,0x1a,0xca = ldw [0xca1a41da] +0x24,0xb6,0x69,0x66,0xe3,0xef,0xec,0x25 = mul r6, 0x25ecefe3 +0x25,0x89,0xda,0x53,0x19,0x73,0x8a,0xc0 = jgt r9, 0xc08a7319, +0x53da +0x27,0xb1,0x96,0x1d,0xd4,0xab,0x2c,0x8c = mul64 r1, 0x8c2cabd4 +0x28,0x4e,0xb0,0x62,0xe8,0x48,0x0b,0x0d = ldh [0xd0b48e8] +0x2c,0x78,0x03,0xf6,0x29,0x29,0x15,0xfc = mul r8, r7 +0x2d,0x18,0x5b,0xfd,0x8f,0x53,0x3b,0xf0 = jgt r8, r1, +0xfd5b +0x2f,0x77,0xc7,0xa4,0x4c,0x32,0x73,0x2a = mul64 r7, r7 +0x30,0x5f,0xfe,0xfc,0x85,0x66,0x7c,0x4b = ldb [0x4b7c6685] +0x34,0x46,0x49,0x33,0xe1,0x72,0xd4,0xcb = div r6, 0xcbd472e1 +0x35,0xa5,0x42,0xb9,0x5b,0x37,0xa1,0x3d = jge r5, 0x3da1375b, +0xb942 +0x37,0x84,0xd8,0xba,0x3b,0x84,0x55,0x1f = div64 r4, 0x1f55843b +0x38,0x8e,0x3f,0xd7,0x1c,0x3e,0x3a,0x7b = lddw [0x7b3a3e1c] +0x3d,0x1a,0xc3,0x9b,0x88,0xa2,0x3f,0x65 = jge r10, r1, +0x9bc3 +0x3f,0x36,0x99,0x32,0x7e,0x07,0x59,0x7a = div64 r6, r3 +0x40,0x95,0xc2,0x39,0x6b,0xe7,0xd7,0xc4 = ldw [r9+0xc4d7e76b] +0x44,0x16,0xf7,0x98,0xf7,0x02,0x92,0x94 = or r6, 0x949202f7 +0x45,0x12,0xa2,0xf2,0x14,0xe7,0x2d,0x1e = jset r2, 0x1e2de714, +0xf2a2 +0x47,0x36,0xf4,0xd5,0xbe,0x04,0x58,0x4d = or64 r6, 0x4d5804be +0x48,0x7e,0xfb,0x77,0xeb,0x0e,0x5a,0x0d = ldh [r7+0xd5a0eeb] +0x4c,0x81,0x0a,0x66,0xfc,0x32,0x61,0xc4 = or r1, r8 +0x4d,0x10,0x67,0x44,0x4d,0x3f,0x4d,0x8b = jset r0, r1, +0x4467 +0x4f,0x81,0xeb,0x6b,0xde,0x98,0x87,0x64 = or64 r1, r8 +0x50,0x38,0x80,0xf8,0x04,0x70,0xd1,0x6c = ldb [r3+0x6cd17004] +0x54,0x40,0x0a,0x6a,0x4a,0xe8,0xab,0xfb = and r0, 0xfbabe84a +0x55,0xb9,0xa3,0x80,0x90,0xbc,0xc8,0x96 = jne r9, 0x96c8bc90, +0x80a3 +0x57,0x30,0x12,0xe9,0x7c,0x06,0x82,0x27 = and64 r0, 0x2782067c +0x58,0x6d,0xf1,0x05,0xd3,0x50,0x4b,0xc0 = lddw [r6+0xc04b50d3] +0x5c,0x02,0x95,0xb2,0xbd,0x3f,0x38,0x37 = and r2, r0 +0x5d,0x56,0xa3,0x4c,0x2a,0xc8,0x4a,0xc5 = jne r6, r5, +0x4ca3 +0x5f,0x59,0xf6,0xaa,0x5d,0xeb,0x27,0xdd = and64 r9, r5 +0x61,0x28,0xb2,0xed,0xb8,0xcf,0xb5,0xe4 = ldxw r8, [r2+0xedb2] +0x62,0xa5,0xdf,0xe0,0x14,0x7d,0x95,0x78 = stw [r5+0xe0df], 0x78957d14 +0x63,0x77,0x2f,0xcf,0x76,0xb7,0xd3,0xfa = stxw [r7+0xcf2f], r7 +0x64,0x68,0xc1,0xf4,0x88,0x92,0xd2,0xeb = lsh r8, 0xebd29288 +0x65,0xe8,0x97,0xe1,0x87,0xbe,0x8f,0xf8 = jsgt r8, 0xf88fbe87, +0xe197 +0x67,0x00,0xd7,0xc0,0x05,0xb0,0xf6,0x74 = lsh64 r0, 0x74f6b005 +0x69,0x14,0xc7,0x8e,0x0b,0xc1,0xad,0x69 = ldxh r4, [r1+0x8ec7] +0x6a,0xb5,0xbc,0x8c,0x4f,0x5c,0x94,0x01 = sth [r5+0x8cbc], 0x1945c4f +0x6b,0x34,0x58,0xf5,0xc8,0x27,0x9e,0x14 = stxh [r4+0xf558], r3 +0x6c,0x21,0x10,0x48,0x01,0x3e,0x6e,0xf8 = lsh r1, r2 +0x6d,0x38,0x69,0xe3,0xc9,0xac,0x3c,0xdb = jsgt r8, r3, +0xe369 +0x6f,0x64,0x49,0xd6,0x07,0xa9,0x93,0x13 = lsh64 r4, r6 +0x71,0xa0,0xeb,0xfb,0x3d,0x6b,0x58,0x45 = ldxb r0, [r10+0xfbeb] +0x72,0xe2,0xc1,0x1b,0x25,0x2f,0x4a,0xdc = stb [r2+0x1bc1], 0xdc4a2f25 +0x73,0x44,0x09,0x0f,0xc1,0x07,0xa8,0xf4 = stxb [r4+0xf09], r4 +0x74,0xe0,0x23,0x23,0x2f,0x04,0x15,0x35 = rsh r0, 0x3515042f +0x75,0x04,0x8e,0x18,0x6a,0xcc,0x3c,0x09 = jsge r4, 0x93ccc6a, +0x188e +0x77,0x09,0x3a,0xa7,0x3c,0x6e,0xfa,0x23 = rsh64 r9, 0x23fa6e3c +0x79,0xa9,0x5c,0x7b,0x16,0x1f,0xfb,0x01 = ldxdw r9, [r10+0x7b5c] +0x7a,0xd8,0x6b,0x04,0x76,0xf0,0x51,0x75 = stdw [r8+0x46b], 0x7551f076 +0x7b,0x72,0x0f,0x30,0x51,0x78,0xd2,0x9a = stxdw [r2+0x300f], r7 +0x7c,0x13,0x12,0x73,0x5a,0x20,0x65,0xdb = rsh r3, r1 +0x7d,0x58,0x52,0x01,0x90,0xf9,0x30,0x9a = jsge r8, r5, +0x152 +0x7f,0x98,0xea,0xff,0xcf,0x5d,0x5f,0xa3 = rsh64 r8, r9 +0x84,0x14,0xd4,0xaf,0x60,0xe1,0x41,0x18 = neg r4 +0x85,0xd3,0xa5,0xe2,0x83,0x3d,0xbd,0x5d = call +0x5dbd3d83 +0x87,0xf5,0x2b,0xbe,0xa9,0xc7,0x31,0xa3 = neg64 r5 +0x94,0x39,0x0d,0xdc,0x0b,0xd2,0xd1,0xc9 = mod r9, 0xc9d1d20b +0x95,0xf2,0xd1,0x83,0x53,0xa9,0x09,0x9f = exit +0x97,0xc8,0xa6,0x75,0xd2,0x09,0x98,0x09 = mod64 r8, 0x99809d2 +0x9c,0x96,0xe7,0x16,0x0f,0x69,0x13,0x90 = mod r6, r9 +0x9f,0x35,0x5a,0x59,0xd6,0x70,0xd9,0x5e = mod64 r5, r3 +0xa4,0x89,0x6b,0x5f,0x0d,0xbf,0x90,0xf7 = xor r9, 0xf790bf0d +0xa5,0xd4,0xef,0x79,0xd3,0xbb,0xde,0xfd = jlt r4, 0xfddebbd3, +0x79ef +0xa7,0x80,0x8b,0x18,0xa9,0x34,0x74,0x45 = xor64 r0, 0x457434a9 +0xac,0x36,0x16,0xe0,0x0f,0x52,0x30,0x65 = xor r6, r3 +0xaf,0x41,0x04,0xc2,0x2e,0xc9,0xf7,0x84 = xor64 r1, r4 +0xb4,0xa1,0x9c,0x78,0xf9,0x3f,0x77,0x1f = mov r1, 0x1f773ff9 +0xb5,0x92,0x5d,0x5a,0x49,0x33,0xfc,0x33 = jle r2, 0x33fc3349, +0x5a5d +0xb7,0x70,0x59,0x4d,0x5b,0x52,0x2a,0x99 = mov64 r0, 0x992a525b +0xbc,0x72,0x3e,0x6c,0xc9,0x8a,0x56,0xd6 = mov r2, r7 +0xbd,0x19,0x80,0xe8,0x29,0x85,0xcf,0x51 = jle r9, r1, +0xe880 +0xbf,0x86,0x55,0x58,0xb2,0x6d,0x14,0x03 = mov64 r6, r8 +0xc4,0xb6,0xe2,0xe0,0x7c,0x68,0xc5,0x2b = arsh r6, 0x2bc5687c +0xc5,0xf2,0xeb,0xe4,0xba,0xc0,0xce,0x4f = jslt r2, 0x4fcec0ba, +0xe4eb +0xc7,0xe8,0xba,0xff,0x1f,0xef,0xc0,0x88 = arsh64 r8, 0x88c0ef1f +0xcc,0x38,0xc5,0x37,0x13,0xc0,0xe7,0x27 = arsh r8, r3 +0xcd,0x90,0x67,0x88,0x6b,0xd0,0x27,0xf4 = jslt r0, r9, +0x8867 +0xcf,0x82,0xe1,0xcd,0xbe,0xc3,0x2d,0x7c = arsh64 r2, r8 +0xd4,0x53,0x3f,0x0c,0x40,0x00,0x00,0x00 = le64 r3 +0xd5,0xe9,0xf6,0xb2,0x50,0xfd,0xb0,0xe5 = jsle r9, 0xe5b0fd50, +0xb2f6 +0xdc,0xb2,0xa3,0x50,0x20,0x00,0x00,0x00 = be32 r2 +0xdd,0x95,0xbf,0xb1,0xf2,0x5f,0x7b,0xc4 = jsle r5, r9, +0xb1bf From a7b633f0f50ed4f7f6c257689c6670a7559afc4a Mon Sep 17 00:00:00 2001 From: david942j Date: Sat, 16 Feb 2019 11:53:19 -0800 Subject: [PATCH 21/35] Implements cstest/bpf_getdetail.c --- include/capstone/capstone.h | 4 +-- suite/MC/BPF/extended-be.cs | 13 +++++++ suite/cstest/src/bpf_detail.c | 59 ++++++++++++++++++++++++++++++++ suite/cstest/src/capstone_test.c | 1 + 4 files changed, 75 insertions(+), 2 deletions(-) diff --git a/include/capstone/capstone.h b/include/capstone/capstone.h index 5bc8e72e4d..3defb0e4f8 100644 --- a/include/capstone/capstone.h +++ b/include/capstone/capstone.h @@ -137,8 +137,8 @@ typedef enum cs_mode { CS_MODE_M680X_CPU12 = 1 << 9, ///< M680X Motorola/Freescale/NXP CPU12 ///< used on M68HC12/HCS12 CS_MODE_M680X_HCS08 = 1 << 10, ///< M680X Freescale/NXP HCS08 mode - CS_MODE_BPF_CLASSIC = 0, ///< Classic BPF mode - CS_MODE_BPF_EXTENDED = 1 << 1, ///< Extended BPF mode + CS_MODE_BPF_CLASSIC = 0, ///< Classic BPF mode (default) + CS_MODE_BPF_EXTENDED = 1 << 0, ///< Extended BPF mode } cs_mode; typedef void* (CAPSTONE_API *cs_malloc_t)(size_t size); diff --git a/suite/MC/BPF/extended-be.cs b/suite/MC/BPF/extended-be.cs index a93cdc5c37..aa97d569e7 100644 --- a/suite/MC/BPF/extended-be.cs +++ b/suite/MC/BPF/extended-be.cs @@ -1,2 +1,15 @@ # CS_ARCH_BPF, CS_MODE_BIG_ENDIAN+CS_MODE_BPF_EXTENDED, None +0x30,0x00,0x00,0x00,0x00,0x00,0x00,0x00 = ldb [0x0] +0x28,0x00,0x00,0x00,0xfa,0x00,0x00,0xff = ldh [0xfa0000ff] +0x40,0x10,0x00,0x00,0xcc,0x00,0x00,0x00 = ldw [r1+0xcc000000] +0x18,0x00,0x00,0x00,0x0c,0xb0,0xce,0xfa,0x00,0x00,0x00,0x00,0xef,0xbe,0xad,0xde = lddw 0xefbeadde0cb0cefa +0x71,0x13,0x11,0x00,0x00,0x00,0x00,0x00 = ldxb r3, [r1+0x1100] 0x94,0x09,0x00,0x00,0x37,0x13,0x03,0x00 = mod r9, 0x37130300 +0x84,0x03,0x00,0x00,0x00,0x00,0x00,0x00 = neg r3 +0x87,0x00,0x00,0x00,0x00,0x00,0x00,0x00 = neg64 r0 +0xdc,0x02,0x00,0x00,0x00,0x00,0x00,0x20 = be32 r2 +0x05,0x00,0x08,0x00,0x00,0x00,0x00,0x00 = jmp +0x800 +0xdd,0x35,0x30,0x00,0x00,0x00,0x00,0x00 = jsle r5, r3, +0x3000 +0xa5,0x35,0x30,0x00,0x10,0x00,0x00,0x00 = jlt r5, 0x10000000, +0x3000 +0xc3,0x12,0x00,0x10,0x00,0x00,0x00,0x00 = xaddw [r2+0x10], r1 +0xdb,0xa9,0x00,0x01,0x00,0x00,0x00,0x00 = xadddw [r9+0x1], r10 diff --git a/suite/cstest/src/bpf_detail.c b/suite/cstest/src/bpf_detail.c index 41973664cc..553b08b3b7 100644 --- a/suite/cstest/src/bpf_detail.c +++ b/suite/cstest/src/bpf_detail.c @@ -3,8 +3,16 @@ #include "factory.h" +static char * ext_name[] = { + [BPF_EXT_LEN] = "#len", +}; + char *get_detail_bpf(csh *handle, cs_mode mode, cs_insn *ins) { + cs_bpf *bpf; + int i; + cs_regs regs_read, regs_write; + uint8_t regs_read_count, regs_write_count; char *result; result = (char *)malloc(sizeof(char)); @@ -12,5 +20,56 @@ char *get_detail_bpf(csh *handle, cs_mode mode, cs_insn *ins) if (ins->detail == NULL) return result; + bpf = &(ins->detail->bpf); + + if (bpf->op_count) + add_str(&result, " ; op_count: %u", bpf->op_count); + for (i = 0; i < bpf->op_count; i++) { + cs_bpf_op *op = &(bpf->operands[i]); + switch (op->type) { + case BPF_OP_INVALID: + add_str(&result, " ; operands[%u].type: INVALID", i); + break; + case BPF_OP_REG: + add_str(&result, " ; operands[%u].type: REG = %s", i, cs_reg_name(*handle, op->reg)); + break; + case BPF_OP_IMM: + add_str(&result, " ; operands[%u].type: IMM = 0x%lx", i, op->imm); + break; + case BPF_OP_OFF: + add_str(&result, " ; operands[%u].type: OFF = +0x%x", i, op->off); + break; + case BPF_OP_MEM: + add_str(&result, " ; operands[%u].type: MEM [base=%s, disp=0x%x]", + i, cs_reg_name(*handle, op->mem.base), op->mem.disp); + break; + case BPF_OP_MMEM: + add_str(&result, " ; operands[%u].type: MMEM = M[0x%x]", i, op->mmem); + break; + case BPF_OP_MSH: + add_str(&result, " ; operands[%u].type: MSH = 4*([0x%x]&0xf)", i, op->msh); + break; + case BPF_OP_EXT: + add_str(&result, " ; operands[%u].type: EXT = %s", i, ext_name[op->ext]); + break; + } + } + + if (!cs_regs_access(*handle, ins, + regs_read, ®s_read_count, + regs_write, ®s_write_count)) { + if (regs_read_count) { + add_str(&result, " ; Registers read:"); + for(i = 0; i < regs_read_count; i++) + add_str(&result, " %s", cs_reg_name(*handle, regs_read[i])); + printf("\n"); + } + + if (regs_write_count) { + add_str(&result, " ; Registers modified:"); + for(i = 0; i < regs_write_count; i++) + add_str(&result, " %s", cs_reg_name(*handle, regs_write[i])); + } + } return result; } diff --git a/suite/cstest/src/capstone_test.c b/suite/cstest/src/capstone_test.c index 5a4645dfc6..46738369b3 100644 --- a/suite/cstest/src/capstone_test.c +++ b/suite/cstest/src/capstone_test.c @@ -270,6 +270,7 @@ int set_function(int arch) break; case CS_ARCH_BPF: function = get_detail_bpf; + break; default: return -1; } From 251adca2e527439bb0b0352e02b90be88ddb9411 Mon Sep 17 00:00:00 2001 From: david942j Date: Sat, 16 Feb 2019 23:02:55 -0800 Subject: [PATCH 22/35] Fix memory leak --- arch/BPF/BPFInstPrinter.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/arch/BPF/BPFInstPrinter.c b/arch/BPF/BPFInstPrinter.c index 8fb3225528..695bedcf35 100644 --- a/arch/BPF/BPFInstPrinter.c +++ b/arch/BPF/BPFInstPrinter.c @@ -280,6 +280,8 @@ void BPF_printInst(MCInst *MI, struct SStream *O, void *PrinterInfo) #ifndef CAPSTONE_DIET if (MI->flat_insn->detail) { MI->flat_insn->detail->bpf = bpf; + return; } #endif + cs_mem_free(bpf.operands); } From ee1306f8f86335867ba9b17b2c4c2cd5e02d9b08 Mon Sep 17 00:00:00 2001 From: david942j Date: Sat, 16 Feb 2019 23:03:30 -0800 Subject: [PATCH 23/35] Add BPF to fuzz --- suite/fuzz/drivermc.c | 4 ++++ suite/fuzz/fuzz_disasm.c | 14 ++++++++++++-- 2 files changed, 16 insertions(+), 2 deletions(-) diff --git a/suite/fuzz/drivermc.c b/suite/fuzz/drivermc.c index a6a0163ee4..70402076b9 100644 --- a/suite/fuzz/drivermc.c +++ b/suite/fuzz/drivermc.c @@ -91,6 +91,10 @@ int main(int argc, char** argv) Data[0] = 24; } else if (strcmp(arch, "CS_ARCH_EVM") == 0 && strcmp(mode, "0") == 0) { Data[0] = 25; + } else if (strcmp(arch, "CS_ARCH_BPF") == 0 && strstr(mode, "CS_MODE_BPF_CLASSIC") != NULL) { + Data[0] = 29; + } else if (strcmp(arch, "CS_ARCH_BPF") == 0 && strstr(mode, "CS_MODE_BPF_EXTENDED") != NULL) { + Data[0] = 30; } else { printf("Unknown mode\n"); //fail instead of continue diff --git a/suite/fuzz/fuzz_disasm.c b/suite/fuzz/fuzz_disasm.c index 6cf14eeb70..bfee670c48 100644 --- a/suite/fuzz/fuzz_disasm.c +++ b/suite/fuzz/fuzz_disasm.c @@ -189,14 +189,24 @@ static struct platform platforms[] = { CS_MODE_BIG_ENDIAN, "tms320c64x" }, -#if CS_NEXT_VERSION >= 5 { //item 28 CS_ARCH_WASM, (cs_mode)0, "WASM" }, -#endif + { + //item 29 + CS_ARCH_BPF, + CS_MODE_LITTLE_ENDIAN | CS_MODE_BPF_CLASSIC, + "cBPF" + }, + { + //item 30 + CS_ARCH_BPF, + CS_MODE_LITTLE_ENDIAN | CS_MODE_BPF_EXTENDED, + "eBPF" + }, }; int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) { From 1a1431c863a818d27610d87bf8d49fa7e89bd6c6 Mon Sep 17 00:00:00 2001 From: david942j Date: Sat, 16 Feb 2019 23:47:10 -0800 Subject: [PATCH 24/35] Implemented regs_read and regs_write --- arch/BPF/BPFMapping.c | 79 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 79 insertions(+) diff --git a/arch/BPF/BPFMapping.c b/arch/BPF/BPFMapping.c index 41f024be38..b6b42b63b8 100644 --- a/arch/BPF/BPFMapping.c +++ b/arch/BPF/BPFMapping.c @@ -277,6 +277,79 @@ static bpf_insn op2insn_jmp(unsigned opcode) return BPF_INS_INVALID; } +static void update_regs_access(cs_struct *ud, cs_detail *detail, + bpf_insn insn_id, unsigned int opcode) +{ + if (insn_id == BPF_INS_INVALID) + return; +#define PUSH_READ(r) do { \ + detail->regs_read[detail->regs_read_count] = r; \ + detail->regs_read_count++; \ + } while (0) +#define PUSH_WRITE(r) do { \ + detail->regs_write[detail->regs_write_count] = r; \ + detail->regs_write_count++; \ + } while (0) + /* + * In eBPF mode, only these instructions have implicit registers access: + * - ld{w,h,b,dw} * // w: r0 + * - exit // r: r0 + */ + if (EBPF_MODE(ud)) { + switch (insn_id) { + default: + break; + case BPF_INS_LDW: + case BPF_INS_LDH: + case BPF_INS_LDB: + case BPF_INS_LDDW: + PUSH_WRITE(BPF_REG_R0); + break; + case BPF_INS_EXIT: + PUSH_READ(BPF_REG_R0); + break; + } + return; + } + + /* cBPF mode */ + switch (BPF_CLASS(opcode)) { + default: + break; + case BPF_CLASS_LD: + PUSH_WRITE(BPF_REG_A); + break; + case BPF_CLASS_LDX: + PUSH_WRITE(BPF_REG_X); + break; + case BPF_CLASS_ST: + PUSH_READ(BPF_REG_A); + break; + case BPF_CLASS_STX: + PUSH_READ(BPF_REG_X); + break; + case BPF_CLASS_ALU: + PUSH_READ(BPF_REG_A); + PUSH_WRITE(BPF_REG_A); + break; + case BPF_CLASS_JMP: + if (insn_id != BPF_INS_JMP) // except the unconditional jump + PUSH_READ(BPF_REG_A); + break; + /* case BPF_CLASS_RET: */ + case BPF_CLASS_MISC: + if (insn_id == BPF_INS_TAX) { + PUSH_READ(BPF_REG_A); + PUSH_WRITE(BPF_REG_X); + } + else { + PUSH_READ(BPF_REG_X); + PUSH_WRITE(BPF_REG_A); + } + break; + } +} + /* * 1. Convert opcode(id) to BPF_INS_* * 2. Set regs_read/regs_write/groups @@ -351,6 +424,12 @@ void BPF_get_insn_id(cs_struct *ud, cs_insn *insn, unsigned int opcode) insn->id = id; #undef PUSH_GROUP + +#ifndef CAPSTONE_DIET + if (detail) { + update_regs_access(ud, detail, id, opcode); + } +#endif } static void sort_and_uniq(cs_regs arr, uint8_t n, uint8_t *new_n) From 6b97b4396d1f0cd91bfcab6a21ecc2d02412f025 Mon Sep 17 00:00:00 2001 From: david942j Date: Sun, 17 Feb 2019 00:48:55 -0800 Subject: [PATCH 25/35] Fix missing write-access on ALU's dst --- arch/BPF/BPFInstPrinter.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/BPF/BPFInstPrinter.c b/arch/BPF/BPFInstPrinter.c index 695bedcf35..030cefcd42 100644 --- a/arch/BPF/BPFInstPrinter.c +++ b/arch/BPF/BPFInstPrinter.c @@ -177,7 +177,7 @@ static void convert_operands(MCInst *MI, cs_bpf *bpf) /* We have three types: * 1. {l,b}e dst // dst = byteswap(dst) * 2. neg dst // dst = -dst - * 3. op dst, {src_reg, imm} + * 3. op dst, {src_reg, imm} // dst = dst op src * so we can simply check the number of operands, * only one operand means we are in case 1. and 2., * otherwise in case 3. @@ -188,7 +188,7 @@ static void convert_operands(MCInst *MI, cs_bpf *bpf) } else { // if (mc_op_count == 2) op = MCInst_getOperand(MI, 0); - push_bpf_reg(bpf, MCOperand_getReg(op), CS_AC_WRITE); + push_bpf_reg(bpf, MCOperand_getReg(op), CS_AC_READ | CS_AC_WRITE); op = MCInst_getOperand(MI, 1); if (MCOperand_isImm(op)) From 105934d6bc6b0c3cceadfab65060954eda07200d Mon Sep 17 00:00:00 2001 From: david942j Date: Sun, 17 Feb 2019 00:49:51 -0800 Subject: [PATCH 26/35] Updated cstool/, test_basic.c, test_detail.c, and test_iter.c --- cstool/cstool.c | 15 +++++++++ cstool/cstool_bpf.c | 79 +++++++++++++++++++++++++++++++++++++++++++++ tests/test_basic.c | 11 ++++++- tests/test_detail.c | 11 ++++++- tests/test_iter.c | 11 ++++++- 5 files changed, 124 insertions(+), 3 deletions(-) create mode 100644 cstool/cstool_bpf.c diff --git a/cstool/cstool.c b/cstool/cstool.c index 40406b74d6..50398aa25e 100644 --- a/cstool/cstool.c +++ b/cstool/cstool.c @@ -60,6 +60,10 @@ static struct { { "evm", CS_ARCH_EVM, 0 }, { "wasm", CS_ARCH_WASM, 0 }, { "mos65xx", CS_ARCH_MOS65XX, 0 }, + { "bpf", CS_ARCH_BPF, CS_MODE_LITTLE_ENDIAN | CS_MODE_BPF_CLASSIC }, + { "bpfbe", CS_ARCH_BPF, CS_MODE_BIG_ENDIAN | CS_MODE_BPF_CLASSIC }, + { "ebpf", CS_ARCH_BPF, CS_MODE_LITTLE_ENDIAN | CS_MODE_BPF_EXTENDED }, + { "ebpfbe", CS_ARCH_BPF, CS_MODE_BIG_ENDIAN | CS_MODE_BPF_EXTENDED }, { NULL } }; @@ -77,6 +81,7 @@ void print_insn_detail_m680x(csh handle, cs_insn *ins); void print_insn_detail_evm(csh handle, cs_insn *ins); void print_insn_detail_wasm(csh handle, cs_insn *ins); void print_insn_detail_mos65xx(csh handle, cs_insn *ins); +void print_insn_detail_bpf(csh handle, cs_insn *ins); static void print_details(csh handle, cs_arch arch, cs_mode md, cs_insn *ins); @@ -222,6 +227,13 @@ static void usage(char *prog) printf(" wasm: Web Assembly\n"); } + if (cs_support(CS_ARCH_BPF)) { + printf(" bpf Classic BPF\n"); + printf(" bpfbe Classic BPF + big endian\n"); + printf(" ebpf Extended BPF\n"); + printf(" ebpfbe Extended BPF + big endian\n"); + } + printf("\nExtra options:\n"); printf(" -d show detailed information of the instructions\n"); printf(" -u show immediates as unsigned\n"); @@ -274,6 +286,9 @@ static void print_details(csh handle, cs_arch arch, cs_mode md, cs_insn *ins) case CS_ARCH_MOS65XX: print_insn_detail_mos65xx(handle, ins); break; + case CS_ARCH_BPF: + print_insn_detail_bpf(handle, ins); + break; default: break; } diff --git a/cstool/cstool_bpf.c b/cstool/cstool_bpf.c new file mode 100644 index 0000000000..3d816e2821 --- /dev/null +++ b/cstool/cstool_bpf.c @@ -0,0 +1,79 @@ +#include + +#include + +static char * ext_name[] = { + [BPF_EXT_LEN] = "#len", +}; + +void print_insn_detail_bpf(csh handle, cs_insn *ins) +{ + cs_bpf *bpf; + 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; + + bpf = &(ins->detail->bpf); + + int i; + + printf("\tOperand count: %u\n", bpf->op_count); + + for (i = 0; i < bpf->op_count; i++) { + cs_bpf_op *op = &(bpf->operands[i]); + switch (op->type) { + case BPF_OP_INVALID: + printf("\t\toperands[%u].type: INVALID\n", i); + break; + case BPF_OP_REG: + printf("\t\toperands[%u].type: REG = %s\n", i, cs_reg_name(handle, op->reg)); + break; + case BPF_OP_IMM: + printf("\t\toperands[%u].type: IMM = 0x%lx\n", i, op->imm); + break; + case BPF_OP_OFF: + printf("\t\toperands[%u].type: OFF = +0x%x\n", i, op->off); + break; + case BPF_OP_MEM: + printf("\t\toperands[%u].type: MEM\n", i); + 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("\t\toperands[%u].type: MMEM = M[0x%x]\n", i, op->mmem); + break; + case BPF_OP_MSH: + printf("\t\toperands[%u].type: MSH = 4*([0x%x]&0xf)\n", i, op->msh); + break; + case BPF_OP_EXT: + printf("\t\toperands[%u].type: EXT = %s\n", i, ext_name[op->ext]); + break; + } + } + + /* print all registers that are involved in this instruction */ + 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"); + } + } +} diff --git a/tests/test_basic.c b/tests/test_basic.c index d87e9cccdd..8ee1536a14 100644 --- a/tests/test_basic.c +++ b/tests/test_basic.c @@ -91,7 +91,7 @@ static void test() #ifdef CAPSTONE_HAS_MOS65XX #define MOS65XX_CODE "\x0d\x34\x12\x00\x81\x65\x87\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" struct platform { cs_arch arch; @@ -339,6 +339,15 @@ static void test() 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 }; diff --git a/tests/test_detail.c b/tests/test_detail.c index 2c080a5558..ba8d157926 100644 --- a/tests/test_detail.c +++ b/tests/test_detail.c @@ -89,7 +89,7 @@ static void test() #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 @@ -283,6 +283,15 @@ static void test() 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 }; diff --git a/tests/test_iter.c b/tests/test_iter.c index f215ba9ecb..e2dd19fd4d 100644 --- a/tests/test_iter.c +++ b/tests/test_iter.c @@ -82,7 +82,7 @@ static void test() #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" struct platform platforms[] = { #ifdef CAPSTONE_HAS_X86 @@ -232,6 +232,15 @@ static void test() 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 }; From ae81e84adce98f33462baaa5593fa66f941b3588 Mon Sep 17 00:00:00 2001 From: david942j Date: Sun, 17 Feb 2019 00:54:36 -0800 Subject: [PATCH 27/35] Updated docs --- CREDITS.TXT | 1 + HACK.TXT | 1 + README.md | 2 +- 3 files changed, 3 insertions(+), 1 deletion(-) diff --git a/CREDITS.TXT b/CREDITS.TXT index a2ffc6ab9f..f0e8efc2ee 100644 --- a/CREDITS.TXT +++ b/CREDITS.TXT @@ -81,3 +81,4 @@ Tong Yu(Spike) & Kai Jern, Lau (xwings): WASM architecture. Sebastian Macke: MOS65XX architecture Ilya Leoshkevich: SystemZ architecture improvements. Do Minh Tuan: Regression testing tool (cstest) +david942j: BPF (both classic and extended) architecture. diff --git a/HACK.TXT b/HACK.TXT index a928621bd6..1183b4ebcb 100644 --- a/HACK.TXT +++ b/HACK.TXT @@ -7,6 +7,7 @@ Capstone source is organized as followings. ├── arch <- code handling disasm engine for each arch │   ├── AArch64 <- ARM64 (aka ARMv8) engine │   ├── ARM <- ARM engine +│   ├── BPF <- Berkeley Packet Filter engine │   ├── EVM <- Ethereum engine │   ├── M680X <- M680X engine │   ├── M68K <- M68K engine diff --git a/README.md b/README.md index 4d00fc572c..d189552334 100644 --- a/README.md +++ b/README.md @@ -12,7 +12,7 @@ disasm engine for binary analysis and reversing in the security community. Created by Nguyen Anh Quynh, then developed and maintained by a small community, Capstone offers some unparalleled features: -- Support multiple hardware architectures: ARM, ARM64 (ARMv8), Ethereum VM, Webassembly, M68K, +- Support multiple hardware architectures: ARM, ARM64 (ARMv8), BPF, Ethereum VM, Webassembly, M68K, Mips, MOS65XX, PPC, Sparc, SystemZ, TMS320C64X, M680X, XCore and X86 (including X86_64). - Having clean/simple/lightweight/intuitive architecture-neutral API. From cddecd6cb06c81063c0798b426ac246d6a1f444c Mon Sep 17 00:00:00 2001 From: david942j Date: Sun, 17 Feb 2019 02:17:38 -0800 Subject: [PATCH 28/35] Fix type of cs_bpf#operands --- arch/BPF/BPFInstPrinter.c | 8 ++------ include/capstone/bpf.h | 6 +++--- 2 files changed, 5 insertions(+), 9 deletions(-) diff --git a/arch/BPF/BPFInstPrinter.c b/arch/BPF/BPFInstPrinter.c index 030cefcd42..7bfc54073e 100644 --- a/arch/BPF/BPFInstPrinter.c +++ b/arch/BPF/BPFInstPrinter.c @@ -7,9 +7,8 @@ static cs_bpf_op *expand_bpf_operands(cs_bpf *bpf) { - bpf->op_count++; - bpf->operands = cs_mem_realloc(bpf->operands, bpf->op_count * sizeof(cs_bpf_op)); - return &bpf->operands[bpf->op_count - 1]; + /* assert(bpf->op_count < 3); */ + return &bpf->operands[bpf->op_count++]; } static void push_bpf_reg(cs_bpf *bpf, unsigned val, uint8_t ac_mode) { @@ -73,7 +72,6 @@ static void convert_operands(MCInst *MI, cs_bpf *bpf) unsigned i; bpf->op_count = 0; - bpf->operands = NULL; if (BPF_CLASS(opcode) == BPF_CLASS_LD || BPF_CLASS(opcode) == BPF_CLASS_LDX) { switch (BPF_MODE(opcode)) { case BPF_MODE_IMM: @@ -280,8 +278,6 @@ void BPF_printInst(MCInst *MI, struct SStream *O, void *PrinterInfo) #ifndef CAPSTONE_DIET if (MI->flat_insn->detail) { MI->flat_insn->detail->bpf = bpf; - return; } #endif - cs_mem_free(bpf.operands); } diff --git a/include/capstone/bpf.h b/include/capstone/bpf.h index d3a6048b69..81102fe98b 100644 --- a/include/capstone/bpf.h +++ b/include/capstone/bpf.h @@ -70,8 +70,8 @@ typedef struct cs_bpf_op { union { uint8_t reg; ///< register value for REG operand uint64_t imm; ///< immediate value IMM operand - uint32_t off; ///< offset value, used in jump class - bpf_op_mem mem; ///< base/index/scale/disp value for MEM operand + uint32_t off; ///< offset value, used in jump & call + bpf_op_mem mem; ///< base/disp value for MEM operand /* cBPF only */ uint32_t mmem; ///< M[k] in cBPF uint32_t msh; ///< corresponds to cBPF's BPF_MSH mode @@ -87,7 +87,7 @@ typedef struct cs_bpf_op { /// Instruction structure typedef struct cs_bpf { uint8_t op_count; - cs_bpf_op *operands; + cs_bpf_op operands[4]; } cs_bpf; /// BPF instruction From af37247900fa3db3d8f1cc9cc6777c1346b0c254 Mon Sep 17 00:00:00 2001 From: david942j Date: Sun, 17 Feb 2019 02:21:29 -0800 Subject: [PATCH 29/35] Implements python bindings --- bindings/Makefile | 4 + bindings/const_generator.py | 3 +- bindings/python/capstone/__init__.py | 25 ++++-- bindings/python/capstone/bpf.py | 69 ++++++++++++++++ bindings/python/capstone/bpf_const.py | 113 ++++++++++++++++++++++++++ bindings/python/test_bpf.py | 97 ++++++++++++++++++++++ tests/test_bpf.c | 10 +-- 7 files changed, 308 insertions(+), 13 deletions(-) create mode 100644 bindings/python/capstone/bpf.py create mode 100644 bindings/python/capstone/bpf_const.py create mode 100755 bindings/python/test_bpf.py diff --git a/bindings/Makefile b/bindings/Makefile index 1eb94d10dd..d22bb21f44 100644 --- a/bindings/Makefile +++ b/bindings/Makefile @@ -13,6 +13,7 @@ TEST_SPARC = $(TMPDIR)/test_sparc TEST_SYSZ = $(TMPDIR)/test_systemz TEST_X86 = $(TMPDIR)/test_x86 TEST_XCORE = $(TMPDIR)/test_xcore +TEST_BPF = $(TMPDIR)/test_bpf PYTHON2 = python @@ -42,6 +43,7 @@ expected: ../tests/test_systemz > $(TEST_SYSZ)_e ../tests/test_x86 > $(TEST_X86)_e ../tests/test_xcore > $(TEST_XCORE)_e + ../tests/test_bpf > $(TEST_BPF)_e python: FORCE cd python && $(MAKE) @@ -56,6 +58,7 @@ python: FORCE $(PYTHON2) python/test_systemz.py > $(TEST_SYSZ)_o $(PYTHON2) python/test_x86.py > $(TEST_X86)_o $(PYTHON2) python/test_xcore.py > $(TEST_XCORE)_o + $(PYTHON2) python/test_bpf.py > $(TEST_BPF)_o $(MAKE) test_diff java: FORCE @@ -85,6 +88,7 @@ test_diff: FORCE $(DIFF) $(TEST_SYSZ)_e $(TEST_SYSZ)_o $(DIFF) $(TEST_X86)_e $(TEST_X86)_o $(DIFF) $(TEST_XCORE)_e $(TEST_XCORE)_o + $(DIFF) $(TEST_BPF)_e $(TEST_BPF)_o clean: rm -rf $(TMPDIR) diff --git a/bindings/const_generator.py b/bindings/const_generator.py index d6a6fbf716..32baf9295c 100644 --- a/bindings/const_generator.py +++ b/bindings/const_generator.py @@ -5,7 +5,7 @@ INCL_DIR = '../include/capstone/' -include = [ 'arm.h', 'arm64.h', 'm68k.h', 'mips.h', 'x86.h', 'ppc.h', 'sparc.h', 'systemz.h', 'xcore.h', 'tms320c64x.h', 'm680x.h', 'evm.h', 'mos65xx.h', 'wasm.h' ] +include = [ 'arm.h', 'arm64.h', 'm68k.h', 'mips.h', 'x86.h', 'ppc.h', 'sparc.h', 'systemz.h', 'xcore.h', 'tms320c64x.h', 'm680x.h', 'evm.h', 'mos65xx.h', 'wasm.h', 'bpf.h' ] template = { 'java': { @@ -50,6 +50,7 @@ 'evm.h': 'evm', 'wasm.h': 'wasm', 'mos65xx.h': 'mos65xx', + 'bpf.h': 'bpf', 'comment_open': '#', 'comment_close': '', }, diff --git a/bindings/python/capstone/__init__.py b/bindings/python/capstone/__init__.py index d6fe46496f..a0d981ba03 100644 --- a/bindings/python/capstone/__init__.py +++ b/bindings/python/capstone/__init__.py @@ -36,6 +36,7 @@ 'CS_ARCH_TMS320C64X', 'CS_ARCH_M680X', 'CS_ARCH_EVM', + 'CS_ARCH_BPF', 'CS_ARCH_ALL', 'CS_MODE_LITTLE_ENDIAN', @@ -71,6 +72,8 @@ 'CS_MODE_M680X_6811', 'CS_MODE_M680X_CPU12', 'CS_MODE_M680X_HCS08', + 'CS_MODE_BPF_CLASSIC', + 'CS_MODE_BPF_EXTENDED', 'CS_OPT_SYNTAX', 'CS_OPT_SYNTAX_DEFAULT', @@ -153,7 +156,9 @@ CS_ARCH_M680X = 10 CS_ARCH_EVM = 11 CS_ARCH_MOS65XX = 12 -CS_ARCH_MAX = 13 +CS_ARCH_WASM = 13 +CS_ARCH_BPF = 14 +CS_ARCH_MAX = 15 CS_ARCH_ALL = 0xFFFF # disasm mode @@ -190,6 +195,8 @@ CS_MODE_M680X_6811 = (1 << 8) # M680X M68HC11 mode CS_MODE_M680X_CPU12 = (1 << 9) # M680X CPU12 mode CS_MODE_M680X_HCS08 = (1 << 10) # M680X HCS08 mode +CS_MODE_BPF_CLASSIC = 0 # Classic BPF mode (default) +CS_MODE_BPF_EXTENDED = 1 << 0 # Extended BPF mode # Capstone option type CS_OPT_SYNTAX = 1 # Intel X86 asm syntax (CS_ARCH_X86 arch) @@ -329,7 +336,7 @@ def copy_ctypes_list(src): return [copy_ctypes(n) for n in src] # Weird import placement because these modules are needed by the below code but need the above functions -from . import arm, arm64, m68k, mips, ppc, sparc, systemz, x86, xcore, tms320c64x, m680x, evm, mos65xx +from . import arm, arm64, m68k, mips, ppc, sparc, systemz, x86, xcore, tms320c64x, m680x, evm, mos65xx, bpf class _cs_arch(ctypes.Union): _fields_ = ( @@ -346,6 +353,7 @@ class _cs_arch(ctypes.Union): ('m680x', m680x.CsM680x), ('evm', evm.CsEvm), ('mos65xx', mos65xx.CsMOS65xx), + ('bpf', bpf.CsBPF), ) class _cs_detail(ctypes.Structure): @@ -662,6 +670,8 @@ def __gen_detail(self): (self.pop, self.push, self.fee) = evm.get_arch_info(self._raw.detail.contents.arch.evm) elif arch == CS_ARCH_MOS65XX: (self.am, self.modifies_flags, self.operands) = mos65xx.get_arch_info(self._raw.detail.contents.arch.mos65xx) + elif arch == CS_ARCH_BPF: + (self.operands) = bpf.get_arch_info(self._raw.detail.contents.arch.bpf) def __getattr__(self, name): @@ -1116,10 +1126,13 @@ def debug(): else: diet = "standard" - archs = { "arm": CS_ARCH_ARM, "arm64": CS_ARCH_ARM64, "m68k": CS_ARCH_M68K, \ - "mips": CS_ARCH_MIPS, "ppc": CS_ARCH_PPC, "sparc": CS_ARCH_SPARC, \ - "sysz": CS_ARCH_SYSZ, 'xcore': CS_ARCH_XCORE, "tms320c64x": CS_ARCH_TMS320C64X, \ - "m680x": CS_ARCH_M680X, 'evm': CS_ARCH_EVM, 'mos65xx': CS_ARCH_MOS65XX } + archs = { + "arm": CS_ARCH_ARM, "arm64": CS_ARCH_ARM64, "m68k": CS_ARCH_M68K, + "mips": CS_ARCH_MIPS, "ppc": CS_ARCH_PPC, "sparc": CS_ARCH_SPARC, + "sysz": CS_ARCH_SYSZ, 'xcore': CS_ARCH_XCORE, "tms320c64x": CS_ARCH_TMS320C64X, + "m680x": CS_ARCH_M680X, 'evm': CS_ARCH_EVM, 'mos65xx': CS_ARCH_MOS65XX, + 'bpf': CS_ARCH_BPF, + } all_archs = "" keys = archs.keys() diff --git a/bindings/python/capstone/bpf.py b/bindings/python/capstone/bpf.py new file mode 100644 index 0000000000..16f12c4afd --- /dev/null +++ b/bindings/python/capstone/bpf.py @@ -0,0 +1,69 @@ +# Capstone Python bindings of BPF +# By david942j , 2019 + +import ctypes +from . import copy_ctypes_list +from .bpf_const import * + +class BPFOpMem(ctypes.Structure): + _fields_ = ( + ('base', ctypes.c_uint8), + ('disp', ctypes.c_int32), + ) + +class BPFOpValue(ctypes.Union): + _fields_ = ( + ('reg', ctypes.c_uint8), + ('imm', ctypes.c_uint64), + ('off', ctypes.c_uint32), + ('mem', BPFOpMem), + ('mmem', ctypes.c_uint32), + ('msh', ctypes.c_uint32), + ('ext', ctypes.c_uint32), + ) + +class BPFOp(ctypes.Structure): + _fields_ = ( + ('type', ctypes.c_uint), + ('value', BPFOpValue), + ('access', ctypes.c_uint8), + ) + + @property + def reg(self): + return self.value.reg + + @property + def imm(self): + return self.value.imm + + @property + def off(self): + return self.value.off + + @property + def mem(self): + return self.value.mem + + @property + def mmem(self): + return self.value.mmem + + @property + def msh(self): + return self.value.msh + + @property + def ext(self): + return self.value.ext + + +class CsBPF(ctypes.Structure): + _fields_ = ( + ('op_count', ctypes.c_uint8), + ('operands', BPFOp * 4), + ) + +def get_arch_info(a): + return (copy_ctypes_list(a.operands[:a.op_count])) + diff --git a/bindings/python/capstone/bpf_const.py b/bindings/python/capstone/bpf_const.py new file mode 100644 index 0000000000..51dadb42ce --- /dev/null +++ b/bindings/python/capstone/bpf_const.py @@ -0,0 +1,113 @@ +# For Capstone Engine. AUTO-GENERATED FILE, DO NOT EDIT [bpf_const.py] + +BPF_OP_INVALID = 0 +BPF_OP_REG = 1 +BPF_OP_IMM = 2 +BPF_OP_OFF = 3 +BPF_OP_MEM = 4 +BPF_OP_MMEM = 5 +BPF_OP_MSH = 6 +BPF_OP_EXT = 7 + +BPF_REG_INVALID = 0 +BPF_REG_A = 1 +BPF_REG_X = 2 +BPF_REG_R0 = 3 +BPF_REG_R1 = 4 +BPF_REG_R2 = 5 +BPF_REG_R3 = 6 +BPF_REG_R4 = 7 +BPF_REG_R5 = 8 +BPF_REG_R6 = 9 +BPF_REG_R7 = 10 +BPF_REG_R8 = 11 +BPF_REG_R9 = 12 +BPF_REG_R10 = 13 +BPF_REG_ENDING = 14 + +BPF_EXT_INVALID = 0 +BPF_EXT_LEN = 1 + +BPF_INS_INVALID = 0 +BPF_INS_ADD = 1 +BPF_INS_SUB = 2 +BPF_INS_MUL = 3 +BPF_INS_DIV = 4 +BPF_INS_OR = 5 +BPF_INS_AND = 6 +BPF_INS_LSH = 7 +BPF_INS_RSH = 8 +BPF_INS_NEG = 9 +BPF_INS_MOD = 10 +BPF_INS_XOR = 11 +BPF_INS_MOV = 12 +BPF_INS_ARSH = 13 +BPF_INS_ADD64 = 14 +BPF_INS_SUB64 = 15 +BPF_INS_MUL64 = 16 +BPF_INS_DIV64 = 17 +BPF_INS_OR64 = 18 +BPF_INS_AND64 = 19 +BPF_INS_LSH64 = 20 +BPF_INS_RSH64 = 21 +BPF_INS_NEG64 = 22 +BPF_INS_MOD64 = 23 +BPF_INS_XOR64 = 24 +BPF_INS_MOV64 = 25 +BPF_INS_ARSH64 = 26 +BPF_INS_LE16 = 27 +BPF_INS_LE32 = 28 +BPF_INS_LE64 = 29 +BPF_INS_BE16 = 30 +BPF_INS_BE32 = 31 +BPF_INS_BE64 = 32 +BPF_INS_LDW = 33 +BPF_INS_LDH = 34 +BPF_INS_LDB = 35 +BPF_INS_LDDW = 36 +BPF_INS_LDXW = 37 +BPF_INS_LDXH = 38 +BPF_INS_LDXB = 39 +BPF_INS_LDXDW = 40 +BPF_INS_STW = 41 +BPF_INS_STH = 42 +BPF_INS_STB = 43 +BPF_INS_STDW = 44 +BPF_INS_STXW = 45 +BPF_INS_STXH = 46 +BPF_INS_STXB = 47 +BPF_INS_STXDW = 48 +BPF_INS_XADDW = 49 +BPF_INS_XADDDW = 50 +BPF_INS_JMP = 51 +BPF_INS_JEQ = 52 +BPF_INS_JGT = 53 +BPF_INS_JGE = 54 +BPF_INS_JSET = 55 +BPF_INS_JNE = 56 +BPF_INS_JSGT = 57 +BPF_INS_JSGE = 58 +BPF_INS_CALL = 59 +BPF_INS_EXIT = 60 +BPF_INS_JLT = 61 +BPF_INS_JLE = 62 +BPF_INS_JSLT = 63 +BPF_INS_JSLE = 64 +BPF_INS_RET = 65 +BPF_INS_TAX = 66 +BPF_INS_TXA = 67 +BPF_INS_ENDING = 68 +BPF_INS_LD = BPF_INS_LDW +BPF_INS_LDX = BPF_INS_LDXW +BPF_INS_ST = BPF_INS_STW +BPF_INS_STX = BPF_INS_STXW + +BPF_GRP_INVALID = 0 +BPF_GRP_LOAD = 1 +BPF_GRP_STORE = 2 +BPF_GRP_ALU = 3 +BPF_GRP_JUMP = 4 +BPF_GRP_CALL = 5 +BPF_GRP_RETURN = 6 +BPF_GRP_MISC = 7 +BPF_GRP_ENDING = 8 diff --git a/bindings/python/test_bpf.py b/bindings/python/test_bpf.py new file mode 100755 index 0000000000..77350db5de --- /dev/null +++ b/bindings/python/test_bpf.py @@ -0,0 +1,97 @@ +#!/usr/bin/env python + +# Capstone Python bindings test of BPF +# By david942j , 2019 + +from __future__ import print_function +from capstone import * +from capstone.bpf import * +from xprint import to_hex, to_x_32 + + +CBPF_CODE = b"\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" +EBPF_CODE = b"\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" + +all_tests = ( + (CS_ARCH_BPF, CS_MODE_LITTLE_ENDIAN | CS_MODE_BPF_CLASSIC, CBPF_CODE, "cBPF Le", None), + (CS_ARCH_BPF, CS_MODE_LITTLE_ENDIAN | CS_MODE_BPF_EXTENDED, EBPF_CODE, "eBPF Le", None), + ) + +ext_name = {} +ext_name[BPF_EXT_LEN] = '#len' + +def print_insn_detail(insn): + # print address, mnemonic and operands + print("0x%x:\t%s\t%s" % (insn.address, insn.mnemonic, insn.op_str)) + + # "data" instruction generated by SKIPDATA option has no detail + if insn.id == 0: + return + + if len(insn.groups) > 0: + print('\tGroups: ' + ' '.join(map(lambda g: insn.group_name(g), insn.groups))) + + print("\tOperand count: %u" % len(insn.operands)) + if len(insn.operands) > 0: + c = 0 + for i in insn.operands: + if i.type == BPF_OP_REG: + print("\t\toperands[%u].type: REG = %s" % (c, insn.reg_name(i.reg))) + if i.type == BPF_OP_IMM: + print("\t\toperands[%u].type: IMM = %s" % (c, hex(i.imm)[:-1])) + if i.type == BPF_OP_OFF: + print("\t\toperands[%u].type: OFF = +0x%s" % (c, to_x_32(i.off))) + if i.type == BPF_OP_MEM: + print("\t\toperands[%u].type: MEM" % c) + if i.mem.base != 0: + print("\t\t\toperands[%u].mem.base: REG = %s" \ + % (c, insn.reg_name(i.mem.base))) + print("\t\t\toperands[%u].mem.disp: 0x%s" \ + % (c, to_x_32(i.mem.disp))) + if i.type == BPF_OP_MMEM: + print("\t\toperands[%u].type: MMEM = 0x%s" % (c, to_x_32(i.mmem))) + if i.type == BPF_OP_MSH: + print("\t\toperands[%u].type: MSH = 4*([0x%s]&0xf)" % (c, to_x_32(i.msh))) + if i.type == BPF_OP_EXT: + print("\t\toperands[%u].type: EXT = %s" % (c, ext_name[i.ext])) + + c += 1 + + (regs_read, regs_write) = insn.regs_access() + + if len(regs_read) > 0: + print("\tRegisters read:", end="") + for r in regs_read: + print(" %s" %(insn.reg_name(r)), end="") + print("") + + if len(regs_write) > 0: + print("\tRegisters modified:", end="") + for r in regs_write: + print(" %s" %(insn.reg_name(r)), end="") + print("") + + +# ## Test class Cs +def test_class(): + + for (arch, mode, code, comment, syntax) in all_tests: + print("*" * 16) + print("Platform: %s" % comment) + print("Code: %s" % to_hex(code)) + print("Disasm:") + + try: + md = Cs(arch, mode) + if syntax is not None: + md.syntax = syntax + md.detail = True + for insn in md.disasm(code, 0x0): + print_insn_detail(insn) + print () + except CsError as e: + print("ERROR: %s" % e) + + +if __name__ == '__main__': + test_class() diff --git a/tests/test_bpf.c b/tests/test_bpf.c index d335cfd908..41b04bc9c5 100644 --- a/tests/test_bpf.c +++ b/tests/test_bpf.c @@ -20,7 +20,7 @@ static void print_string_hex(const char *comment, unsigned char *str, size_t len printf("%s", comment); for (c = str; c < str + len; c++) { - printf("0x%02x ", *c & 0xff); + printf(" 0x%02x", *c & 0xff); } printf("\n"); @@ -43,9 +43,9 @@ static void print_insn_detail(csh cs_handle, cs_insn *ins) if (ins->detail->groups_count) { int j; - printf("\tGroups: "); + printf("\tGroups:"); for(j = 0; j < ins->detail->groups_count; j++) { - printf("%s ", cs_group_name(handle, ins->detail->groups[j])); + printf(" %s", cs_group_name(handle, ins->detail->groups[j])); } printf("\n"); } @@ -110,6 +110,7 @@ static void print_insn_detail(csh cs_handle, cs_insn *ins) printf("\n"); } } + puts(""); } static void test() @@ -168,7 +169,6 @@ static void test() 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); @@ -180,8 +180,6 @@ static void test() abort(); } - printf("\n"); - cs_close(&handle); } } From 24936cacc9a3d61e81031809209c1c6e02caae70 Mon Sep 17 00:00:00 2001 From: david942j Date: Sun, 17 Feb 2019 04:20:38 -0800 Subject: [PATCH 30/35] Fix some bugs found by self code review --- arch/BPF/BPFDisassembler.c | 56 +++++++++-------------- arch/BPF/BPFInstPrinter.c | 78 +++++++++++++++++---------------- arch/BPF/BPFMapping.c | 6 +-- bindings/python/capstone/bpf.py | 4 +- bindings/python/test_bpf.py | 55 +++++++++++------------ cstool/cstool_bpf.c | 26 +++++------ include/capstone/bpf.h | 4 +- suite/cstest/include/helper.h | 2 - suite/cstest/src/bpf_detail.c | 24 +++++----- tests/test_bpf.c | 28 ++++++------ 10 files changed, 130 insertions(+), 153 deletions(-) diff --git a/arch/BPF/BPFDisassembler.c b/arch/BPF/BPFDisassembler.c index 4636c5eacd..15f727d7fe 100644 --- a/arch/BPF/BPFDisassembler.c +++ b/arch/BPF/BPFDisassembler.c @@ -72,7 +72,7 @@ static bpf_internal* fetch_ebpf(cs_struct *ud, const uint8_t *code, bpf->op = (uint16_t)code[0]; // eBPF has one 16-byte instruction: BPF_LD | BPF_DW | BPF_IMM, - // in this case imm is combined with next 8-byte block's imm. + // in this case imm is combined with the next block's imm. if (bpf->op == (BPF_CLASS_LD | BPF_SIZE_DW | BPF_MODE_IMM)) { if (code_len < 16) { cs_mem_free(bpf); @@ -117,7 +117,7 @@ static bool decodeLoad(cs_struct *ud, MCInst *MI, bpf_internal *bpf) * +-----+-----------+--------------------+ * | ldb | [k] | [x+k] | * | ldh | [k] | [x+k] | - * +-----+----+------+------+-----+-------+ + * +-----+-----------+--------------------+ */ if (BPF_SIZE(bpf->op) == BPF_SIZE_DW) return false; @@ -256,36 +256,12 @@ static bool decodeStore(cs_struct *ud, MCInst *MI, bpf_internal *bpf) static bool decodeALU(cs_struct *ud, MCInst *MI, bpf_internal *bpf) { - /* - * +----------------+--------+--------------------+ - * | 4 bits | 1 bit | 3 bits | - * | operation code | source | instruction class | - * +----------------+--------+--------------------+ - * (MSB) (LSB) - */ - - if (!EBPF_MODE(ud)) { - if (BPF_OP(bpf->op) > BPF_ALU_XOR) - return false; - } - else { - if (BPF_OP(bpf->op) > BPF_ALU_END) - return false; - } - - /* ALU64 class doesn't have ENDian */ - /* ENDian's imm must be one of 16, 32, 64 */ - if (BPF_OP(bpf->op) == BPF_ALU_END) { - if (BPF_CLASS(bpf->op) == BPF_CLASS_ALU64) - return false; - if (bpf->k != 16 && bpf->k != 32 && bpf->k != 64) - return false; - } - /* Set MI->Operands */ /* cBPF */ if (!EBPF_MODE(ud)) { + if (BPF_OP(bpf->op) > BPF_ALU_XOR) + return false; /* cBPF's NEG has no operands */ if (BPF_OP(bpf->op) == BPF_ALU_NEG) return true; @@ -298,6 +274,17 @@ static bool decodeALU(cs_struct *ud, MCInst *MI, bpf_internal *bpf) /* eBPF */ + if (BPF_OP(bpf->op) > BPF_ALU_END) + return false; + /* ALU64 class doesn't have ENDian */ + /* ENDian's imm must be one of 16, 32, 64 */ + if (BPF_OP(bpf->op) == BPF_ALU_END) { + if (BPF_CLASS(bpf->op) == BPF_CLASS_ALU64) + return false; + if (bpf->k != 16 && bpf->k != 32 && bpf->k != 64) + return false; + } + /* - op dst, imm * - op dst, src * - neg dst @@ -310,7 +297,7 @@ static bool decodeALU(cs_struct *ud, MCInst *MI, bpf_internal *bpf) if (BPF_OP(bpf->op) == BPF_ALU_NEG) return true; if (BPF_OP(bpf->op) == BPF_ALU_END) { - /* ENDian instructions use BPF_SRC to decide using little or big endian */ + /* bpf->k must be one of 16, 32, 64 */ MCInst_setOpcode(MI, MCInst_getOpcode(MI) | (bpf->k << 4)); return true; } @@ -408,7 +395,6 @@ static bool decodeMISC(cs_struct *ud, MCInst *MI, bpf_internal *bpf) static bool getInstruction(cs_struct *ud, MCInst *MI, bpf_internal *bpf) { cs_detail *detail; - uint8_t opcode; detail = MI->flat_insn->detail; // initialize detail @@ -416,12 +402,10 @@ static bool getInstruction(cs_struct *ud, MCInst *MI, bpf_internal *bpf) memset(detail, 0, offsetof(cs_detail, bpf) + sizeof(cs_bpf)); } - opcode = bpf->op; - MCInst_clear(MI); - MCInst_setOpcode(MI, opcode); + MCInst_setOpcode(MI, bpf->op); - switch (BPF_CLASS(opcode)) { + switch (BPF_CLASS(bpf->op)) { default: /* should never happen */ return false; case BPF_CLASS_LD: @@ -449,7 +433,7 @@ static bool getInstruction(cs_struct *ud, MCInst *MI, bpf_internal *bpf) } bool BPF_getInstruction(csh ud, const uint8_t *code, size_t code_len, - MCInst *instr, uint16_t *size, uint64_t _address, void *info) + MCInst *instr, uint16_t *size, uint64_t address, void *info) { cs_struct *cs; bpf_internal *bpf; @@ -461,7 +445,7 @@ bool BPF_getInstruction(csh ud, const uint8_t *code, size_t code_len, bpf = fetch_cbpf(cs, code, code_len); if (bpf == NULL) return false; - if (!getInstruction((cs_struct*)ud, instr, bpf)) { + if (!getInstruction(cs, instr, bpf)) { cs_mem_free(bpf); return false; } diff --git a/arch/BPF/BPFInstPrinter.c b/arch/BPF/BPFInstPrinter.c index 7bfc54073e..d304837145 100644 --- a/arch/BPF/BPFInstPrinter.c +++ b/arch/BPF/BPFInstPrinter.c @@ -1,6 +1,8 @@ /* Capstone Disassembly Engine */ /* BPF Backend by david942j , 2019 */ +#include + #include "BPFConstants.h" #include "BPFInstPrinter.h" #include "BPFMapping.h" @@ -11,7 +13,7 @@ static cs_bpf_op *expand_bpf_operands(cs_bpf *bpf) return &bpf->operands[bpf->op_count++]; } -static void push_bpf_reg(cs_bpf *bpf, unsigned val, uint8_t ac_mode) { +static void push_op_reg(cs_bpf *bpf, bpf_op_type val, uint8_t ac_mode) { cs_bpf_op *op = expand_bpf_operands(bpf); op->type = BPF_OP_REG; @@ -19,14 +21,14 @@ static void push_bpf_reg(cs_bpf *bpf, unsigned val, uint8_t ac_mode) { op->access = ac_mode; } -static void push_bpf_imm(cs_bpf *bpf, uint64_t val) { +static void push_op_imm(cs_bpf *bpf, uint64_t val) { cs_bpf_op *op = expand_bpf_operands(bpf); op->type = BPF_OP_IMM; op->imm = val; } -static void push_bpf_off(cs_bpf *bpf, uint32_t val) { +static void push_op_off(cs_bpf *bpf, uint32_t val) { cs_bpf_op *op = expand_bpf_operands(bpf); @@ -34,7 +36,7 @@ static void push_bpf_off(cs_bpf *bpf, uint32_t val) { op->off = val; } -static void push_bpf_mem(cs_bpf *bpf, bpf_reg reg, uint64_t val) { +static void push_op_mem(cs_bpf *bpf, bpf_reg reg, uint32_t val) { cs_bpf_op *op = expand_bpf_operands(bpf); op->type = BPF_OP_MEM; @@ -42,21 +44,21 @@ static void push_bpf_mem(cs_bpf *bpf, bpf_reg reg, uint64_t val) { op->mem.disp = val; } -static void push_bpf_mmem(cs_bpf *bpf, uint64_t val) { +static void push_op_mmem(cs_bpf *bpf, uint32_t val) { cs_bpf_op *op = expand_bpf_operands(bpf); op->type = BPF_OP_MMEM; op->mmem = val; } -static void push_bpf_msh(cs_bpf *bpf, uint64_t val) { +static void push_op_msh(cs_bpf *bpf, uint32_t val) { cs_bpf_op *op = expand_bpf_operands(bpf); op->type = BPF_OP_MSH; op->msh = val; } -static void push_bpf_ext(cs_bpf *bpf, bpf_ext_type val) { +static void push_op_ext(cs_bpf *bpf, bpf_ext_type val) { cs_bpf_op *op = expand_bpf_operands(bpf); op->type = BPF_OP_EXT; @@ -75,35 +77,35 @@ static void convert_operands(MCInst *MI, cs_bpf *bpf) if (BPF_CLASS(opcode) == BPF_CLASS_LD || BPF_CLASS(opcode) == BPF_CLASS_LDX) { switch (BPF_MODE(opcode)) { case BPF_MODE_IMM: - push_bpf_imm(bpf, (uint64_t)MCOperand_getImm(MCInst_getOperand(MI, 0))); + push_op_imm(bpf, MCOperand_getImm(MCInst_getOperand(MI, 0))); break; case BPF_MODE_ABS: op = MCInst_getOperand(MI, 0); - push_bpf_mem(bpf, BPF_REG_INVALID, (uint64_t)MCOperand_getImm(op)); + push_op_mem(bpf, BPF_REG_INVALID, MCOperand_getImm(op)); break; case BPF_MODE_IND: op = MCInst_getOperand(MI, 0); op2 = MCInst_getOperand(MI, 1); - push_bpf_mem(bpf, MCOperand_getReg(op), (uint64_t)MCOperand_getImm(op2)); + push_op_mem(bpf, MCOperand_getReg(op), MCOperand_getImm(op2)); break; case BPF_MODE_MEM: if (EBPF_MODE(MI->csh)) { /* ldx{w,h,b,dw} dst, [src+off] */ - push_bpf_reg(bpf, MCOperand_getReg(MCInst_getOperand(MI, 0)), CS_AC_WRITE); + push_op_reg(bpf, MCOperand_getReg(MCInst_getOperand(MI, 0)), CS_AC_WRITE); op = MCInst_getOperand(MI, 1); op2 = MCInst_getOperand(MI, 2); - push_bpf_mem(bpf, MCOperand_getReg(op), (uint64_t)MCOperand_getImm(op2)); + push_op_mem(bpf, MCOperand_getReg(op), MCOperand_getImm(op2)); } else { - push_bpf_mmem(bpf, (uint64_t)MCOperand_getImm(MCInst_getOperand(MI, 0))); + push_op_mmem(bpf, MCOperand_getImm(MCInst_getOperand(MI, 0))); } break; case BPF_MODE_LEN: - push_bpf_ext(bpf, BPF_EXT_LEN); + push_op_ext(bpf, BPF_EXT_LEN); break; case BPF_MODE_MSH: op = MCInst_getOperand(MI, 0); - push_bpf_msh(bpf, (uint64_t)MCOperand_getImm(op)); + push_op_msh(bpf, MCOperand_getImm(op)); break; /* case BPF_MODE_XADD: // not exists */ } @@ -112,7 +114,7 @@ static void convert_operands(MCInst *MI, cs_bpf *bpf) if (BPF_CLASS(opcode) == BPF_CLASS_ST || BPF_CLASS(opcode) == BPF_CLASS_STX) { if (!EBPF_MODE(MI->csh)) { // cBPF has only one case - st* M[k] - push_bpf_mmem(bpf, (uint64_t)MCOperand_getImm(MCInst_getOperand(MI, 0))); + push_op_mmem(bpf, MCOperand_getImm(MCInst_getOperand(MI, 0))); return; } /* eBPF has two cases: @@ -122,12 +124,12 @@ static void convert_operands(MCInst *MI, cs_bpf *bpf) */ op = MCInst_getOperand(MI, 0); op2 = MCInst_getOperand(MI, 1); - push_bpf_mem(bpf, MCOperand_getReg(op), (uint64_t)MCOperand_getImm(op2)); + push_op_mem(bpf, MCOperand_getReg(op), MCOperand_getImm(op2)); op = MCInst_getOperand(MI, 2); if (MCOperand_isImm(op)) - push_bpf_imm(bpf, (uint64_t)MCOperand_getImm(op)); + push_op_imm(bpf, MCOperand_getImm(op)); else if (MCOperand_isReg(op)) - push_bpf_reg(bpf, MCOperand_getReg(op), CS_AC_READ); + push_op_reg(bpf, MCOperand_getReg(op), CS_AC_READ); return; } @@ -146,12 +148,12 @@ static void convert_operands(MCInst *MI, cs_bpf *bpf) BPF_OP(opcode) == BPF_JUMP_CALL || (!EBPF_MODE(MI->csh) && i >= 1) || (EBPF_MODE(MI->csh) && i == 2)) - push_bpf_off(bpf, MCOperand_getImm(op)); + push_op_off(bpf, MCOperand_getImm(op)); else - push_bpf_imm(bpf, (uint64_t)MCOperand_getImm(op)); + push_op_imm(bpf, MCOperand_getImm(op)); } else if (MCOperand_isReg(op)) { - push_bpf_reg(bpf, MCOperand_getReg(op), CS_AC_READ); + push_op_reg(bpf, MCOperand_getReg(op), CS_AC_READ); } } return; @@ -162,9 +164,9 @@ static void convert_operands(MCInst *MI, cs_bpf *bpf) for (i = 0; i < mc_op_count; i++) { op = MCInst_getOperand(MI, i); if (MCOperand_isImm(op)) - push_bpf_imm(bpf, (uint64_t)MCOperand_getImm(op)); + push_op_imm(bpf, MCOperand_getImm(op)); else if (MCOperand_isReg(op)) - push_bpf_reg(bpf, MCOperand_getReg(op), CS_AC_READ); + push_op_reg(bpf, MCOperand_getReg(op), CS_AC_READ); } return; } @@ -173,26 +175,26 @@ static void convert_operands(MCInst *MI, cs_bpf *bpf) /* if (BPF_CLASS(opcode) == BPF_CLASS_ALU || BPF_CLASS(opcode) == BPF_CLASS_ALU64) */ /* We have three types: - * 1. {l,b}e dst // dst = byteswap(dst) - * 2. neg dst // dst = -dst - * 3. op dst, {src_reg, imm} // dst = dst op src + * 1. {l,b}e dst // dst = byteswap(dst) + * 2. neg dst // dst = -dst + * 3. dst, {src_reg, imm} // dst = dst src * so we can simply check the number of operands, - * only one operand means we are in case 1. and 2., + * exactly one operand means we are in case 1. and 2., * otherwise in case 3. */ if (mc_op_count == 1) { op = MCInst_getOperand(MI, 0); - push_bpf_reg(bpf, MCOperand_getReg(op), CS_AC_READ | CS_AC_WRITE); + push_op_reg(bpf, MCOperand_getReg(op), CS_AC_READ | CS_AC_WRITE); } else { // if (mc_op_count == 2) op = MCInst_getOperand(MI, 0); - push_bpf_reg(bpf, MCOperand_getReg(op), CS_AC_READ | CS_AC_WRITE); + push_op_reg(bpf, MCOperand_getReg(op), CS_AC_READ | CS_AC_WRITE); op = MCInst_getOperand(MI, 1); if (MCOperand_isImm(op)) - push_bpf_imm(bpf, (uint64_t)MCOperand_getImm(op)); + push_op_imm(bpf, MCOperand_getImm(op)); else if (MCOperand_isReg(op)) - push_bpf_reg(bpf, MCOperand_getReg(op), CS_AC_READ); + push_op_reg(bpf, MCOperand_getReg(op), CS_AC_READ); } } @@ -208,7 +210,7 @@ static void print_operand(MCInst *MI, struct SStream *O, const cs_bpf_op *op) SStream_concat(O, BPF_reg_name((csh)MI->csh, op->reg)); break; case BPF_OP_IMM: - sprintf(buf, "0x%lx", op->imm); + sprintf(buf, "0x%" PRIx64, op->imm); SStream_concat(O, buf); break; case BPF_OP_OFF: @@ -222,7 +224,7 @@ static void print_operand(MCInst *MI, struct SStream *O, const cs_bpf_op *op) if (op->mem.disp != 0) { if (op->mem.base != BPF_REG_INVALID) SStream_concat(O, "+"); - sprintf(buf, "%#x", op->mem.disp); + sprintf(buf, "0x%x", op->mem.disp); SStream_concat(O, buf); } if (op->mem.base == BPF_REG_INVALID && op->mem.disp == 0) // special case @@ -231,16 +233,16 @@ static void print_operand(MCInst *MI, struct SStream *O, const cs_bpf_op *op) break; case BPF_OP_MMEM: SStream_concat(O, "m["); - sprintf(buf, "0x%lx", op->imm); + sprintf(buf, "0x%x", op->mmem); SStream_concat(O, buf); SStream_concat(O, "]"); break; case BPF_OP_MSH: - sprintf(buf, "4*([0x%lx]&0xf)", op->imm); + sprintf(buf, "4*([0x%x]&0xf)", op->msh); SStream_concat(O, buf); break; case BPF_OP_EXT: - switch (op->imm) { + switch (op->ext) { case BPF_EXT_LEN: SStream_concat(O, "#len"); break; @@ -260,8 +262,8 @@ void BPF_printInst(MCInst *MI, struct SStream *O, void *PrinterInfo) cs_insn insn; cs_bpf bpf; - /* set pubOpcode */ insn.detail = NULL; + /* set pubOpcode as instruction id */ BPF_get_insn_id((cs_struct*)MI->csh, &insn, MCInst_getOpcode(MI)); MCInst_setOpcodePub(MI, insn.id); diff --git a/arch/BPF/BPFMapping.c b/arch/BPF/BPFMapping.c index b6b42b63b8..ee35def3ba 100644 --- a/arch/BPF/BPFMapping.c +++ b/arch/BPF/BPFMapping.c @@ -501,8 +501,6 @@ void BPF_reg_access(const cs_insn *insn, } } - sort_and_uniq(regs_read, read_count, &read_count); - sort_and_uniq(regs_write, write_count, &write_count); - *regs_read_count = read_count; - *regs_write_count = write_count; + sort_and_uniq(regs_read, read_count, regs_read_count); + sort_and_uniq(regs_write, write_count, regs_write_count); } diff --git a/bindings/python/capstone/bpf.py b/bindings/python/capstone/bpf.py index 16f12c4afd..d6263bd3e2 100644 --- a/bindings/python/capstone/bpf.py +++ b/bindings/python/capstone/bpf.py @@ -1,5 +1,5 @@ -# Capstone Python bindings of BPF -# By david942j , 2019 +# Capstone Python bindings +# BPF by david942j , 2019 import ctypes from . import copy_ctypes_list diff --git a/bindings/python/test_bpf.py b/bindings/python/test_bpf.py index 77350db5de..4df7f3599e 100755 --- a/bindings/python/test_bpf.py +++ b/bindings/python/test_bpf.py @@ -1,7 +1,7 @@ #!/usr/bin/env python -# Capstone Python bindings test of BPF -# By david942j , 2019 +# Capstone Python bindings +# BPF tests by david942j , 2019 from __future__ import print_function from capstone import * @@ -32,47 +32,42 @@ def print_insn_detail(insn): print('\tGroups: ' + ' '.join(map(lambda g: insn.group_name(g), insn.groups))) print("\tOperand count: %u" % len(insn.operands)) - if len(insn.operands) > 0: - c = 0 - for i in insn.operands: - if i.type == BPF_OP_REG: - print("\t\toperands[%u].type: REG = %s" % (c, insn.reg_name(i.reg))) - if i.type == BPF_OP_IMM: - print("\t\toperands[%u].type: IMM = %s" % (c, hex(i.imm)[:-1])) - if i.type == BPF_OP_OFF: - print("\t\toperands[%u].type: OFF = +0x%s" % (c, to_x_32(i.off))) - if i.type == BPF_OP_MEM: - print("\t\toperands[%u].type: MEM" % c) - if i.mem.base != 0: - print("\t\t\toperands[%u].mem.base: REG = %s" \ - % (c, insn.reg_name(i.mem.base))) - print("\t\t\toperands[%u].mem.disp: 0x%s" \ - % (c, to_x_32(i.mem.disp))) - if i.type == BPF_OP_MMEM: - print("\t\toperands[%u].type: MMEM = 0x%s" % (c, to_x_32(i.mmem))) - if i.type == BPF_OP_MSH: - print("\t\toperands[%u].type: MSH = 4*([0x%s]&0xf)" % (c, to_x_32(i.msh))) - if i.type == BPF_OP_EXT: - print("\t\toperands[%u].type: EXT = %s" % (c, ext_name[i.ext])) - - c += 1 + for c, op in enumerate(insn.operands): + print("\t\toperands[%u].type: " % c, end='') + if op.type == BPF_OP_REG: + print("REG = " + insn.reg_name(op.reg)) + elif op.type == BPF_OP_IMM: + print("IMM = " + hex(op.imm)[:-1]) + elif op.type == BPF_OP_OFF: + print("OFF = +0x" + to_x_32(op.off)) + elif op.type == BPF_OP_MEM: + print("MEM") + if op.mem.base != 0: + print("\t\t\toperands[%u].mem.base: REG = %s" \ + % (c, insn.reg_name(op.mem.base))) + print("\t\t\toperands[%u].mem.disp: 0x%s" \ + % (c, to_x_32(op.mem.disp))) + elif op.type == BPF_OP_MMEM: + print("MMEM = 0x" + to_x_32(op.mmem)) + elif op.type == BPF_OP_MSH: + print("MSH = 4*([0x%s]&0xf)" % to_x_32(op.msh)) + elif op.type == BPF_OP_EXT: + print("EXT = " + ext_name[op.ext]) (regs_read, regs_write) = insn.regs_access() if len(regs_read) > 0: print("\tRegisters read:", end="") for r in regs_read: - print(" %s" %(insn.reg_name(r)), end="") + print(" %s" % insn.reg_name(r), end="") print("") if len(regs_write) > 0: print("\tRegisters modified:", end="") for r in regs_write: - print(" %s" %(insn.reg_name(r)), end="") + print(" %s" % insn.reg_name(r), end="") print("") - -# ## Test class Cs def test_class(): for (arch, mode, code, comment, syntax) in all_tests: diff --git a/cstool/cstool_bpf.c b/cstool/cstool_bpf.c index 3d816e2821..c6c6f40f1f 100644 --- a/cstool/cstool_bpf.c +++ b/cstool/cstool_bpf.c @@ -1,6 +1,7 @@ #include #include +#include static char * ext_name[] = { [BPF_EXT_LEN] = "#len", @@ -18,40 +19,41 @@ void print_insn_detail_bpf(csh handle, cs_insn *ins) bpf = &(ins->detail->bpf); - int i; + unsigned i; 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("\t\toperands[%u].type: INVALID\n", i); + printf("INVALID\n"); break; case BPF_OP_REG: - printf("\t\toperands[%u].type: REG = %s\n", i, cs_reg_name(handle, op->reg)); + printf("REG = %s\n", cs_reg_name(handle, op->reg)); break; case BPF_OP_IMM: - printf("\t\toperands[%u].type: IMM = 0x%lx\n", i, op->imm); + printf("IMM = 0x%" PRIx64 "\n", op->imm); break; case BPF_OP_OFF: - printf("\t\toperands[%u].type: OFF = +0x%x\n", i, op->off); + printf("OFF = +0x%x\n", op->off); break; case BPF_OP_MEM: - printf("\t\toperands[%u].type: MEM\n", i); + 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("\t\toperands[%u].type: MMEM = M[0x%x]\n", i, op->mmem); + printf("MMEM = M[0x%x]\n", op->mmem); break; case BPF_OP_MSH: - printf("\t\toperands[%u].type: MSH = 4*([0x%x]&0xf)\n", i, op->msh); + printf("MSH = 4*([0x%x]&0xf)\n", op->msh); break; case BPF_OP_EXT: - printf("\t\toperands[%u].type: EXT = %s\n", i, ext_name[op->ext]); + printf("EXT = %s\n", ext_name[op->ext]); break; } } @@ -62,17 +64,15 @@ void print_insn_detail_bpf(csh handle, cs_insn *ins) regs_write, ®s_write_count)) { if (regs_read_count) { printf("\tRegisters read:"); - for(i = 0; i < regs_read_count; i++) { + 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++) { + for(i = 0; i < regs_write_count; i++) printf(" %s", cs_reg_name(handle, regs_write[i])); - } printf("\n"); } } diff --git a/include/capstone/bpf.h b/include/capstone/bpf.h index 81102fe98b..c2ccff6d05 100644 --- a/include/capstone/bpf.h +++ b/include/capstone/bpf.h @@ -48,7 +48,7 @@ typedef enum bpf_reg { BPF_REG_R9, BPF_REG_R10, - BPF_REG_ENDING, // <-- mark the end of the list or registers + BPF_REG_ENDING, } bpf_reg; /// Instruction's operand referring to memory @@ -198,7 +198,7 @@ typedef enum bpf_insn_group { BPF_GRP_RETURN, BPF_GRP_MISC, ///< cBPF only - BPF_GRP_ENDING, ///< <-- mark the end of the list of groups + BPF_GRP_ENDING, } bpf_insn_group; #ifdef __cplusplus diff --git a/suite/cstest/include/helper.h b/suite/cstest/include/helper.h index 8ef092732f..1022303857 100644 --- a/suite/cstest/include/helper.h +++ b/suite/cstest/include/helper.h @@ -17,8 +17,6 @@ #define X86_32 1 #define X86_64 2 -#define ARR_SIZE(a) (sizeof(a)/sizeof(a[0])) - char **split(char *str, char *delim, int *size); void print_strs(char **list_str, int size); void free_strs(char **list_str, int size); diff --git a/suite/cstest/src/bpf_detail.c b/suite/cstest/src/bpf_detail.c index 553b08b3b7..d72332f79a 100644 --- a/suite/cstest/src/bpf_detail.c +++ b/suite/cstest/src/bpf_detail.c @@ -1,6 +1,8 @@ /* Capstone testing regression */ /* By david942j , 2019 */ +#include + #include "factory.h" static char * ext_name[] = { @@ -10,7 +12,7 @@ static char * ext_name[] = { char *get_detail_bpf(csh *handle, cs_mode mode, cs_insn *ins) { cs_bpf *bpf; - int i; + unsigned int i; cs_regs regs_read, regs_write; uint8_t regs_read_count, regs_write_count; char *result; @@ -26,31 +28,32 @@ char *get_detail_bpf(csh *handle, cs_mode mode, cs_insn *ins) add_str(&result, " ; op_count: %u", bpf->op_count); for (i = 0; i < bpf->op_count; i++) { cs_bpf_op *op = &(bpf->operands[i]); + add_str(&result, " ; operands[%u].type: ", i); switch (op->type) { case BPF_OP_INVALID: - add_str(&result, " ; operands[%u].type: INVALID", i); + add_str(&result, "INVALID"); break; case BPF_OP_REG: - add_str(&result, " ; operands[%u].type: REG = %s", i, cs_reg_name(*handle, op->reg)); + add_str(&result, "REG = %s", cs_reg_name(*handle, op->reg)); break; case BPF_OP_IMM: - add_str(&result, " ; operands[%u].type: IMM = 0x%lx", i, op->imm); + add_str(&result, "IMM = 0x%" PRIx64, op->imm); break; case BPF_OP_OFF: - add_str(&result, " ; operands[%u].type: OFF = +0x%x", i, op->off); + add_str(&result, "OFF = +0x%x", op->off); break; case BPF_OP_MEM: - add_str(&result, " ; operands[%u].type: MEM [base=%s, disp=0x%x]", - i, cs_reg_name(*handle, op->mem.base), op->mem.disp); + add_str(&result, "MEM [base=%s, disp=0x%x]", + cs_reg_name(*handle, op->mem.base), op->mem.disp); break; case BPF_OP_MMEM: - add_str(&result, " ; operands[%u].type: MMEM = M[0x%x]", i, op->mmem); + add_str(&result, "MMEM = M[0x%x]", op->mmem); break; case BPF_OP_MSH: - add_str(&result, " ; operands[%u].type: MSH = 4*([0x%x]&0xf)", i, op->msh); + add_str(&result, "MSH = 4*([0x%x]&0xf)", op->msh); break; case BPF_OP_EXT: - add_str(&result, " ; operands[%u].type: EXT = %s", i, ext_name[op->ext]); + add_str(&result, "EXT = %s", ext_name[op->ext]); break; } } @@ -62,7 +65,6 @@ char *get_detail_bpf(csh *handle, cs_mode mode, cs_insn *ins) add_str(&result, " ; Registers read:"); for(i = 0; i < regs_read_count; i++) add_str(&result, " %s", cs_reg_name(*handle, regs_read[i])); - printf("\n"); } if (regs_write_count) { diff --git a/tests/test_bpf.c b/tests/test_bpf.c index 41b04bc9c5..f4bc15f293 100644 --- a/tests/test_bpf.c +++ b/tests/test_bpf.c @@ -52,40 +52,40 @@ static void print_insn_detail(csh cs_handle, cs_insn *ins) bpf = &(ins->detail->bpf); - int i; + unsigned i; 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("\t\toperands[%u].type: INVALID\n", i); + printf("INVALID\n"); break; case BPF_OP_REG: - printf("\t\toperands[%u].type: REG = %s\n", i, cs_reg_name(cs_handle, op->reg)); + printf("REG = %s\n", cs_reg_name(handle, op->reg)); break; case BPF_OP_IMM: - printf("\t\toperands[%u].type: IMM = 0x%lx\n", i, op->imm); + printf("IMM = 0x%" PRIx64 "\n", op->imm); break; case BPF_OP_OFF: - printf("\t\toperands[%u].type: OFF = +0x%x\n", i, op->off); + printf("OFF = +0x%x\n", op->off); break; case BPF_OP_MEM: - printf("\t\toperands[%u].type: MEM\n", i); + printf("MEM\n"); if (op->mem.base != BPF_REG_INVALID) printf("\t\t\toperands[%u].mem.base: REG = %s\n", - i, cs_reg_name(cs_handle, op->mem.base)); + 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("\t\toperands[%u].type: MMEM = M[0x%x]\n", i, op->mmem); + printf("MMEM = M[0x%x]\n", op->mmem); break; case BPF_OP_MSH: - printf("\t\toperands[%u].type: MSH = 4*([0x%x]&0xf)\n", i, op->msh); + printf("MSH = 4*([0x%x]&0xf)\n", op->msh); break; case BPF_OP_EXT: - printf("\t\toperands[%u].type: EXT = %s\n", i, ext_name[op->ext]); + printf("EXT = %s\n", ext_name[op->ext]); break; } } @@ -96,17 +96,15 @@ static void print_insn_detail(csh cs_handle, cs_insn *ins) regs_write, ®s_write_count)) { if (regs_read_count) { printf("\tRegisters read:"); - for(i = 0; i < regs_read_count; i++) { + 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++) { + for(i = 0; i < regs_write_count; i++) printf(" %s", cs_reg_name(cs_handle, regs_write[i])); - } printf("\n"); } } From 192fadfa47d1226027819767cee2f8062c736c41 Mon Sep 17 00:00:00 2001 From: david942j Date: Sun, 17 Feb 2019 04:26:53 -0800 Subject: [PATCH 31/35] Remove dummy tests --- suite/MC/BPF/classic-be.cs | 8 ++++++++ suite/MC/BPF/classic.cs | 10 ---------- suite/MC/BPF/extended.cs | 15 --------------- 3 files changed, 8 insertions(+), 25 deletions(-) create mode 100644 suite/MC/BPF/classic-be.cs delete mode 100644 suite/MC/BPF/classic.cs delete mode 100644 suite/MC/BPF/extended.cs diff --git a/suite/MC/BPF/classic-be.cs b/suite/MC/BPF/classic-be.cs new file mode 100644 index 0000000000..b7578ca88b --- /dev/null +++ b/suite/MC/BPF/classic-be.cs @@ -0,0 +1,8 @@ +# CS_ARCH_BPF, CS_MODE_BIG_ENDIAN+CS_MODE_BPF_CLASSIC, None +0x00,0x01,0x00,0x00,0x33,0x00,0x0c,0x11 = ldx 0x33000c11 +0x00,0x80,0x00,0x00,0x00,0x00,0x00,0x00 = ld #len +0x00,0xa1,0x00,0x00,0x10,0x00,0x00,0x00 = ldx 4*([0x10000000]&0xf) +0x00,0x60,0x00,0x00,0x09,0x00,0x00,0x00 = ld m[0x9000000] +0x00,0x30,0x00,0x00,0x37,0x13,0x03,0x00 = ldb [0x37130300] +0x00,0x63,0x00,0x00,0x0f,0x00,0x30,0x00 = stx m[0xf003000] +0x00,0x84,0x00,0x00,0x00,0x00,0x00,0x00 = neg diff --git a/suite/MC/BPF/classic.cs b/suite/MC/BPF/classic.cs deleted file mode 100644 index 6dfa27ad0a..0000000000 --- a/suite/MC/BPF/classic.cs +++ /dev/null @@ -1,10 +0,0 @@ -# CS_ARCH_BPF, CS_MODE_LITTLE_ENDIAN+CS_MODE_BPF_CLASSIC, None -0x01,0x00,0x00,0x00,0x33,0x00,0x00,0x00 = ldx 0x33 -0x80,0x00,0x00,0x00,0x00,0x00,0x00,0x00 = ld #len -0xa1,0x00,0x00,0x00,0x10,0x00,0x00,0x00 = ldx 4*([0x10]&0xf) -0x60,0x00,0x00,0x00,0x09,0x00,0x00,0x00 = ld m[0x9] -0x30,0x00,0x00,0x00,0x37,0x13,0x03,0x00 = ldb [0x31337] -0x48,0x00,0x00,0x00,0x09,0x00,0x00,0x00 = ldh [x+0x9] -0x62,0x00,0x00,0x00,0x03,0x00,0x00,0x00 = st m[0x3] -0x63,0x00,0x00,0x00,0x0f,0x00,0x00,0x00 = stx m[0xf] -0x84,0x00,0x00,0x00,0x00,0x00,0x00,0x00 = neg diff --git a/suite/MC/BPF/extended.cs b/suite/MC/BPF/extended.cs deleted file mode 100644 index c512a335bc..0000000000 --- a/suite/MC/BPF/extended.cs +++ /dev/null @@ -1,15 +0,0 @@ -# CS_ARCH_BPF, CS_MODE_LITTLE_ENDIAN+CS_MODE_BPF_EXTENDED, None -0x30,0x00,0x00,0x00,0x00,0x00,0x00,0x00 = ldb [0x0] -0x28,0x00,0x00,0x00,0xfa,0x00,0x00,0xff = ldh [0xff0000fa] -0x40,0x10,0x00,0x00,0xcc,0x00,0x00,0x00 = ldw [r1+0xcc] -0x18,0x00,0x00,0x00,0x0c,0xb0,0xce,0xfa,0x00,0x00,0x00,0x00,0xef,0xbe,0xad,0xde = lddw 0xdeadbeeffaceb00c -0x71,0x13,0x11,0x00,0x00,0x00,0x00,0x00 = ldxb r3, [r1+0x11] -0x94,0x09,0x00,0x00,0x37,0x13,0x03,0x00 = mod r9, 0x31337 -0x84,0x03,0x00,0x00,0x00,0x00,0x00,0x00 = neg r3 -0x87,0x00,0x00,0x00,0x00,0x00,0x00,0x00 = neg64 r0 -0xdc,0x02,0x00,0x00,0x20,0x00,0x00,0x00 = be32 r2 -0x05,0x00,0x08,0x00,0x00,0x00,0x00,0x00 = jmp +0x8 -0xdd,0x35,0x30,0x00,0x00,0x00,0x00,0x00 = jsle r5, r3, +0x30 -0xa5,0x35,0x30,0x00,0x10,0x00,0x00,0x00 = jlt r5, 0x10, +0x30 -0xc3,0x12,0x00,0x10,0x00,0x00,0x00,0x00 = xaddw [r2+0x1000], r1 -0xdb,0xa9,0x00,0x01,0x00,0x00,0x00,0x00 = xadddw [r9+0x100], r10 From 7eeecc9589d8ef47db9d3efef1f3e80669311c50 Mon Sep 17 00:00:00 2001 From: david942j Date: Sun, 17 Feb 2019 04:38:11 -0800 Subject: [PATCH 32/35] remove typeof --- arch/BPF/BPFMapping.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/BPF/BPFMapping.c b/arch/BPF/BPFMapping.c index ee35def3ba..33fae2c624 100644 --- a/arch/BPF/BPFMapping.c +++ b/arch/BPF/BPFMapping.c @@ -439,7 +439,7 @@ static void sort_and_uniq(cs_regs arr, uint8_t n, uint8_t *new_n) int i; int j; int iMin; - typeof(arr[0]) tmp; + int tmp; /* a modified selection sort for sorting and making unique */ for (j = 0; j < n; j++) { From 6af3a6021a62d218e34e34aa6179a4e8b28695bc Mon Sep 17 00:00:00 2001 From: david942j Date: Sun, 17 Feb 2019 04:52:36 -0800 Subject: [PATCH 33/35] Address comments --- arch/BPF/BPFInstPrinter.c | 22 ++++++++++++++-------- arch/BPF/BPFModule.c | 3 +-- cstool/cstool_bpf.c | 7 ++++--- tests/test_bpf.c | 16 +++++++--------- 4 files changed, 26 insertions(+), 22 deletions(-) diff --git a/arch/BPF/BPFInstPrinter.c b/arch/BPF/BPFInstPrinter.c index d304837145..6933a78bc5 100644 --- a/arch/BPF/BPFInstPrinter.c +++ b/arch/BPF/BPFInstPrinter.c @@ -13,7 +13,8 @@ static cs_bpf_op *expand_bpf_operands(cs_bpf *bpf) return &bpf->operands[bpf->op_count++]; } -static void push_op_reg(cs_bpf *bpf, bpf_op_type val, uint8_t ac_mode) { +static void push_op_reg(cs_bpf *bpf, bpf_op_type val, uint8_t ac_mode) +{ cs_bpf_op *op = expand_bpf_operands(bpf); op->type = BPF_OP_REG; @@ -21,22 +22,24 @@ static void push_op_reg(cs_bpf *bpf, bpf_op_type val, uint8_t ac_mode) { op->access = ac_mode; } -static void push_op_imm(cs_bpf *bpf, uint64_t val) { +static void push_op_imm(cs_bpf *bpf, uint64_t val) +{ cs_bpf_op *op = expand_bpf_operands(bpf); op->type = BPF_OP_IMM; op->imm = val; } -static void push_op_off(cs_bpf *bpf, uint32_t val) { - +static void push_op_off(cs_bpf *bpf, uint32_t val) +{ cs_bpf_op *op = expand_bpf_operands(bpf); op->type = BPF_OP_OFF; op->off = val; } -static void push_op_mem(cs_bpf *bpf, bpf_reg reg, uint32_t val) { +static void push_op_mem(cs_bpf *bpf, bpf_reg reg, uint32_t val) +{ cs_bpf_op *op = expand_bpf_operands(bpf); op->type = BPF_OP_MEM; @@ -44,21 +47,24 @@ static void push_op_mem(cs_bpf *bpf, bpf_reg reg, uint32_t val) { op->mem.disp = val; } -static void push_op_mmem(cs_bpf *bpf, uint32_t val) { +static void push_op_mmem(cs_bpf *bpf, uint32_t val) +{ cs_bpf_op *op = expand_bpf_operands(bpf); op->type = BPF_OP_MMEM; op->mmem = val; } -static void push_op_msh(cs_bpf *bpf, uint32_t val) { +static void push_op_msh(cs_bpf *bpf, uint32_t val) +{ cs_bpf_op *op = expand_bpf_operands(bpf); op->type = BPF_OP_MSH; op->msh = val; } -static void push_op_ext(cs_bpf *bpf, bpf_ext_type val) { +static void push_op_ext(cs_bpf *bpf, bpf_ext_type val) +{ cs_bpf_op *op = expand_bpf_operands(bpf); op->type = BPF_OP_EXT; diff --git a/arch/BPF/BPFModule.c b/arch/BPF/BPFModule.c index 9ad9461585..d744b827ad 100644 --- a/arch/BPF/BPFModule.c +++ b/arch/BPF/BPFModule.c @@ -25,9 +25,8 @@ cs_err BPF_global_init(cs_struct *ud) cs_err BPF_option(cs_struct *handle, cs_opt_type type, size_t value) { - if (type == CS_OPT_MODE) { + if (type == CS_OPT_MODE) handle->mode = (cs_mode)value; - } return CS_ERR_OK; } diff --git a/cstool/cstool_bpf.c b/cstool/cstool_bpf.c index c6c6f40f1f..879f45fef6 100644 --- a/cstool/cstool_bpf.c +++ b/cstool/cstool_bpf.c @@ -3,12 +3,15 @@ #include #include -static char * ext_name[] = { +static const char * ext_name[] = { [BPF_EXT_LEN] = "#len", }; +void print_insn_detail_bpf(csh handle, cs_insn *ins); + void print_insn_detail_bpf(csh handle, cs_insn *ins) { + unsigned i; cs_bpf *bpf; cs_regs regs_read, regs_write; uint8_t regs_read_count, regs_write_count; @@ -19,8 +22,6 @@ void print_insn_detail_bpf(csh handle, cs_insn *ins) bpf = &(ins->detail->bpf); - unsigned i; - printf("\tOperand count: %u\n", bpf->op_count); for (i = 0; i < bpf->op_count; i++) { diff --git a/tests/test_bpf.c b/tests/test_bpf.c index f4bc15f293..b97e330cbf 100644 --- a/tests/test_bpf.c +++ b/tests/test_bpf.c @@ -9,14 +9,14 @@ static csh handle; struct platform { cs_arch arch; cs_mode mode; - unsigned char *code; + const unsigned char *code; size_t size; - char *comment; + const char *comment; }; -static void print_string_hex(const char *comment, unsigned char *str, size_t len) +static void print_string_hex(const char *comment, const unsigned char *str, size_t len) { - unsigned char *c; + const unsigned char *c; printf("%s", comment); for (c = str; c < str + len; c++) { @@ -26,7 +26,7 @@ static void print_string_hex(const char *comment, unsigned char *str, size_t len printf("\n"); } -static char * ext_name[] = { +static const char * ext_name[] = { [BPF_EXT_LEN] = "#len", }; @@ -35,6 +35,7 @@ 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) @@ -44,16 +45,13 @@ static void print_insn_detail(csh cs_handle, cs_insn *ins) int j; printf("\tGroups:"); - for(j = 0; j < ins->detail->groups_count; j++) { + 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); - unsigned i; - printf("\tOperand count: %u\n", bpf->op_count); for (i = 0; i < bpf->op_count; i++) { cs_bpf_op *op = &(bpf->operands[i]); From e489d00779264cd679360cdf5922fb0ba73ba7c0 Mon Sep 17 00:00:00 2001 From: david942j Date: Sun, 17 Feb 2019 05:33:32 -0800 Subject: [PATCH 34/35] Fix MSVC's warnings and add test_bpf.py to bindings/python/Makefile --- arch/BPF/BPFDisassembler.c | 2 +- arch/BPF/BPFInstPrinter.c | 35 +++++++++++++---------------------- bindings/python/Makefile | 2 +- 3 files changed, 15 insertions(+), 24 deletions(-) diff --git a/arch/BPF/BPFDisassembler.c b/arch/BPF/BPFDisassembler.c index 15f727d7fe..5c0f44be0c 100644 --- a/arch/BPF/BPFDisassembler.c +++ b/arch/BPF/BPFDisassembler.c @@ -298,7 +298,7 @@ static bool decodeALU(cs_struct *ud, MCInst *MI, bpf_internal *bpf) return true; if (BPF_OP(bpf->op) == BPF_ALU_END) { /* bpf->k must be one of 16, 32, 64 */ - MCInst_setOpcode(MI, MCInst_getOpcode(MI) | (bpf->k << 4)); + MCInst_setOpcode(MI, MCInst_getOpcode(MI) | ((uint32_t)bpf->k << 4)); return true; } diff --git a/arch/BPF/BPFInstPrinter.c b/arch/BPF/BPFInstPrinter.c index 6933a78bc5..2476ca555d 100644 --- a/arch/BPF/BPFInstPrinter.c +++ b/arch/BPF/BPFInstPrinter.c @@ -87,12 +87,12 @@ static void convert_operands(MCInst *MI, cs_bpf *bpf) break; case BPF_MODE_ABS: op = MCInst_getOperand(MI, 0); - push_op_mem(bpf, BPF_REG_INVALID, MCOperand_getImm(op)); + push_op_mem(bpf, BPF_REG_INVALID, (uint32_t)MCOperand_getImm(op)); break; case BPF_MODE_IND: op = MCInst_getOperand(MI, 0); op2 = MCInst_getOperand(MI, 1); - push_op_mem(bpf, MCOperand_getReg(op), MCOperand_getImm(op2)); + push_op_mem(bpf, MCOperand_getReg(op), (uint32_t)MCOperand_getImm(op2)); break; case BPF_MODE_MEM: if (EBPF_MODE(MI->csh)) { @@ -100,10 +100,10 @@ static void convert_operands(MCInst *MI, cs_bpf *bpf) push_op_reg(bpf, MCOperand_getReg(MCInst_getOperand(MI, 0)), CS_AC_WRITE); op = MCInst_getOperand(MI, 1); op2 = MCInst_getOperand(MI, 2); - push_op_mem(bpf, MCOperand_getReg(op), MCOperand_getImm(op2)); + push_op_mem(bpf, MCOperand_getReg(op), (uint32_t)MCOperand_getImm(op2)); } else { - push_op_mmem(bpf, MCOperand_getImm(MCInst_getOperand(MI, 0))); + push_op_mmem(bpf, (uint32_t)MCOperand_getImm(MCInst_getOperand(MI, 0))); } break; case BPF_MODE_LEN: @@ -111,7 +111,7 @@ static void convert_operands(MCInst *MI, cs_bpf *bpf) break; case BPF_MODE_MSH: op = MCInst_getOperand(MI, 0); - push_op_msh(bpf, MCOperand_getImm(op)); + push_op_msh(bpf, (uint32_t)MCOperand_getImm(op)); break; /* case BPF_MODE_XADD: // not exists */ } @@ -120,7 +120,7 @@ static void convert_operands(MCInst *MI, cs_bpf *bpf) if (BPF_CLASS(opcode) == BPF_CLASS_ST || BPF_CLASS(opcode) == BPF_CLASS_STX) { if (!EBPF_MODE(MI->csh)) { // cBPF has only one case - st* M[k] - push_op_mmem(bpf, MCOperand_getImm(MCInst_getOperand(MI, 0))); + push_op_mmem(bpf, (uint32_t)MCOperand_getImm(MCInst_getOperand(MI, 0))); return; } /* eBPF has two cases: @@ -130,7 +130,7 @@ static void convert_operands(MCInst *MI, cs_bpf *bpf) */ op = MCInst_getOperand(MI, 0); op2 = MCInst_getOperand(MI, 1); - push_op_mem(bpf, MCOperand_getReg(op), MCOperand_getImm(op2)); + push_op_mem(bpf, MCOperand_getReg(op), (uint32_t)MCOperand_getImm(op2)); op = MCInst_getOperand(MI, 2); if (MCOperand_isImm(op)) push_op_imm(bpf, MCOperand_getImm(op)); @@ -154,7 +154,7 @@ static void convert_operands(MCInst *MI, cs_bpf *bpf) BPF_OP(opcode) == BPF_JUMP_CALL || (!EBPF_MODE(MI->csh) && i >= 1) || (EBPF_MODE(MI->csh) && i == 2)) - push_op_off(bpf, MCOperand_getImm(op)); + push_op_off(bpf, (uint32_t)MCOperand_getImm(op)); else push_op_imm(bpf, MCOperand_getImm(op)); } @@ -206,8 +206,6 @@ static void convert_operands(MCInst *MI, cs_bpf *bpf) static void print_operand(MCInst *MI, struct SStream *O, const cs_bpf_op *op) { - char buf[32]; - switch (op->type) { case BPF_OP_INVALID: SStream_concat(O, "invalid"); @@ -216,12 +214,10 @@ static void print_operand(MCInst *MI, struct SStream *O, const cs_bpf_op *op) SStream_concat(O, BPF_reg_name((csh)MI->csh, op->reg)); break; case BPF_OP_IMM: - sprintf(buf, "0x%" PRIx64, op->imm); - SStream_concat(O, buf); + SStream_concat(O, "0x%" PRIx64, op->imm); break; case BPF_OP_OFF: - sprintf(buf, "+0x%x", op->off); - SStream_concat(O, buf); + SStream_concat(O, "+0x%x", op->off); break; case BPF_OP_MEM: SStream_concat(O, "["); @@ -230,22 +226,17 @@ static void print_operand(MCInst *MI, struct SStream *O, const cs_bpf_op *op) if (op->mem.disp != 0) { if (op->mem.base != BPF_REG_INVALID) SStream_concat(O, "+"); - sprintf(buf, "0x%x", op->mem.disp); - SStream_concat(O, buf); + SStream_concat(O, "0x%x", op->mem.disp); } if (op->mem.base == BPF_REG_INVALID && op->mem.disp == 0) // special case SStream_concat(O, "0x0"); SStream_concat(O, "]"); break; case BPF_OP_MMEM: - SStream_concat(O, "m["); - sprintf(buf, "0x%x", op->mmem); - SStream_concat(O, buf); - SStream_concat(O, "]"); + SStream_concat(O, "m[0x%x]", op->mmem); break; case BPF_OP_MSH: - sprintf(buf, "4*([0x%x]&0xf)", op->msh); - SStream_concat(O, buf); + SStream_concat(O, "4*([0x%x]&0xf)", op->msh); break; case BPF_OP_EXT: switch (op->ext) { diff --git a/bindings/python/Makefile b/bindings/python/Makefile index 45c8468b6b..8907f9e2e1 100644 --- a/bindings/python/Makefile +++ b/bindings/python/Makefile @@ -70,7 +70,7 @@ clean: TESTS = test_basic.py test_detail.py test_arm.py test_arm64.py test_m68k.py test_mips.py TESTS += test_ppc.py test_sparc.py test_systemz.py test_x86.py test_xcore.py test_tms320c64x.py -TESTS += test_m680x.py test_skipdata.py test_mos65xx.py +TESTS += test_m680x.py test_skipdata.py test_mos65xx.py test_bpf.py check: @for t in $(TESTS); do \ From 5ce04b9b487df67eb971118eb261c101fe1508f4 Mon Sep 17 00:00:00 2001 From: david942j Date: Sun, 17 Feb 2019 20:02:51 -0800 Subject: [PATCH 35/35] Fix: call is not offset --- arch/BPF/BPFDisassembler.c | 3 +-- arch/BPF/BPFInstPrinter.c | 6 ++---- suite/MC/BPF/extended-all.cs | 2 +- 3 files changed, 4 insertions(+), 7 deletions(-) diff --git a/arch/BPF/BPFDisassembler.c b/arch/BPF/BPFDisassembler.c index 5c0f44be0c..cea4752368 100644 --- a/arch/BPF/BPFDisassembler.c +++ b/arch/BPF/BPFDisassembler.c @@ -337,9 +337,8 @@ static bool decodeJump(cs_struct *ud, MCInst *MI, bpf_internal *bpf) return false; /* No operands for exit */ - if (BPF_OP(bpf->op) == BPF_JUMP_EXIT) { + if (BPF_OP(bpf->op) == BPF_JUMP_EXIT) return bpf->op == (BPF_CLASS_JMP | BPF_JUMP_EXIT); - } if (BPF_OP(bpf->op) == BPF_JUMP_CALL) { if (bpf->op != (BPF_CLASS_JMP | BPF_JUMP_CALL)) return false; diff --git a/arch/BPF/BPFInstPrinter.c b/arch/BPF/BPFInstPrinter.c index 2476ca555d..782d8cbc0f 100644 --- a/arch/BPF/BPFInstPrinter.c +++ b/arch/BPF/BPFInstPrinter.c @@ -146,12 +146,10 @@ static void convert_operands(MCInst *MI, cs_bpf *bpf) /* decide the imm is BPF_OP_IMM or BPF_OP_OFF type here */ /* * 1. ja +off - * 2. call +off // eBPF - * 3. j {x,k}, +jt, +jf // cBPF - * 4. j dst_reg, {src_reg, k}, +off // eBPF + * 2. j {x,k}, +jt, +jf // cBPF + * 3. j dst_reg, {src_reg, k}, +off // eBPF */ if (BPF_OP(opcode) == BPF_JUMP_JA || - BPF_OP(opcode) == BPF_JUMP_CALL || (!EBPF_MODE(MI->csh) && i >= 1) || (EBPF_MODE(MI->csh) && i == 2)) push_op_off(bpf, (uint32_t)MCOperand_getImm(op)); diff --git a/suite/MC/BPF/extended-all.cs b/suite/MC/BPF/extended-all.cs index d320fae8c3..6558521d2b 100644 --- a/suite/MC/BPF/extended-all.cs +++ b/suite/MC/BPF/extended-all.cs @@ -67,7 +67,7 @@ 0x7d,0x58,0x52,0x01,0x90,0xf9,0x30,0x9a = jsge r8, r5, +0x152 0x7f,0x98,0xea,0xff,0xcf,0x5d,0x5f,0xa3 = rsh64 r8, r9 0x84,0x14,0xd4,0xaf,0x60,0xe1,0x41,0x18 = neg r4 -0x85,0xd3,0xa5,0xe2,0x83,0x3d,0xbd,0x5d = call +0x5dbd3d83 +0x85,0xd3,0xa5,0xe2,0x83,0x3d,0xbd,0x5d = call 0x5dbd3d83 0x87,0xf5,0x2b,0xbe,0xa9,0xc7,0x31,0xa3 = neg64 r5 0x94,0x39,0x0d,0xdc,0x0b,0xd2,0xd1,0xc9 = mod r9, 0xc9d1d20b 0x95,0xf2,0xd1,0x83,0x53,0xa9,0x09,0x9f = exit