diff --git a/librz/arch/meson.build b/librz/arch/meson.build index 7d86bee3b17..93056607361 100644 --- a/librz/arch/meson.build +++ b/librz/arch/meson.build @@ -357,6 +357,18 @@ if capstone_dep.version() == 'next' or capstone_dep.version().split('.')[0].to_i ] endif +if capstone_dep.version() == 'next' or capstone_dep.version().split('.')[0].to_int() > 5 + # plugins + arch_plugins_list += [ + 'bpf_cs', + ] + + # plugins sources + arch_plugin_sources += [ + 'p/arch_bpf_cs.c', + ] +endif + if capstone_dep.version() == 'next' or capstone_dep.version().split('.')[0].to_int() > 4 # plugins arch_plugins_list += [ diff --git a/librz/arch/p/analysis/analysis_bpf_cs.c b/librz/arch/p/analysis/analysis_bpf_cs.c new file mode 100644 index 00000000000..66b0cf85bbd --- /dev/null +++ b/librz/arch/p/analysis/analysis_bpf_cs.c @@ -0,0 +1,467 @@ +// SPDX-FileCopyrightText: 2026 Jagath-P +// SPDX-License-Identifier: LGPL-3.0-only + +#include +#include +#include + +typedef struct { + csh handle; + cs_mode omode; +} BPFContext; + +static char *bpf_get_reg_profile(RzAnalysis *analysis) { + const char *ebpf_reg_profile = + "=PC pc\n" + "=SP R10\n" + "=R0 R0\n" + "=A0 R1\n" + "=A1 R2\n" + "=A2 R3\n" + "=A3 R4\n" + "=A4 R5\n" + "gpr pc .64 0 0\n" // program counter + "gpr R0 .64 8 0\n" + "gpr R1 .64 16 0\n" + "gpr R2 .64 24 0\n" + "gpr R3 .64 32 0\n" + "gpr R4 .64 40 0\n" + "gpr R5 .64 48 0\n" + "gpr R6 .64 56 0\n" + "gpr R7 .64 64 0\n" + "gpr R8 .64 72 0\n" + "gpr R9 .64 80 0\n" + "gpr R10 .64 88 0\n"; // stack pointer + + return rz_str_dup(ebpf_reg_profile); +} + +static RzStructuredData *bpf_opex(csh handle, cs_insn *insn) { + if (!insn->detail) { + return NULL; + } + + RzStructuredData *root = rz_structured_data_new_map(); + if (!root) { + return NULL; + } + + RzStructuredData *opex = rz_structured_data_map_add_map(root, "opex"); + if (!opex) { + rz_structured_data_free(root); + return NULL; + } + + RzStructuredData *operands = rz_structured_data_map_add_array(opex, "operands"); + cs_bpf *x = &insn->detail->bpf; + for (st32 i = 0; i < x->op_count; i++) { + cs_bpf_op *op = x->operands + i; + RzStructuredData *operand = rz_structured_data_array_add_map(operands); + switch (op->type) { + case BPF_OP_REG: { + const char *reg_name = cs_reg_name(handle, op->reg); + rz_structured_data_map_add_string(operand, "type", "reg"); + rz_structured_data_map_add_string(operand, "value", reg_name ? reg_name : "unknown"); + break; + } + case BPF_OP_IMM: + rz_structured_data_map_add_string(operand, "type", "imm"); + if (op->is_signed) { + if (op->imm & (0xffffffff00000000)) { + rz_structured_data_map_add_signed(operand, "value", (st64)op->imm); + } else { + rz_structured_data_map_add_signed(operand, "value", (st64)(st32)op->imm); + } + } else { + rz_structured_data_map_add_unsigned(operand, "value", op->imm, true); + } + break; + case BPF_OP_OFF: + rz_structured_data_map_add_string(operand, "type", "off"); + if (op->is_signed) { + rz_structured_data_map_add_signed(operand, "value", (st32)(st16)op->off); + } else { + rz_structured_data_map_add_unsigned(operand, "value", op->off, true); + } + break; + case BPF_OP_MEM: { + const char *base_name = cs_reg_name(handle, (unsigned int)op->mem.base); + rz_structured_data_map_add_string(operand, "type", "mem"); + rz_structured_data_map_add_string(operand, "base", base_name ? base_name : "unknown"); + if (op->is_pkt) { + rz_structured_data_map_add_boolean(operand, "is_packet", true); + if (op->is_signed) { + rz_structured_data_map_add_signed(operand, "disp", (st32)op->mem.disp); + } else { + rz_structured_data_map_add_unsigned(operand, "disp", op->mem.disp, true); + } + } else { + if (op->is_signed) { + rz_structured_data_map_add_signed(operand, "disp", (st32)(st16)op->mem.disp); + } else { + rz_structured_data_map_add_unsigned(operand, "disp", op->mem.disp, true); + } + } + break; + } + default: + rz_structured_data_map_add_string(operand, "type", "invalid"); + break; + } + } + return root; +} + +static bool bpf_anal_init(void **user) { + BPFContext *ctx = RZ_NEW0(BPFContext); + rz_return_val_if_fail(ctx, false); + ctx->handle = 0; + ctx->omode = -1; + *user = ctx; + return true; +} + +static bool bpf_anal_fini(void *user) { + BPFContext *ctx = (BPFContext *)user; + if (ctx) { + if (ctx->handle) { + cs_close(&ctx->handle); + } + RZ_FREE(ctx); + } + return true; +} + +static int bpf_arch_info(RzAnalysis *a, RzAnalysisInfoType query) { + switch (query) { + case RZ_ANALYSIS_ARCHINFO_MIN_OP_SIZE: + return 8; + case RZ_ANALYSIS_ARCHINFO_MAX_OP_SIZE: + return 16; + case RZ_ANALYSIS_ARCHINFO_TEXT_ALIGN: + return 8; + case RZ_ANALYSIS_ARCHINFO_DATA_ALIGN: + return 1; + case RZ_ANALYSIS_ARCHINFO_CAN_USE_POINTERS: + return true; + default: + return -1; + } +} + +static void ebpf_op_type(RzAnalysisOp *op, ut64 addr, cs_insn *insn) { + switch (insn->id) { + case BPF_INS_ADD: op->type = RZ_ANALYSIS_OP_TYPE_ADD; break; + case BPF_INS_SUB: op->type = RZ_ANALYSIS_OP_TYPE_SUB; break; + case BPF_INS_MUL: op->type = RZ_ANALYSIS_OP_TYPE_MUL; break; + case BPF_INS_DIV: op->type = RZ_ANALYSIS_OP_TYPE_DIV; break; + case BPF_INS_OR: op->type = RZ_ANALYSIS_OP_TYPE_OR; break; + case BPF_INS_AND: op->type = RZ_ANALYSIS_OP_TYPE_AND; break; + case BPF_INS_LSH: op->type = RZ_ANALYSIS_OP_TYPE_SHL; break; + case BPF_INS_RSH: op->type = RZ_ANALYSIS_OP_TYPE_SHR; break; + case BPF_INS_NEG: op->type = RZ_ANALYSIS_OP_TYPE_UNK; break; + case BPF_INS_MOD: op->type = RZ_ANALYSIS_OP_TYPE_MOD; break; + case BPF_INS_XOR: op->type = RZ_ANALYSIS_OP_TYPE_XOR; break; + case BPF_INS_MOV: op->type = RZ_ANALYSIS_OP_TYPE_MOV; break; + case BPF_INS_ARSH: + op->type = RZ_ANALYSIS_OP_TYPE_SAR; + break; + + /* ALU64 */ + case BPF_INS_ADD64: op->type = RZ_ANALYSIS_OP_TYPE_ADD; break; + case BPF_INS_SUB64: op->type = RZ_ANALYSIS_OP_TYPE_SUB; break; + case BPF_INS_MUL64: op->type = RZ_ANALYSIS_OP_TYPE_MUL; break; + case BPF_INS_DIV64: op->type = RZ_ANALYSIS_OP_TYPE_DIV; break; + case BPF_INS_OR64: op->type = RZ_ANALYSIS_OP_TYPE_OR; break; + case BPF_INS_AND64: op->type = RZ_ANALYSIS_OP_TYPE_AND; break; + case BPF_INS_LSH64: op->type = RZ_ANALYSIS_OP_TYPE_SHL; break; + case BPF_INS_RSH64: op->type = RZ_ANALYSIS_OP_TYPE_SHR; break; + case BPF_INS_NEG64: op->type = RZ_ANALYSIS_OP_TYPE_UNK; break; + case BPF_INS_MOD64: op->type = RZ_ANALYSIS_OP_TYPE_MOD; break; + case BPF_INS_XOR64: op->type = RZ_ANALYSIS_OP_TYPE_XOR; break; + case BPF_INS_MOV64: op->type = RZ_ANALYSIS_OP_TYPE_MOV; break; + case BPF_INS_ARSH64: + op->type = RZ_ANALYSIS_OP_TYPE_SAR; + break; + + case BPF_INS_SDIV: + case BPF_INS_SDIV64: + op->type = RZ_ANALYSIS_OP_TYPE_DIV; + op->sign = true; + break; + case BPF_INS_SMOD: + case BPF_INS_SMOD64: + op->type = RZ_ANALYSIS_OP_TYPE_MOD; + op->sign = true; + break; + case BPF_INS_MOVSB: + case BPF_INS_MOVSH: + case BPF_INS_MOVSB64: + case BPF_INS_MOVSH64: + op->type = RZ_ANALYSIS_OP_TYPE_MOV; + op->sign = true; + break; + + /* Byte Swap */ + case BPF_INS_LE16: + case BPF_INS_LE32: + case BPF_INS_LE64: + case BPF_INS_BE16: + case BPF_INS_BE32: + case BPF_INS_BE64: + case BPF_INS_BSWAP16: + case BPF_INS_BSWAP32: + case BPF_INS_BSWAP64: + op->type = RZ_ANALYSIS_OP_TYPE_MOV; // endian-swap into same reg + break; + + /* Load */ + case BPF_INS_LDXW: + op->refptr = 4; + op->type = RZ_ANALYSIS_OP_TYPE_LOAD; + op->direction = RZ_ANALYSIS_OP_DIR_READ; + break; + case BPF_INS_LDXH: + op->refptr = 2; + op->type = RZ_ANALYSIS_OP_TYPE_LOAD; + op->direction = RZ_ANALYSIS_OP_DIR_READ; + break; + case BPF_INS_LDXB: + op->refptr = 1; + op->type = RZ_ANALYSIS_OP_TYPE_LOAD; + op->direction = RZ_ANALYSIS_OP_DIR_READ; + break; + case BPF_INS_LDXDW: + op->refptr = 8; + op->type = RZ_ANALYSIS_OP_TYPE_LOAD; + op->direction = RZ_ANALYSIS_OP_DIR_READ; + break; + case BPF_INS_LDW: + op->refptr = 4; + op->type = RZ_ANALYSIS_OP_TYPE_LOAD; + op->direction = RZ_ANALYSIS_OP_DIR_READ; + break; + case BPF_INS_LDH: + op->refptr = 2; + op->type = RZ_ANALYSIS_OP_TYPE_LOAD; + op->direction = RZ_ANALYSIS_OP_DIR_READ; + break; + case BPF_INS_LDB: + op->refptr = 1; + op->type = RZ_ANALYSIS_OP_TYPE_LOAD; + op->direction = RZ_ANALYSIS_OP_DIR_READ; + break; + case BPF_INS_LDDW: + op->refptr = 8; + op->type = RZ_ANALYSIS_OP_TYPE_LOAD; + op->direction = RZ_ANALYSIS_OP_DIR_READ; + break; + + case BPF_INS_LDABSW: + case BPF_INS_LDABSH: + case BPF_INS_LDABSB: + case BPF_INS_LDINDW: + case BPF_INS_LDINDH: + case BPF_INS_LDINDB: + op->type = RZ_ANALYSIS_OP_TYPE_LOAD; + op->direction = RZ_ANALYSIS_OP_DIR_READ; + break; + + /* Store */ + case BPF_INS_STXW: + case BPF_INS_STXH: + case BPF_INS_STXB: + case BPF_INS_STXDW: + case BPF_INS_STW: + case BPF_INS_STH: + case BPF_INS_STB: + case BPF_INS_STDW: + op->type = RZ_ANALYSIS_OP_TYPE_STORE; + op->direction = RZ_ANALYSIS_OP_DIR_WRITE; + break; + case BPF_INS_XADDW: + case BPF_INS_XADDDW: + op->type = RZ_ANALYSIS_OP_TYPE_STORE; + // atomic add-and-store + op->direction = RZ_ANALYSIS_OP_DIR_WRITE; + break; + + /* + * Atomics (AFADD, AFOR, AFAND, AFXOR, AADD, AOR, AAND, AXOR) + * only exist in Capstone versions after v6. + */ + case BPF_INS_AADD: + case BPF_INS_AOR: + case BPF_INS_AAND: + case BPF_INS_AXOR: + case BPF_INS_AFADD: + case BPF_INS_AFOR: + case BPF_INS_AFAND: + case BPF_INS_AFXOR: + case BPF_INS_AXCHG64: + case BPF_INS_ACMPXCHG64: + case BPF_INS_AADD64: + case BPF_INS_AOR64: + case BPF_INS_AAND64: + case BPF_INS_AXOR64: + case BPF_INS_AFADD64: + case BPF_INS_AFOR64: + case BPF_INS_AFAND64: + case BPF_INS_AFXOR64: + op->type = RZ_ANALYSIS_OP_TYPE_STORE; + break; + + case BPF_INS_JA: + if (insn->detail->bpf.op_count > 0) { + op->jump = addr + 8 + ((st16)insn->detail->bpf.operands[0].off) * 8; + } else { + op->type = RZ_ANALYSIS_OP_TYPE_ILL; + break; + } + op->type = RZ_ANALYSIS_OP_TYPE_JMP; + break; + + /* Conditional jump */ + case BPF_INS_JSGT: + case BPF_INS_JSGE: + case BPF_INS_JSLT: + case BPF_INS_JSLE: + op->sign = true; + /* fall through */ + case BPF_INS_JEQ: + case BPF_INS_JGT: + case BPF_INS_JGE: + case BPF_INS_JSET: + case BPF_INS_JNE: + case BPF_INS_JLT: + case BPF_INS_JLE: + if (insn->detail->bpf.op_count > 2) { + op->jump = addr + 8 + ((st16)insn->detail->bpf.operands[2].off) * 8; + } else { + op->type = RZ_ANALYSIS_OP_TYPE_ILL; + break; + } + op->fail = addr + 8; + op->type = RZ_ANALYSIS_OP_TYPE_CJMP; + break; + + /* Conditional jumps 32-bit operands */ + case BPF_INS_JAL: + if (insn->detail->bpf.op_count > 0) { + op->jump = addr + 8 + ((st32)insn->detail->bpf.operands[0].imm) * 8; + } else { + op->type = RZ_ANALYSIS_OP_TYPE_ILL; + break; + } + op->type = RZ_ANALYSIS_OP_TYPE_JMP; + break; + + case BPF_INS_JSLT32: + case BPF_INS_JSLE32: + case BPF_INS_JSGT32: + case BPF_INS_JSGE32: + op->sign = true; + /* fallthrough */ + case BPF_INS_JEQ32: + case BPF_INS_JGT32: + case BPF_INS_JGE32: + case BPF_INS_JNE32: + case BPF_INS_JLT32: + case BPF_INS_JLE32: + case BPF_INS_JSET32: + if (insn->detail->bpf.op_count > 2) { + op->jump = addr + 8 + ((st16)insn->detail->bpf.operands[2].off) * 8; + } else { + op->type = RZ_ANALYSIS_OP_TYPE_ILL; + break; + } + op->fail = addr + 8; + op->type = RZ_ANALYSIS_OP_TYPE_CJMP; + break; + + case BPF_INS_CALL: + op->type = RZ_ANALYSIS_OP_TYPE_CALL; + break; + case BPF_INS_CALLX: + op->type = RZ_ANALYSIS_OP_TYPE_RCALL; + break; + + case BPF_INS_EXIT: + op->type = RZ_ANALYSIS_OP_TYPE_RET; + break; + + default: + op->type = RZ_ANALYSIS_OP_TYPE_UNK; + break; + } +} + +static int bpf_analysis_op(RzAnalysis *a, RzAnalysisOp *op, ut64 addr, const ut8 *buf, int len, RzAnalysisOpMask mask) { + BPFContext *ctx = (BPFContext *)a->plugin_data; + cs_insn *insn; + int n; + cs_mode mode = CS_MODE_BPF_EXTENDED | (a->big_endian ? CS_MODE_BIG_ENDIAN : CS_MODE_LITTLE_ENDIAN); + + if (mode != ctx->omode) { + if (ctx->handle) { + cs_close(&ctx->handle); + } + ctx->omode = mode; + } + if (!ctx->handle) { + cs_err err = cs_open(CS_ARCH_BPF, mode, &ctx->handle); + if (err != CS_ERR_OK) { + rz_warn_if_reached(); + return -1; + } + cs_option(ctx->handle, CS_OPT_DETAIL, CS_OPT_ON); + } + + n = cs_disasm(ctx->handle, buf, len, addr, 1, &insn); + if (n < 1) { + op->type = RZ_ANALYSIS_OP_TYPE_ILL; + if (mask & RZ_ANALYSIS_OP_MASK_DISASM) { + op->mnemonic = strdup("invalid"); + } + cs_free(insn, n); + return -1; + } + op->size = insn->size; + op->id = insn->id; + if (op->size != 8 && op->size != 16) { + cs_free(insn, n); + return -1; + } + if (mask & RZ_ANALYSIS_OP_MASK_DISASM) { + op->mnemonic = rz_str_newf("%s %s", insn->mnemonic, insn->op_str); + } + if (mask & RZ_ANALYSIS_OP_MASK_OPEX) { + op->opex = bpf_opex(ctx->handle, insn); + } + op->nopcode = 1; + ebpf_op_type(op, addr, insn); + cs_free(insn, n); + return op->size; +} + +RzAnalysisPlugin rz_analysis_plugin_bpf_cs = { + .name = "bpf", + .desc = "Extended BPF analysis plugin", + .author = "Jagath-P", + .license = "LGPL3", + .arch = "bpf", + .bits = 64, + .op = &bpf_analysis_op, + .init = bpf_anal_init, + .fini = bpf_anal_fini, + .archinfo = bpf_arch_info, + .get_reg_profile = &bpf_get_reg_profile, +}; + +#ifndef RZ_PLUGIN_INCORE +RZ_API RzLibStruct rizin_plugin = { + .type = RZ_LIB_TYPE_ANALYSIS, + .data = &rz_analysis_plugin_bpf_cs, + .version = RZ_VERSION +}; +#endif diff --git a/librz/arch/p/arch_bpf_cs.c b/librz/arch/p/arch_bpf_cs.c new file mode 100644 index 00000000000..3d7639a74f3 --- /dev/null +++ b/librz/arch/p/arch_bpf_cs.c @@ -0,0 +1,8 @@ +// SPDX-FileCopyrightText: 2026 Jagath-P +// SPDX-License-Identifier: LGPL-3.0-only + +#include +#include "analysis/analysis_bpf_cs.c" +#include "asm/asm_bpf_cs.c" + +RZ_ARCH_PLUGIN_DEFINE_DEPRECATED(bpf_cs); diff --git a/librz/arch/p/asm/asm_bpf_cs.c b/librz/arch/p/asm/asm_bpf_cs.c new file mode 100644 index 00000000000..7da25daff47 --- /dev/null +++ b/librz/arch/p/asm/asm_bpf_cs.c @@ -0,0 +1,71 @@ +// SPDX-FileCopyrightText: 2026 Jagath-P +// SPDX-License-Identifier: LGPL-3.0-only + +#include +#include "capstone.h" +#include "cs_helper.h" + +CAPSTONE_DEFINE_PLUGIN_FUNCTIONS(bpf_asm); + +static int bpf_disassemble(const RzAsm *a, RzAsmOp *op, const ut8 *buf, int len) { + CapstoneContext *ctx = (CapstoneContext *)a->plugin_data; + cs_insn *insn; + int n; + cs_mode mode = CS_MODE_BPF_EXTENDED | (a->big_endian ? CS_MODE_BIG_ENDIAN : CS_MODE_LITTLE_ENDIAN); + op->size = 8; + if (ctx->omode != mode) { + if (ctx->handle) { + cs_close(&ctx->handle); + } + ctx->omode = mode; + } + if (!ctx->handle) { + cs_err err = cs_open(CS_ARCH_BPF, mode, &ctx->handle); + if (err != CS_ERR_OK) { + rz_warn_if_reached(); + return -1; + } + cs_option(ctx->handle, CS_OPT_DETAIL, CS_OPT_OFF); + } + + n = cs_disasm(ctx->handle, buf, len, a->pc, 1, &insn); + if (n < 1) { + rz_asm_op_set_asm(op, "invalid"); + cs_free(insn, n); + return -1; + } + if (insn->size != 8 && insn->size != 16) { + cs_free(insn, n); + return -1; + } + op->size = insn->size; + if (insn->op_str[0]) { + rz_asm_op_setf_asm(op, "%s %s", insn->mnemonic, insn->op_str); + } else { + rz_asm_op_set_asm(op, insn->mnemonic); + } + cs_free(insn, n); + return op->size; +} + +RzAsmPlugin rz_asm_plugin_bpf_cs = { + .name = "bpf", + .author = "Jagath-P", + .license = "LGPL3", + .desc = "eBPF disassembler", + .arch = "bpf", + .bits = 64, + .endian = RZ_SYS_ENDIAN_BIG | RZ_SYS_ENDIAN_LITTLE, + .init = &bpf_asm_init, + .fini = &bpf_asm_fini, + .disassemble = &bpf_disassemble, + .mnemonics = &bpf_asm_mnemonics +}; + +#ifndef RZ_PLUGIN_INCORE +RZ_API RzLibStruct rizin_plugin = { + .type = RZ_LIB_TYPE_ASM, + .data = &rz_asm_plugin_bpf_cs, + .version = RZ_VERSION +}; +#endif diff --git a/librz/arch/p/asm/asm_cbpf_cs.c b/librz/arch/p/asm/asm_cbpf_cs.c index 6c3214b31ef..c569b3dfcbf 100644 --- a/librz/arch/p/asm/asm_cbpf_cs.c +++ b/librz/arch/p/asm/asm_cbpf_cs.c @@ -51,7 +51,8 @@ static int cbpf_disassemble(const RzAsm *a, RzAsmOp *op, const ut8 *buf, int len RzAsmPlugin rz_asm_plugin_cbpf_cs = { .name = "cbpf", .license = "LGPL3", - .desc = "CBPF disassembly plugin", + .desc = "cBPF disassembler", + .author = "Jagath-P", .arch = "cbpf", .bits = 32, .endian = RZ_SYS_ENDIAN_BIG | RZ_SYS_ENDIAN_LITTLE, diff --git a/subprojects/packagefiles/capstone-6.0.0-alpha9/meson.build b/subprojects/packagefiles/capstone-6.0.0-alpha9/meson.build index 47ce09660c6..96f43b4d194 100644 --- a/subprojects/packagefiles/capstone-6.0.0-alpha9/meson.build +++ b/subprojects/packagefiles/capstone-6.0.0-alpha9/meson.build @@ -32,6 +32,10 @@ cs_files = [ 'arch/ARM/ARMInstPrinter.c', 'arch/ARM/ARMMapping.c', 'arch/ARM/ARMModule.c', + 'arch/BPF/BPFDisassembler.c', + 'arch/BPF/BPFInstPrinter.c', + 'arch/BPF/BPFMapping.c', + 'arch/BPF/BPFModule.c', 'arch/HPPA/HPPADisassembler.c', 'arch/HPPA/HPPAInstPrinter.c', 'arch/HPPA/HPPAMapping.c', @@ -116,6 +120,7 @@ libcapstone_c_args = [ '-DCAPSTONE_HAS_ARC', '-DCAPSTONE_HAS_ALPHA', '-DCAPSTONE_HAS_ARM', + '-DCAPSTONE_HAS_BPF', '-DCAPSTONE_HAS_HPPA', '-DCAPSTONE_HAS_LOONGARCH', '-DCAPSTONE_HAS_M680X', diff --git a/subprojects/packagefiles/capstone-next/meson.build b/subprojects/packagefiles/capstone-next/meson.build index 2789ca07fc9..96f43b4d194 100644 --- a/subprojects/packagefiles/capstone-next/meson.build +++ b/subprojects/packagefiles/capstone-next/meson.build @@ -32,6 +32,10 @@ cs_files = [ 'arch/ARM/ARMInstPrinter.c', 'arch/ARM/ARMMapping.c', 'arch/ARM/ARMModule.c', + 'arch/BPF/BPFDisassembler.c', + 'arch/BPF/BPFInstPrinter.c', + 'arch/BPF/BPFMapping.c', + 'arch/BPF/BPFModule.c', 'arch/HPPA/HPPADisassembler.c', 'arch/HPPA/HPPAInstPrinter.c', 'arch/HPPA/HPPAMapping.c', @@ -95,10 +99,6 @@ cs_files = [ 'arch/Xtensa/XtensaInstPrinter.c', 'arch/Xtensa/XtensaMapping.c', 'arch/Xtensa/XtensaModule.c', - 'arch/BPF/BPFDisassembler.c', - 'arch/BPF/BPFInstPrinter.c', - 'arch/BPF/BPFMapping.c', - 'arch/BPF/BPFModule.c', 'cs.c', 'Mapping.c', 'MCInst.c', @@ -120,6 +120,7 @@ libcapstone_c_args = [ '-DCAPSTONE_HAS_ARC', '-DCAPSTONE_HAS_ALPHA', '-DCAPSTONE_HAS_ARM', + '-DCAPSTONE_HAS_BPF', '-DCAPSTONE_HAS_HPPA', '-DCAPSTONE_HAS_LOONGARCH', '-DCAPSTONE_HAS_M680X', @@ -134,7 +135,6 @@ libcapstone_c_args = [ '-DCAPSTONE_HAS_XCORE', '-DCAPSTONE_HAS_XTENSA', '-DCAPSTONE_HAS_RISCV', - '-DCAPSTONE_HAS_BPF', ] if meson.get_compiler('c').has_argument('-Wmaybe-uninitialized') diff --git a/test/db/analysis/bpf b/test/db/analysis/bpf new file mode 100644 index 00000000000..8e5c9e6bbc0 --- /dev/null +++ b/test/db/analysis/bpf @@ -0,0 +1,1049 @@ +NAME=ebpf analysis +FILE=bins/bpf/xdp_flowtable.bpf.o +ARGS=-a bpf -E little +CMDS=< 0x080001c8 mov64 r3, r10 +| ||||||| 0x080001d0 add64 r3, 0xffffffb8 +| ||||||| 0x080001d8 mov r5, 0x2 +| ||||||| 0x080001e0 stxb [r3], r5 +| ||||||| 0x080001e8 ldxb r5, [r2+0x1] +| ||||||| 0x080001f0 stxb [r3+0xc], r5 +| ||||||| 0x080001f8 ldxb r5, [r2+0x9] +| ||||||| 0x08000200 stxb [r3+0x1], r5 +| ||||||| 0x08000208 ldxh r5, [r2+0x2] +| ||||||| 0x08000210 be16 r5 +| ||||||| 0x08000218 stxh [r3+0x6], r5 +| ||||||| 0x08000220 ldxw r5, [r2+0xc] +| ||||||| 0x08000228 stxw [r3+0x10], r5 +| ||||||| 0x08000230 ldxw r2, [r2+0x10] +| ||||||| 0x08000238 stxw [r3+0x20], r2 +| ||||||| 0x08000240 ldxh r2, [r4] +| ||||||| 0x08000248 stxh [r3+0x2], r2 +| ||||||| 0x08000250 ldxh r2, [r4+0x2] +| ||||||| 0x08000258 stxh [r3+0x4], r2 +| ========< 0x08000260 ja +0x3c +| ||||||| ;-- LBB0_12: +| |||||`--> 0x08000268 mov64 r4, r10 +| ||||| | 0x08000270 add64 r4, 0xffffffb8 +| ||||| | 0x08000278 mov64 r5, r6 +| ||||| | 0x08000280 add64 r5, 0x3a +| |||||,==< 0x08000288 jgt r5, r3, +0x4a +| ||||||| 0x08000290 ldxb r5, [r2+0x7] +| ========< 0x08000298 jlt32 r5, 0x2, +0x48 +| ||||||| 0x080002a0 mov64 r5, r6 +| ||||||| 0x080002a8 add64 r5, 0x36 +| ||||||| 0x080002b0 ldxb r7, [r2+0x6] +| ========< 0x080002b8 jne32 r7, 0x6, +0x8 +| ||||||| 0x080002c0 add64 r6, 0x4a +| ========< 0x080002c8 jgt r6, r3, +0x42 +| ||||||| 0x080002d0 ldxh r3, [r5+0xc] +| ||||||| 0x080002d8 and r3, 0x100 +| ========< 0x080002e0 jne32 r3, 0x0, +0x3f +| ||||||| 0x080002e8 ldxh r3, [r5+0xc] +| ||||||| 0x080002f0 and r3, 0x400 +| ========< 0x080002f8 jne32 r3, 0x0, +0x3c +| ||||||| ;-- LBB0_18: +| --------> 0x08000300 mov64 r0, 0x20 +| ||||||| 0x08000308 mov64 r3, r4 +| ||||||| 0x08000310 add64 r3, r0 +| ||||||| 0x08000318 mov64 r0, 0x10 +| ||||||| 0x08000320 mov64 r6, r4 +| ||||||| 0x08000328 add64 r6, r0 +| ||||||| 0x08000330 mov64 r0, r10 +| ||||||| 0x08000338 add64 r0, 0xffffffb8 +| ||||||| 0x08000340 mov r7, 0xa +| ||||||| 0x08000348 stxb [r0], r7 +| ||||||| 0x08000350 ldxb r7, [r2+0x6] +| ||||||| 0x08000358 stxb [r0+0x1], r7 +| ||||||| 0x08000360 ldxh r7, [r2+0x4] +| ||||||| 0x08000368 be16 r7 +| ||||||| 0x08000370 stxh [r0+0x6], r7 +| ||||||| 0x08000378 mov64 r7, 0x8 +| ||||||| 0x08000380 mov64 r8, r2 +| ||||||| 0x08000388 add64 r8, r7 +| ||||||| 0x08000390 ldxw r7, [r8+0xc] +| ||||||| 0x08000398 stxw [r6+0xc], r7 +| ||||||| 0x080003a0 ldxw r7, [r8+0x8] +| ||||||| 0x080003a8 stxw [r6+0x8], r7 +| ||||||| 0x080003b0 ldxw r7, [r8+0x4] +| ||||||| 0x080003b8 stxw [r6+0x4], r7 +| ||||||| 0x080003c0 ldxw r6, [r2+0x8] +| ||||||| 0x080003c8 stxw [r4+0x10], r6 +| ||||||| 0x080003d0 mov64 r6, 0x18 +| ||||||| 0x080003d8 mov64 r7, r2 +| ||||||| 0x080003e0 add64 r7, r6 +| ||||||| 0x080003e8 ldxw r6, [r7+0x8] +| ||||||| 0x080003f0 stxw [r3+0x8], r6 +| ||||||| 0x080003f8 ldxw r6, [r7+0xc] +| ||||||| 0x08000400 stxw [r3+0xc], r6 +| ||||||| 0x08000408 ldxw r2, [r2+0x18] +| ||||||| 0x08000410 stxw [r4+0x20], r2 +| ||||||| 0x08000418 ldxw r2, [r7+0x4] +| ||||||| 0x08000420 stxw [r3+0x4], r2 +| ||||||| 0x08000428 ldxh r2, [r5] +| ||||||| 0x08000430 stxh [r0+0x2], r2 +| ||||||| 0x08000438 ldxh r2, [r5+0x2] +| ||||||| 0x08000440 stxh [r0+0x4], r2 +| ||||||| ; CODE XREF from sym.xdp_flowtable_do_lookup @ 0x8000260 +| ||||||| ;-- LBB0_19: +| --------> 0x08000448 mov64 r2, r10 +| ||||||| 0x08000450 add64 r2, 0xffffffb8 +| ||||||| 0x08000458 mov64 r3, r10 +| ||||||| 0x08000460 add64 r3, 0xfffffffc +| ||||||| 0x08000468 mov r4, 0x4 +| ||||||| 0x08000470 call -0x1 +| ||||||| 0x08000478 mov64 r1, r0 +| ||||||| 0x08000480 mov r0, 0x2 +| ========< 0x08000488 jeq r1, 0x0, +0xa +| ||||||| 0x08000490 mov64 r2, r10 +| ||||||| 0x08000498 add64 r2, 0xffffffb4 +| ||||||| 0x080004a0 lddw r1, 0x0 +| ||||||| 0x080004b0 call 0x1 +| ||||||| 0x080004b8 mov64 r1, r0 +| ||||||| 0x080004c0 mov r0, 0x2 +| ========< 0x080004c8 jeq r1, 0x0, +0x2 +| ||||||| 0x080004d0 mov r2, 0x1 +| ||||||| 0x080004d8 aadd [r1], r2 +| ||||||| ;-- LBB0_22: +\ ```````-> 0x080004e0 exit +address: 0x8000338 +opcode: add64 r0, 0xffffffb8 +disasm: add64 r0, 0xffffffb8 +mnemonic: add64 +mask: ffffffffffffffff +prefix: 0 +id: 18 +bytes: 07000000b8ffffff +refptr: 0 +size: 8 +sign: false +type: add +cycles: 0 +opex: + operands: + - type: "reg" + value: "r0" + - type: "imm" + value: 0xffffffb8 +family: cpu +address: 0x80002e0 +opcode: jne32 r3, 0x0, +0x3f +disasm: jne32 r3, 0x0, +0x3f +mnemonic: jne32 +mask: ff00000000000000 +prefix: 0 +id: 89 +bytes: 56033f0000000000 +refptr: 0 +size: 8 +sign: false +type: cjmp +cycles: 0 +opex: + operands: + - type: "reg" + value: "r3" + - type: "imm" + value: 0 + - type: "off" + value: 63 +jump: 0x080004e0 +fail: 0x080002e8 +cond: al +family: cpu +pc = 0x0000000000000000 +R0 = 0x0000000000000000 +R1 = 0x0000000000000000 +R2 = 0x0000000000000000 +R3 = 0x0000000000000000 +R4 = 0x0000000000000000 +R5 = 0x0000000000000000 +R6 = 0x0000000000000000 +R7 = 0x0000000000000000 +R8 = 0x0000000000000000 +R9 = 0x0000000000000000 +R10 = 0x0000000000000000 +EOF +RUN + +NAME=ebpf covering more instructions +FILE= +CMDS=<