mirror of
https://github.com/capstone-engine/capstone
synced 2026-08-11 16:26:07 -04:00
Update BPF arch (#2568)
This commit is contained in:
parent
2c4b05f635
commit
812e654c85
23 changed files with 1471 additions and 753 deletions
|
|
@ -353,6 +353,7 @@ DEFINE_get_detail_op(mips, Mips);
|
|||
DEFINE_get_detail_op(riscv, RISCV);
|
||||
DEFINE_get_detail_op(systemz, SystemZ);
|
||||
DEFINE_get_detail_op(xtensa, Xtensa);
|
||||
DEFINE_get_detail_op(bpf, BPF);
|
||||
|
||||
/// Returns true if for this architecture the
|
||||
/// alias operands should be filled.
|
||||
|
|
|
|||
|
|
@ -145,6 +145,7 @@ DECL_get_detail_op(mips, Mips);
|
|||
DECL_get_detail_op(riscv, RISCV);
|
||||
DECL_get_detail_op(systemz, SystemZ);
|
||||
DECL_get_detail_op(xtensa, Xtensa);
|
||||
DECL_get_detail_op(bpf, BPF);
|
||||
|
||||
/// Increments the detail->arch.op_count by one.
|
||||
#define DEFINE_inc_detail_op_count(arch, ARCH) \
|
||||
|
|
@ -182,6 +183,8 @@ DEFINE_inc_detail_op_count(systemz, SystemZ);
|
|||
DEFINE_dec_detail_op_count(systemz, SystemZ);
|
||||
DEFINE_inc_detail_op_count(xtensa, Xtensa);
|
||||
DEFINE_dec_detail_op_count(xtensa, Xtensa);
|
||||
DEFINE_inc_detail_op_count(bpf, BPF);
|
||||
DEFINE_dec_detail_op_count(bpf, BPF);
|
||||
|
||||
/// Returns true if a memory operand is currently edited.
|
||||
static inline bool doing_mem(const MCInst *MI)
|
||||
|
|
@ -214,6 +217,7 @@ DEFINE_get_arch_detail(mips, Mips);
|
|||
DEFINE_get_arch_detail(riscv, RISCV);
|
||||
DEFINE_get_arch_detail(systemz, SystemZ);
|
||||
DEFINE_get_arch_detail(xtensa, Xtensa);
|
||||
DEFINE_get_arch_detail(bpf, BPF);
|
||||
|
||||
#define DEFINE_check_safe_inc(Arch, ARCH) \
|
||||
static inline void Arch##_check_safe_inc(const MCInst *MI) { \
|
||||
|
|
@ -230,6 +234,7 @@ DEFINE_check_safe_inc(LoongArch, LOONGARCH);
|
|||
DEFINE_check_safe_inc(RISCV, RISCV);
|
||||
DEFINE_check_safe_inc(SystemZ, SYSTEMZ);
|
||||
DEFINE_check_safe_inc(Mips, MIPS);
|
||||
DEFINE_check_safe_inc(BPF, BPF);
|
||||
|
||||
static inline bool detail_is_set(const MCInst *MI)
|
||||
{
|
||||
|
|
|
|||
46
SStream.c
46
SStream.c
|
|
@ -331,6 +331,22 @@ void printInt16(SStream *ss, int16_t val)
|
|||
}
|
||||
}
|
||||
|
||||
void printInt16HexOffset(SStream *ss, int16_t val)
|
||||
{
|
||||
assert(ss);
|
||||
SSTREAM_RETURN_IF_CLOSED(ss);
|
||||
if (val >= 0) {
|
||||
SStream_concat(ss, "+0x%" PRIx16, val);
|
||||
} else {
|
||||
if (val == INT16_MIN)
|
||||
SStream_concat(ss, "-0x%" PRIx16,
|
||||
(uint16_t)INT16_MAX + 1);
|
||||
else
|
||||
SStream_concat(ss, "-0x%" PRIx16, (int16_t)-val);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void printInt32(SStream *ss, int32_t val)
|
||||
{
|
||||
assert(ss);
|
||||
|
|
@ -352,6 +368,36 @@ void printInt32(SStream *ss, int32_t val)
|
|||
}
|
||||
}
|
||||
|
||||
void printInt32HexOffset(SStream *ss, int32_t val)
|
||||
{
|
||||
assert(ss);
|
||||
SSTREAM_RETURN_IF_CLOSED(ss);
|
||||
if (val >= 0) {
|
||||
SStream_concat(ss, "+0x%" PRIx32, val);
|
||||
} else {
|
||||
if (val == INT32_MIN)
|
||||
SStream_concat(ss, "-0x%" PRIx32,
|
||||
(uint32_t)INT32_MAX + 1);
|
||||
else
|
||||
SStream_concat(ss, "-0x%" PRIx32, (int32_t)-val);
|
||||
}
|
||||
}
|
||||
|
||||
void printInt32Hex(SStream *ss, int32_t val)
|
||||
{
|
||||
assert(ss);
|
||||
SSTREAM_RETURN_IF_CLOSED(ss);
|
||||
if (val >= 0) {
|
||||
SStream_concat(ss, "0x%" PRIx32, val);
|
||||
} else {
|
||||
if (val == INT32_MIN)
|
||||
SStream_concat(ss, "-0x%" PRIx32,
|
||||
(uint32_t)INT32_MAX + 1);
|
||||
else
|
||||
SStream_concat(ss, "-0x%" PRIx32, (int32_t)-val);
|
||||
}
|
||||
}
|
||||
|
||||
void printUInt32Bang(SStream *ss, uint32_t val)
|
||||
{
|
||||
assert(ss);
|
||||
|
|
|
|||
|
|
@ -73,7 +73,11 @@ void printInt32Bang(SStream *O, int32_t val);
|
|||
|
||||
void printInt8(SStream *O, int8_t val);
|
||||
void printInt16(SStream *O, int16_t val);
|
||||
void printInt16HexOffset(SStream *O, int16_t val);
|
||||
|
||||
void printInt32(SStream *O, int32_t val);
|
||||
void printInt32Hex(SStream *ss, int32_t val);
|
||||
void printInt32HexOffset(SStream *ss, int32_t val);
|
||||
|
||||
void printUInt32Bang(SStream *O, uint32_t val);
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,7 @@
|
|||
/* Capstone Disassembly Engine */
|
||||
/* BPF Backend by david942j <david942j@gmail.com>, 2019 */
|
||||
/* SPDX-FileCopyrightText: 2024 Roee Toledano <roeetoledano10@gmail.com> */
|
||||
/* SPDX-License-Identifier: BSD-3 */
|
||||
|
||||
/* This file defines constants and macros used for parsing a BPF instruction */
|
||||
|
||||
|
|
@ -9,80 +11,93 @@
|
|||
#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_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_JMP32 0x06 ///< eBPF 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
|
||||
#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_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 '<='
|
||||
|
||||
///< Types of complex atomic instructions
|
||||
#define BPF_ATOMIC_XCHG 0xe0 ///< eBPF only: atomic exchange
|
||||
#define BPF_ATOMIC_CMPXCHG 0xf0 ///< eBPF only: atomic compare and exchange
|
||||
|
||||
#define BPF_SRC(code) ((code) & 0x08)
|
||||
#define BPF_RVAL(code) ((code) & 0x18) /* cBPF only: for return types */
|
||||
///< Source operand
|
||||
#define BPF_SRC_K 0x00
|
||||
#define BPF_SRC_X 0x08
|
||||
#define BPF_SRC_A 0x10 /* cBPF only */
|
||||
#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
|
||||
#define BPF_SRC_LITTLE BPF_SRC_K
|
||||
#define BPF_SRC_BIG BPF_SRC_X
|
||||
|
||||
#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_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
|
||||
#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
|
||||
#define BPF_MODE_IMM 0x00 ///< used for 32-bit mov in cBPF and 64-bit in eBPF
|
||||
#define BPF_MODE_ABS \
|
||||
0x20 ///< absolute indexing of socket buffer. eBPF only, but deprecated in new versions
|
||||
#define BPF_MODE_IND \
|
||||
0x40 ///< indirect indexing of socket buffer. eBPF only, but deprecated in new versions
|
||||
#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_ATOMIC \
|
||||
0xc0 ///< eBPF only: atomic operations. Originally BPF_MODE_XADD
|
||||
|
||||
#define BPF_MODE_FETCH \
|
||||
0x01 /* eBPF only: overwrite 'src' with what was in the modified mem address before it was modified.
|
||||
NOTE: in contrast to regular modifiers, this one is encoded in the 'imm' field, not opcode!
|
||||
Must be used for BPF_XCHG and BPF_CMPXCHG. Optional for the other atomic operations. */
|
||||
|
||||
#define BPF_MISCOP(code) ((code) & 0x80)
|
||||
///< Operation of misc
|
||||
#define BPF_MISCOP_TAX 0x00
|
||||
#define BPF_MISCOP_TXA 0x80
|
||||
#define BPF_MISCOP_TAX 0x00
|
||||
#define BPF_MISCOP_TXA 0x80
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -1,5 +1,7 @@
|
|||
/* Capstone Disassembly Engine */
|
||||
/* BPF Backend by david942j <david942j@gmail.com>, 2019 */
|
||||
/* SPDX-FileCopyrightText: 2024 Roee Toledano <roeetoledano10@gmail.com> */
|
||||
/* SPDX-License-Identifier: BSD-3 */
|
||||
|
||||
#ifdef CAPSTONE_HAS_BPF
|
||||
|
||||
|
|
@ -9,26 +11,12 @@
|
|||
#include "BPFConstants.h"
|
||||
#include "BPFDisassembler.h"
|
||||
#include "BPFMapping.h"
|
||||
#include "../../Mapping.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 (((uint16_t)code[0] << 8) | code[1]);
|
||||
else
|
||||
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 ((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);
|
||||
}
|
||||
#include "../../utils.h"
|
||||
|
||||
///< Malloc bpf_internal, also checks if code_len is large enough.
|
||||
static bpf_internal *alloc_bpf_internal(size_t code_len)
|
||||
static bpf_internal *alloc_bpf_internal(const size_t code_len)
|
||||
{
|
||||
bpf_internal *bpf;
|
||||
|
||||
|
|
@ -43,8 +31,8 @@ static bpf_internal *alloc_bpf_internal(size_t code_len)
|
|||
}
|
||||
|
||||
///< Fetch a cBPF structure from code
|
||||
static bpf_internal* fetch_cbpf(cs_struct *ud, const uint8_t *code,
|
||||
size_t code_len)
|
||||
static bpf_internal *fetch_cbpf(MCInst *instr, const uint8_t *code,
|
||||
const size_t code_len)
|
||||
{
|
||||
bpf_internal *bpf;
|
||||
|
||||
|
|
@ -52,16 +40,16 @@ static bpf_internal* fetch_cbpf(cs_struct *ud, const uint8_t *code,
|
|||
if (bpf == NULL)
|
||||
return NULL;
|
||||
|
||||
bpf->op = read_u16(ud, code);
|
||||
bpf->op = readBytes16(instr, code);
|
||||
bpf->jt = code[2];
|
||||
bpf->jf = code[3];
|
||||
bpf->k = read_u32(ud, code + 4);
|
||||
bpf->k = readBytes32(instr, 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)
|
||||
static bpf_internal *fetch_ebpf(MCInst *instr, const uint8_t *code,
|
||||
const size_t code_len)
|
||||
{
|
||||
bpf_internal *bpf;
|
||||
|
||||
|
|
@ -80,39 +68,43 @@ static bpf_internal* fetch_ebpf(cs_struct *ud, const uint8_t *code,
|
|||
cs_mem_free(bpf);
|
||||
return NULL;
|
||||
}
|
||||
bpf->k = read_u32(ud, code + 4) | (((uint64_t)read_u32(ud, code + 12)) << 32);
|
||||
bpf->k = readBytes32(instr, code + 4) |
|
||||
(((uint64_t)readBytes32(instr, code + 12)) << 32);
|
||||
bpf->insn_size = 16;
|
||||
}
|
||||
else {
|
||||
bpf->offset = read_u16(ud, code + 2);
|
||||
bpf->k = read_u32(ud, code + 4);
|
||||
} else {
|
||||
bpf->offset = readBytes16(instr, code + 2);
|
||||
bpf->k = readBytes32(instr, code + 4);
|
||||
}
|
||||
return bpf;
|
||||
}
|
||||
|
||||
#define CHECK_READABLE_REG(ud, reg) do { \
|
||||
if (! ((reg) >= BPF_REG_R0 && (reg) <= BPF_REG_R10)) \
|
||||
#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)) \
|
||||
#define CHECK_WRITEABLE_REG(ud, reg) \
|
||||
do { \
|
||||
if (!((reg) >= BPF_REG_R0 && (reg) < BPF_REG_R10)) \
|
||||
return false; \
|
||||
} while (0)
|
||||
|
||||
#define CHECK_READABLE_AND_PUSH(ud, MI, r) do { \
|
||||
#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); \
|
||||
#define CHECK_WRITABLE_AND_PUSH(ud, MI, r) \
|
||||
do { \
|
||||
CHECK_WRITEABLE_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)
|
||||
static bool decodeLoad(MCInst *MI, bpf_internal *bpf)
|
||||
{
|
||||
if (!EBPF_MODE(ud)) {
|
||||
if (!EBPF_MODE(MI->csh->mode)) {
|
||||
/*
|
||||
* +-----+-----------+--------------------+
|
||||
* | ldb | [k] | [x+k] |
|
||||
|
|
@ -121,7 +113,8 @@ static bool decodeLoad(cs_struct *ud, MCInst *MI, bpf_internal *bpf)
|
|||
*/
|
||||
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) {
|
||||
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;
|
||||
|
|
@ -129,8 +122,7 @@ static bool decodeLoad(cs_struct *ud, MCInst *MI, bpf_internal *bpf)
|
|||
if (BPF_MODE(bpf->op) == BPF_MODE_ABS) {
|
||||
MCOperand_CreateImm0(MI, bpf->k);
|
||||
return true;
|
||||
}
|
||||
else if (BPF_MODE(bpf->op) == BPF_MODE_IND) {
|
||||
} else if (BPF_MODE(bpf->op) == BPF_MODE_IND) {
|
||||
MCOperand_CreateReg0(MI, BPF_REG_X);
|
||||
MCOperand_CreateImm0(MI, bpf->k);
|
||||
return true;
|
||||
|
|
@ -160,14 +152,12 @@ static bool decodeLoad(cs_struct *ud, MCInst *MI, bpf_internal *bpf)
|
|||
if (BPF_MODE(bpf->op) == BPF_MODE_ABS) {
|
||||
MCOperand_CreateImm0(MI, bpf->k);
|
||||
return true;
|
||||
}
|
||||
else if (BPF_MODE(bpf->op) == BPF_MODE_IND) {
|
||||
} else if (BPF_MODE(bpf->op) == BPF_MODE_IND) {
|
||||
MCOperand_CreateReg0(MI, BPF_REG_X);
|
||||
MCOperand_CreateImm0(MI, bpf->k);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
else { /* LDX */
|
||||
} else { /* LDX */
|
||||
if (BPF_MODE(bpf->op) == BPF_MODE_MSH) {
|
||||
MCOperand_CreateImm0(MI, bpf->k);
|
||||
return true;
|
||||
|
|
@ -179,14 +169,15 @@ static bool decodeLoad(cs_struct *ud, MCInst *MI, bpf_internal *bpf)
|
|||
/* eBPF mode */
|
||||
/*
|
||||
* - IMM: lddw dst, imm64
|
||||
* - ABS: ld{w,h,b,dw} [k]
|
||||
* - IND: ld{w,h,b,dw} [src+k]
|
||||
* - ABS: ld{w,h,b} [k]
|
||||
* - IND: ld{w,h,b} [src]
|
||||
* - MEM: ldx{w,h,b,dw} dst, [src+off]
|
||||
*/
|
||||
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))
|
||||
if (bpf->op !=
|
||||
(BPF_CLASS_LD | BPF_SIZE_DW | BPF_MODE_IMM))
|
||||
return false;
|
||||
CHECK_WRITABLE_AND_PUSH(ud, MI, bpf->dst);
|
||||
MCOperand_CreateImm0(MI, bpf->k);
|
||||
|
|
@ -196,11 +187,9 @@ static bool decodeLoad(cs_struct *ud, MCInst *MI, bpf_internal *bpf)
|
|||
return true;
|
||||
case BPF_MODE_IND:
|
||||
CHECK_READABLE_AND_PUSH(ud, MI, bpf->src);
|
||||
MCOperand_CreateImm0(MI, bpf->k);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
|
||||
}
|
||||
/* LDX */
|
||||
if (BPF_MODE(bpf->op) == BPF_MODE_MEM) {
|
||||
|
|
@ -212,7 +201,7 @@ static bool decodeLoad(cs_struct *ud, MCInst *MI, bpf_internal *bpf)
|
|||
return false;
|
||||
}
|
||||
|
||||
static bool decodeStore(cs_struct *ud, MCInst *MI, bpf_internal *bpf)
|
||||
static bool decodeStore(MCInst *MI, bpf_internal *bpf)
|
||||
{
|
||||
/* in cBPF, only BPF_ST* | BPF_MEM | BPF_W is valid
|
||||
* while in eBPF:
|
||||
|
|
@ -220,7 +209,7 @@ static bool decodeStore(cs_struct *ud, MCInst *MI, bpf_internal *bpf)
|
|||
* - BPF_ST* | BPF_MEM | BPF_{W,H,B,DW}
|
||||
* are valid
|
||||
*/
|
||||
if (!EBPF_MODE(ud)) {
|
||||
if (!EBPF_MODE(MI->csh->mode)) {
|
||||
/* can only store to M[] */
|
||||
if (bpf->op != (BPF_CLASS(bpf->op) | BPF_MODE_MEM | BPF_SIZE_W))
|
||||
return false;
|
||||
|
|
@ -229,11 +218,11 @@ static bool decodeStore(cs_struct *ud, MCInst *MI, bpf_internal *bpf)
|
|||
}
|
||||
|
||||
/* eBPF */
|
||||
|
||||
if (BPF_MODE(bpf->op) == BPF_MODE_XADD) {
|
||||
if (BPF_MODE(bpf->op) == BPF_MODE_ATOMIC) {
|
||||
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)
|
||||
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);
|
||||
|
|
@ -255,12 +244,12 @@ static bool decodeStore(cs_struct *ud, MCInst *MI, bpf_internal *bpf)
|
|||
return true;
|
||||
}
|
||||
|
||||
static bool decodeALU(cs_struct *ud, MCInst *MI, bpf_internal *bpf)
|
||||
static bool decodeALU(MCInst *MI, bpf_internal *bpf)
|
||||
{
|
||||
/* Set MI->Operands */
|
||||
|
||||
/* cBPF */
|
||||
if (!EBPF_MODE(ud)) {
|
||||
if (!EBPF_MODE(MI->csh->mode)) {
|
||||
if (BPF_OP(bpf->op) > BPF_ALU_XOR)
|
||||
return false;
|
||||
/* cBPF's NEG has no operands */
|
||||
|
|
@ -281,7 +270,8 @@ static bool decodeALU(cs_struct *ud, MCInst *MI, bpf_internal *bpf)
|
|||
if (BPF_OP(bpf->op) == BPF_ALU_END) {
|
||||
if (bpf->k != 16 && bpf->k != 32 && bpf->k != 64)
|
||||
return false;
|
||||
if (BPF_CLASS(bpf->op) == BPF_CLASS_ALU64 && BPF_SRC(bpf->op) != BPF_SRC_LITTLE)
|
||||
if (BPF_CLASS(bpf->op) == BPF_CLASS_ALU64 &&
|
||||
BPF_SRC(bpf->op) != BPF_SRC_LITTLE)
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
@ -298,24 +288,23 @@ 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) | ((uint32_t)bpf->k << 4));
|
||||
bpf->op |= ((uint32_t)bpf->k << 4);
|
||||
return true;
|
||||
}
|
||||
|
||||
/* normal cases */
|
||||
if (BPF_SRC(bpf->op) == BPF_SRC_K) {
|
||||
MCOperand_CreateImm0(MI, bpf->k);
|
||||
}
|
||||
else { /* BPF_SRC_X */
|
||||
} else { /* BPF_SRC_X */
|
||||
CHECK_READABLE_AND_PUSH(ud, MI, bpf->src);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool decodeJump(cs_struct *ud, MCInst *MI, bpf_internal *bpf)
|
||||
static bool decodeJump(MCInst *MI, bpf_internal *bpf)
|
||||
{
|
||||
/* cBPF and eBPF are very different in class jump */
|
||||
if (!EBPF_MODE(ud)) {
|
||||
if (!EBPF_MODE(MI->csh->mode)) {
|
||||
if (BPF_OP(bpf->op) > BPF_JUMP_JSET)
|
||||
return false;
|
||||
|
||||
|
|
@ -331,11 +320,11 @@ static bool decodeJump(cs_struct *ud, MCInst *MI, bpf_internal *bpf)
|
|||
MCOperand_CreateReg0(MI, BPF_REG_X);
|
||||
MCOperand_CreateImm0(MI, bpf->jt);
|
||||
MCOperand_CreateImm0(MI, bpf->jf);
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
if (BPF_OP(bpf->op) > BPF_JUMP_JSLE)
|
||||
return false;
|
||||
|
||||
/* JMP32 has no CALL/EXIT instruction */
|
||||
/* No operands for exit */
|
||||
if (BPF_OP(bpf->op) == BPF_JUMP_EXIT)
|
||||
return bpf->op == (BPF_CLASS_JMP | BPF_JUMP_EXIT);
|
||||
|
|
@ -344,7 +333,8 @@ static bool decodeJump(cs_struct *ud, MCInst *MI, bpf_internal *bpf)
|
|||
MCOperand_CreateImm0(MI, bpf->k);
|
||||
return true;
|
||||
}
|
||||
if (bpf->op == (BPF_CLASS_JMP | BPF_JUMP_CALL | BPF_SRC_X)) {
|
||||
if (bpf->op ==
|
||||
(BPF_CLASS_JMP | BPF_JUMP_CALL | BPF_SRC_X)) {
|
||||
CHECK_READABLE_AND_PUSH(ud, MI, bpf->k);
|
||||
return true;
|
||||
}
|
||||
|
|
@ -355,7 +345,11 @@ static bool decodeJump(cs_struct *ud, MCInst *MI, bpf_internal *bpf)
|
|||
if (BPF_OP(bpf->op) == BPF_JUMP_JA) {
|
||||
if (BPF_SRC(bpf->op) != BPF_SRC_K)
|
||||
return false;
|
||||
MCOperand_CreateImm0(MI, bpf->offset);
|
||||
if (BPF_CLASS(bpf->op) == BPF_CLASS_JMP)
|
||||
MCOperand_CreateImm0(MI, bpf->offset);
|
||||
else
|
||||
MCOperand_CreateImm0(MI, bpf->k);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
@ -370,7 +364,7 @@ static bool decodeJump(cs_struct *ud, MCInst *MI, bpf_internal *bpf)
|
|||
return true;
|
||||
}
|
||||
|
||||
static bool decodeReturn(cs_struct *ud, MCInst *MI, bpf_internal *bpf)
|
||||
static bool decodeReturn(MCInst *MI, bpf_internal *bpf)
|
||||
{
|
||||
/* Here only handles the BPF_RET class in cBPF */
|
||||
switch (BPF_RVAL(bpf->op)) {
|
||||
|
|
@ -387,7 +381,7 @@ static bool decodeReturn(cs_struct *ud, MCInst *MI, bpf_internal *bpf)
|
|||
return false;
|
||||
}
|
||||
|
||||
static bool decodeMISC(cs_struct *ud, MCInst *MI, bpf_internal *bpf)
|
||||
static bool decodeMISC(MCInst *MI, bpf_internal *bpf)
|
||||
{
|
||||
uint16_t op = bpf->op ^ BPF_CLASS_MISC;
|
||||
return op == BPF_MISCOP_TAX || op == BPF_MISCOP_TXA;
|
||||
|
|
@ -396,7 +390,7 @@ static bool decodeMISC(cs_struct *ud, MCInst *MI, bpf_internal *bpf)
|
|||
///< 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)
|
||||
static bool getInstruction(MCInst *MI, bpf_internal *bpf)
|
||||
{
|
||||
cs_detail *detail;
|
||||
|
||||
|
|
@ -407,52 +401,462 @@ static bool getInstruction(cs_struct *ud, MCInst *MI, bpf_internal *bpf)
|
|||
}
|
||||
|
||||
MCInst_clear(MI);
|
||||
MCInst_setOpcode(MI, bpf->op);
|
||||
|
||||
switch (BPF_CLASS(bpf->op)) {
|
||||
default: /* should never happen */
|
||||
return false;
|
||||
case BPF_CLASS_LD:
|
||||
case BPF_CLASS_LDX:
|
||||
return decodeLoad(ud, MI, bpf);
|
||||
return decodeLoad(MI, bpf);
|
||||
case BPF_CLASS_ST:
|
||||
case BPF_CLASS_STX:
|
||||
return decodeStore(ud, MI, bpf);
|
||||
return decodeStore(MI, bpf);
|
||||
case BPF_CLASS_ALU:
|
||||
return decodeALU(ud, MI, bpf);
|
||||
return decodeALU(MI, bpf);
|
||||
case BPF_CLASS_JMP:
|
||||
return decodeJump(ud, MI, bpf);
|
||||
return decodeJump(MI, bpf);
|
||||
case BPF_CLASS_RET:
|
||||
/* eBPF doesn't have this class */
|
||||
if (EBPF_MODE(ud))
|
||||
return false;
|
||||
return decodeReturn(ud, MI, bpf);
|
||||
case BPF_CLASS_MISC:
|
||||
/* case BPF_CLASS_ALU64: */
|
||||
if (EBPF_MODE(ud))
|
||||
return decodeALU(ud, MI, bpf);
|
||||
/* case BPF_CLASS_JMP32: */
|
||||
if (EBPF_MODE(MI->csh->mode))
|
||||
return decodeJump(MI, bpf);
|
||||
else
|
||||
return decodeMISC(ud, MI, bpf);
|
||||
return decodeReturn(MI, bpf);
|
||||
case BPF_CLASS_MISC:
|
||||
/* case BPF_CLASS_ALU64: */
|
||||
if (EBPF_MODE(MI->csh->mode))
|
||||
return decodeALU(MI, bpf);
|
||||
else
|
||||
return decodeMISC(MI, bpf);
|
||||
}
|
||||
}
|
||||
|
||||
bool BPF_getInstruction(csh ud, const uint8_t *code, size_t code_len,
|
||||
MCInst *instr, uint16_t *size, uint64_t address, void *info)
|
||||
// Check for regular load instructions
|
||||
#define REG_LOAD_CASE(c) \
|
||||
case BPF_SIZE_##c: \
|
||||
if (BPF_CLASS(opcode) == BPF_CLASS_LD) \
|
||||
return BPF_INS_LD##c; \
|
||||
else \
|
||||
return BPF_INS_LDX##c;
|
||||
|
||||
static bpf_insn op2insn_ld_cbpf(unsigned opcode)
|
||||
{
|
||||
switch (BPF_SIZE(opcode)) {
|
||||
REG_LOAD_CASE(W);
|
||||
REG_LOAD_CASE(H);
|
||||
REG_LOAD_CASE(B);
|
||||
REG_LOAD_CASE(DW);
|
||||
}
|
||||
|
||||
return BPF_INS_INVALID;
|
||||
}
|
||||
#undef REG_LOAD_CASE
|
||||
|
||||
// Check for packet load instructions
|
||||
#define PACKET_LOAD_CASE(c) \
|
||||
case BPF_SIZE_##c: \
|
||||
if (BPF_MODE(opcode) == BPF_MODE_ABS) \
|
||||
return BPF_INS_LDABS##c; \
|
||||
else if (BPF_MODE(opcode) == BPF_MODE_IND) \
|
||||
return BPF_INS_LDIND##c; \
|
||||
else \
|
||||
return BPF_INS_INVALID;
|
||||
|
||||
static bpf_insn op2insn_ld_ebpf(unsigned opcode)
|
||||
{
|
||||
if (BPF_CLASS(opcode) == BPF_CLASS_LD) {
|
||||
switch (BPF_SIZE(opcode)) {
|
||||
PACKET_LOAD_CASE(W);
|
||||
PACKET_LOAD_CASE(H);
|
||||
PACKET_LOAD_CASE(B);
|
||||
}
|
||||
}
|
||||
|
||||
// If it's not a packet load instruction, it must be a regular load instruction
|
||||
return op2insn_ld_cbpf(opcode);
|
||||
}
|
||||
#undef PACKET_LOAD_CASE
|
||||
|
||||
/* During parsing we already checked to make sure the size is D/DW and
|
||||
* mode is STX and not ST, so we don't need to check again*/
|
||||
#define ALU_CASE_REG(c) \
|
||||
case BPF_ALU_##c: \
|
||||
if (BPF_SIZE(opcode) == BPF_SIZE_W) \
|
||||
return BPF_INS_A##c; \
|
||||
else \
|
||||
return BPF_INS_A##c##64;
|
||||
|
||||
#define ALU_CASE_FETCH(c) \
|
||||
case BPF_ALU_##c | BPF_MODE_FETCH: \
|
||||
if (BPF_SIZE(opcode) == BPF_SIZE_W) \
|
||||
return BPF_INS_AF##c; \
|
||||
else \
|
||||
return BPF_INS_AF##c##64;
|
||||
|
||||
#define COMPLEX_CASE(c) \
|
||||
case BPF_ATOMIC_##c | BPF_MODE_FETCH: \
|
||||
if (BPF_SIZE(opcode) == BPF_SIZE_DW) \
|
||||
return BPF_INS_A##c##64;
|
||||
|
||||
#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;
|
||||
|
||||
static bpf_insn op2insn_st(unsigned opcode, const uint32_t imm)
|
||||
{
|
||||
/*
|
||||
* - BPF_STX | ALU atomic operations | BPF_{W,DW}
|
||||
* - BPF_STX | Complex atomic operations | BPF_{DW}
|
||||
* - BPF_ST* | BPF_MEM | BPF_{W,H,B,DW}
|
||||
*/
|
||||
|
||||
if (BPF_MODE(opcode) == BPF_MODE_ATOMIC) {
|
||||
switch (imm) {
|
||||
ALU_CASE_REG(ADD);
|
||||
ALU_CASE_REG(OR);
|
||||
ALU_CASE_REG(AND);
|
||||
ALU_CASE_REG(XOR);
|
||||
ALU_CASE_FETCH(ADD);
|
||||
ALU_CASE_FETCH(OR);
|
||||
ALU_CASE_FETCH(AND);
|
||||
ALU_CASE_FETCH(XOR);
|
||||
COMPLEX_CASE(XCHG);
|
||||
COMPLEX_CASE(CMPXCHG);
|
||||
default: // Could only be reached if complex atomic operation is used without fetch modifier, or not as DW
|
||||
return BPF_INS_INVALID;
|
||||
}
|
||||
}
|
||||
|
||||
/* should be BPF_MEM */
|
||||
switch (BPF_SIZE(opcode)) {
|
||||
CASE(W);
|
||||
CASE(H);
|
||||
CASE(B);
|
||||
CASE(DW);
|
||||
}
|
||||
|
||||
CS_ASSERT_RET_VAL(
|
||||
false && "Malformed atomic BPF instruction",
|
||||
BPF_INS_INVALID);
|
||||
}
|
||||
#undef CASE
|
||||
|
||||
#define CASE(c) \
|
||||
case BPF_ALU_##c: \
|
||||
CASE_IF(c)
|
||||
|
||||
#define CASE_IF(c) \
|
||||
do { \
|
||||
if (BPF_CLASS(opcode) == BPF_CLASS_ALU) \
|
||||
return BPF_INS_##c; \
|
||||
else \
|
||||
return BPF_INS_##c##64; \
|
||||
} while (0)
|
||||
|
||||
static bpf_insn op2insn_alu(unsigned opcode, const uint16_t off,
|
||||
const bool is_ebpf)
|
||||
{
|
||||
/* Endian is a special case */
|
||||
if (BPF_OP(opcode) == BPF_ALU_END) {
|
||||
if (BPF_CLASS(opcode) == BPF_CLASS_ALU64) {
|
||||
switch (opcode ^ BPF_CLASS_ALU64 ^ BPF_ALU_END ^
|
||||
BPF_SRC_LITTLE) {
|
||||
case (16 << 4):
|
||||
return BPF_INS_BSWAP16;
|
||||
case (32 << 4):
|
||||
return BPF_INS_BSWAP32;
|
||||
case (64 << 4):
|
||||
return BPF_INS_BSWAP64;
|
||||
default:
|
||||
return BPF_INS_INVALID;
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
switch (BPF_OP(opcode)) {
|
||||
CASE(ADD);
|
||||
CASE(SUB);
|
||||
CASE(MUL);
|
||||
CASE(OR);
|
||||
CASE(AND);
|
||||
CASE(LSH);
|
||||
CASE(RSH);
|
||||
CASE(NEG);
|
||||
CASE(XOR);
|
||||
CASE(ARSH);
|
||||
case BPF_ALU_DIV:
|
||||
if (!is_ebpf || off == 0)
|
||||
CASE_IF(DIV);
|
||||
else if (off == 1)
|
||||
CASE_IF(SDIV);
|
||||
else
|
||||
return BPF_INS_INVALID;
|
||||
case BPF_ALU_MOD:
|
||||
if (!is_ebpf || off == 0)
|
||||
CASE_IF(MOD);
|
||||
else if (off == 1)
|
||||
CASE_IF(SMOD);
|
||||
else
|
||||
return BPF_INS_INVALID;
|
||||
case BPF_ALU_MOV:
|
||||
/* BPF_CLASS_ALU can have: mov, mov8s, mov16s
|
||||
* BPF_CLASS_ALU64 can have: mov, mov8s, mov16s, mov32s
|
||||
* */
|
||||
if (off == 0)
|
||||
CASE_IF(MOV);
|
||||
else if (off == 8)
|
||||
CASE_IF(MOVSB);
|
||||
else if (off == 16)
|
||||
CASE_IF(MOVSH);
|
||||
else if (off == 32 && BPF_CLASS(opcode) == BPF_CLASS_ALU64)
|
||||
return BPF_INS_MOVSW64;
|
||||
else
|
||||
return BPF_INS_INVALID;
|
||||
}
|
||||
|
||||
return BPF_INS_INVALID;
|
||||
}
|
||||
#undef CASE_IF
|
||||
#undef CASE
|
||||
|
||||
#define BPF_CALLX (BPF_CLASS_JMP | BPF_JUMP_CALL | BPF_SRC_X)
|
||||
|
||||
#define CASE(c) \
|
||||
case BPF_JUMP_##c: \
|
||||
if (BPF_CLASS(opcode) == BPF_CLASS_JMP) \
|
||||
return BPF_INS_##c; \
|
||||
else \
|
||||
return BPF_INS_##c##32;
|
||||
|
||||
#define SPEC_CASE(c) \
|
||||
case BPF_JUMP_##c: \
|
||||
if (BPF_CLASS(opcode) == BPF_CLASS_JMP) \
|
||||
return BPF_INS_##c; \
|
||||
else \
|
||||
return BPF_INS_INVALID;
|
||||
|
||||
static bpf_insn op2insn_jmp(unsigned opcode)
|
||||
{
|
||||
if (opcode == BPF_CALLX) {
|
||||
return BPF_INS_CALLX;
|
||||
}
|
||||
|
||||
switch (BPF_OP(opcode)) {
|
||||
case BPF_JUMP_JA:
|
||||
if (BPF_CLASS(opcode) == BPF_CLASS_JMP)
|
||||
return BPF_INS_JA;
|
||||
else
|
||||
return BPF_INS_JAL;
|
||||
CASE(JEQ);
|
||||
CASE(JGT);
|
||||
CASE(JGE);
|
||||
CASE(JSET);
|
||||
CASE(JNE);
|
||||
CASE(JSGT);
|
||||
CASE(JSGE);
|
||||
SPEC_CASE(CALL);
|
||||
SPEC_CASE(EXIT);
|
||||
CASE(JLT);
|
||||
CASE(JLE);
|
||||
CASE(JSLT);
|
||||
CASE(JSLE);
|
||||
}
|
||||
|
||||
return BPF_INS_INVALID;
|
||||
}
|
||||
#undef SPEC_CASE
|
||||
#undef CASE
|
||||
#undef BPF_CALLX
|
||||
|
||||
#ifndef CAPSTONE_DIET
|
||||
|
||||
static void update_regs_access(MCInst *MI, cs_detail *detail,
|
||||
bpf_insn insn_id, unsigned int opcode)
|
||||
{
|
||||
if (insn_id == BPF_INS_INVALID)
|
||||
return;
|
||||
/*
|
||||
* In eBPF mode, only these instructions have implicit registers access:
|
||||
* - legacy ld{w,h,b,dw} * // w: r0
|
||||
* - exit // r: r0
|
||||
*/
|
||||
if (EBPF_MODE(MI->csh->mode)) {
|
||||
switch (insn_id) {
|
||||
default:
|
||||
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:
|
||||
case BPF_INS_LDDW:
|
||||
if (BPF_MODE(opcode) == BPF_MODE_ABS ||
|
||||
BPF_MODE(opcode) == BPF_MODE_IND)
|
||||
map_add_implicit_write(MI, BPF_REG_R0);
|
||||
break;
|
||||
case BPF_INS_EXIT:
|
||||
map_add_implicit_read(MI, BPF_REG_R0);
|
||||
break;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
/* cBPF mode */
|
||||
switch (BPF_CLASS(opcode)) {
|
||||
default:
|
||||
break;
|
||||
case BPF_CLASS_LD:
|
||||
map_add_implicit_write(MI, BPF_REG_A);
|
||||
break;
|
||||
case BPF_CLASS_LDX:
|
||||
map_add_implicit_write(MI, BPF_REG_X);
|
||||
break;
|
||||
case BPF_CLASS_ST:
|
||||
map_add_implicit_read(MI, BPF_REG_A);
|
||||
break;
|
||||
case BPF_CLASS_STX:
|
||||
map_add_implicit_read(MI, BPF_REG_X);
|
||||
break;
|
||||
case BPF_CLASS_ALU:
|
||||
map_add_implicit_read(MI, BPF_REG_A);
|
||||
map_add_implicit_write(MI, BPF_REG_A);
|
||||
break;
|
||||
case BPF_CLASS_JMP:
|
||||
if (insn_id != BPF_INS_JA) // except the unconditional jump
|
||||
map_add_implicit_read(MI, BPF_REG_A);
|
||||
break;
|
||||
/* case BPF_CLASS_RET: */
|
||||
case BPF_CLASS_MISC:
|
||||
if (insn_id == BPF_INS_TAX) {
|
||||
map_add_implicit_read(MI, BPF_REG_A);
|
||||
map_add_implicit_write(MI, BPF_REG_X);
|
||||
} else {
|
||||
map_add_implicit_read(MI, BPF_REG_X);
|
||||
map_add_implicit_write(MI, BPF_REG_A);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
static bool setFinalOpcode(MCInst *MI, const bpf_internal *bpf)
|
||||
{
|
||||
bpf_insn id = BPF_INS_INVALID;
|
||||
#ifndef CAPSTONE_DIET
|
||||
cs_detail *detail;
|
||||
|
||||
detail = get_detail(MI);
|
||||
#endif
|
||||
|
||||
const uint16_t opcode = bpf->op;
|
||||
switch (BPF_CLASS(opcode)) {
|
||||
default: // will never happen
|
||||
break;
|
||||
case BPF_CLASS_LD:
|
||||
case BPF_CLASS_LDX:
|
||||
if (EBPF_MODE(MI->csh->mode))
|
||||
id = op2insn_ld_ebpf(opcode);
|
||||
else
|
||||
id = op2insn_ld_cbpf(opcode);
|
||||
add_group(MI, BPF_GRP_LOAD);
|
||||
break;
|
||||
case BPF_CLASS_ST:
|
||||
case BPF_CLASS_STX:
|
||||
id = op2insn_st(opcode, bpf->k);
|
||||
add_group(MI, BPF_GRP_STORE);
|
||||
break;
|
||||
case BPF_CLASS_ALU:
|
||||
id = op2insn_alu(opcode, bpf->offset, EBPF_MODE(MI->csh->mode));
|
||||
add_group(MI, BPF_GRP_ALU);
|
||||
break;
|
||||
case BPF_CLASS_JMP:
|
||||
id = op2insn_jmp(opcode);
|
||||
#ifndef CAPSTONE_DIET
|
||||
if (id == BPF_INS_CALL || id == BPF_INS_CALLX)
|
||||
add_group(MI, BPF_GRP_CALL);
|
||||
else if (id == BPF_INS_EXIT)
|
||||
add_group(MI, BPF_GRP_RETURN);
|
||||
else
|
||||
add_group(MI, BPF_GRP_JUMP);
|
||||
#endif
|
||||
break;
|
||||
case BPF_CLASS_RET:
|
||||
/* case BPF_CLASS_JMP32: */
|
||||
if (EBPF_MODE(MI->csh->mode)) {
|
||||
id = op2insn_jmp(opcode);
|
||||
add_group(MI, BPF_GRP_JUMP);
|
||||
} else {
|
||||
id = BPF_INS_RET;
|
||||
add_group(MI, 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(MI->csh->mode)) {
|
||||
// ALU64 in eBPF
|
||||
id = op2insn_alu(opcode, bpf->offset, true);
|
||||
add_group(MI, BPF_GRP_ALU);
|
||||
} else {
|
||||
if (BPF_MISCOP(opcode) == BPF_MISCOP_TXA)
|
||||
id = BPF_INS_TXA;
|
||||
else
|
||||
id = BPF_INS_TAX;
|
||||
add_group(MI, BPF_GRP_MISC);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
if (id == BPF_INS_INVALID)
|
||||
return false;
|
||||
|
||||
MCInst_setOpcodePub(MI, id);
|
||||
#undef PUSH_GROUP
|
||||
|
||||
#ifndef CAPSTONE_DIET
|
||||
if (detail) {
|
||||
update_regs_access(MI, detail, id, opcode);
|
||||
}
|
||||
#endif
|
||||
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)
|
||||
{
|
||||
cs_struct *cs;
|
||||
bpf_internal *bpf;
|
||||
|
||||
cs = (cs_struct*)ud;
|
||||
if (EBPF_MODE(cs))
|
||||
bpf = fetch_ebpf(cs, code, code_len);
|
||||
if (EBPF_MODE(instr->csh->mode))
|
||||
bpf = fetch_ebpf(instr, code, code_len);
|
||||
else
|
||||
bpf = fetch_cbpf(cs, code, code_len);
|
||||
bpf = fetch_cbpf(instr, code, code_len);
|
||||
if (bpf == NULL)
|
||||
return false;
|
||||
if (!getInstruction(cs, instr, bpf)) {
|
||||
if (!getInstruction(instr, bpf) || !setFinalOpcode(instr, bpf)) {
|
||||
cs_mem_free(bpf);
|
||||
return false;
|
||||
}
|
||||
MCInst_setOpcode(instr, bpf->op);
|
||||
|
||||
*size = bpf->insn_size;
|
||||
cs_mem_free(bpf);
|
||||
|
|
|
|||
|
|
@ -22,6 +22,7 @@ typedef struct bpf_internal {
|
|||
} bpf_internal;
|
||||
|
||||
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);
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -1,11 +1,14 @@
|
|||
/* Capstone Disassembly Engine */
|
||||
/* BPF Backend by david942j <david942j@gmail.com>, 2019 */
|
||||
/* SPDX-FileCopyrightText: 2024 Roee Toledano <roeetoledano10@gmail.com> */
|
||||
/* SPDX-License-Identifier: BSD-3 */
|
||||
|
||||
#include <capstone/platform.h>
|
||||
|
||||
#include "BPFConstants.h"
|
||||
#include "BPFInstPrinter.h"
|
||||
#include "BPFMapping.h"
|
||||
#include "../../Mapping.h"
|
||||
|
||||
static cs_bpf_op *expand_bpf_operands(cs_bpf *bpf)
|
||||
{
|
||||
|
|
@ -22,29 +25,34 @@ 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, const bool is_signed)
|
||||
{
|
||||
cs_bpf_op *op = expand_bpf_operands(bpf);
|
||||
|
||||
op->type = BPF_OP_IMM;
|
||||
op->imm = val;
|
||||
op->is_signed = is_signed;
|
||||
}
|
||||
|
||||
static void push_op_off(cs_bpf *bpf, uint32_t val)
|
||||
static void push_op_off(cs_bpf *bpf, uint32_t val, const bool is_signed)
|
||||
{
|
||||
cs_bpf_op *op = expand_bpf_operands(bpf);
|
||||
|
||||
op->type = BPF_OP_OFF;
|
||||
op->off = val;
|
||||
op->is_signed = is_signed;
|
||||
}
|
||||
|
||||
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,
|
||||
const bool is_signed, const bool is_pkt)
|
||||
{
|
||||
cs_bpf_op *op = expand_bpf_operands(bpf);
|
||||
|
||||
op->type = BPF_OP_MEM;
|
||||
op->mem.base = reg;
|
||||
op->mem.disp = val;
|
||||
op->is_signed = is_signed;
|
||||
op->is_pkt = is_pkt;
|
||||
}
|
||||
|
||||
static void push_op_mmem(cs_bpf *bpf, uint32_t val)
|
||||
|
|
@ -77,38 +85,61 @@ static void convert_operands(MCInst *MI, cs_bpf *bpf)
|
|||
unsigned mc_op_count = MCInst_getNumOperands(MI);
|
||||
MCOperand *op;
|
||||
MCOperand *op2;
|
||||
unsigned i;
|
||||
|
||||
bpf->op_count = 0;
|
||||
if (BPF_CLASS(opcode) == BPF_CLASS_LD || BPF_CLASS(opcode) == BPF_CLASS_LDX) {
|
||||
if (BPF_CLASS(opcode) == BPF_CLASS_LD ||
|
||||
BPF_CLASS(opcode) == BPF_CLASS_LDX) {
|
||||
switch (BPF_MODE(opcode)) {
|
||||
case BPF_MODE_IMM:
|
||||
if (EBPF_MODE(MI->csh)) {
|
||||
push_op_reg(bpf, MCOperand_getReg(MCInst_getOperand(MI, 0)), CS_AC_WRITE);
|
||||
push_op_imm(bpf, MCOperand_getImm(MCInst_getOperand(MI, 1)));
|
||||
if (EBPF_MODE(MI->csh->mode)) {
|
||||
push_op_reg(bpf,
|
||||
MCOperand_getReg(
|
||||
MCInst_getOperand(MI, 0)),
|
||||
CS_AC_WRITE);
|
||||
push_op_imm(bpf,
|
||||
MCOperand_getImm(
|
||||
MCInst_getOperand(MI, 1)),
|
||||
false);
|
||||
} else {
|
||||
push_op_imm(bpf, MCOperand_getImm(MCInst_getOperand(MI, 0)));
|
||||
push_op_imm(bpf,
|
||||
MCOperand_getImm(
|
||||
MCInst_getOperand(MI, 0)),
|
||||
false);
|
||||
}
|
||||
break;
|
||||
case BPF_MODE_ABS:
|
||||
op = MCInst_getOperand(MI, 0);
|
||||
push_op_mem(bpf, BPF_REG_INVALID, (uint32_t)MCOperand_getImm(op));
|
||||
push_op_mem(bpf, BPF_REG_INVALID,
|
||||
(uint32_t)MCOperand_getImm(op), EBPF_MODE(MI->csh->mode), true);
|
||||
break;
|
||||
case BPF_MODE_IND:
|
||||
op = MCInst_getOperand(MI, 0);
|
||||
op2 = MCInst_getOperand(MI, 1);
|
||||
push_op_mem(bpf, MCOperand_getReg(op), (uint32_t)MCOperand_getImm(op2));
|
||||
if (EBPF_MODE(MI->csh->mode))
|
||||
push_op_mem(bpf, MCOperand_getReg(op), 0x0,
|
||||
true, true);
|
||||
else {
|
||||
op2 = MCInst_getOperand(MI, 1);
|
||||
push_op_mem(bpf, MCOperand_getReg(op),
|
||||
(uint32_t)MCOperand_getImm(op2),
|
||||
false, true);
|
||||
}
|
||||
break;
|
||||
case BPF_MODE_MEM:
|
||||
if (EBPF_MODE(MI->csh)) {
|
||||
if (EBPF_MODE(MI->csh->mode)) {
|
||||
/* ldx{w,h,b,dw} dst, [src+off] */
|
||||
push_op_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_op_mem(bpf, MCOperand_getReg(op), (uint32_t)MCOperand_getImm(op2));
|
||||
}
|
||||
else {
|
||||
push_op_mmem(bpf, (uint32_t)MCOperand_getImm(MCInst_getOperand(MI, 0)));
|
||||
push_op_mem(bpf, MCOperand_getReg(op),
|
||||
(uint32_t)MCOperand_getImm(op2),
|
||||
true, false);
|
||||
} else {
|
||||
push_op_mmem(bpf,
|
||||
(uint32_t)MCOperand_getImm(
|
||||
MCInst_getOperand(MI, 0)));
|
||||
}
|
||||
break;
|
||||
case BPF_MODE_LEN:
|
||||
|
|
@ -118,14 +149,16 @@ static void convert_operands(MCInst *MI, cs_bpf *bpf)
|
|||
op = MCInst_getOperand(MI, 0);
|
||||
push_op_msh(bpf, (uint32_t)MCOperand_getImm(op));
|
||||
break;
|
||||
/* case BPF_MODE_XADD: // not exists */
|
||||
/* 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)) {
|
||||
if (BPF_CLASS(opcode) == BPF_CLASS_ST ||
|
||||
BPF_CLASS(opcode) == BPF_CLASS_STX) {
|
||||
if (!EBPF_MODE(MI->csh->mode)) {
|
||||
// cBPF has only one case - st* M[k]
|
||||
push_op_mmem(bpf, (uint32_t)MCOperand_getImm(MCInst_getOperand(MI, 0)));
|
||||
push_op_mmem(bpf, (uint32_t)MCOperand_getImm(
|
||||
MCInst_getOperand(MI, 0)));
|
||||
return;
|
||||
}
|
||||
/* eBPF has two cases:
|
||||
|
|
@ -135,47 +168,66 @@ 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), (uint32_t)MCOperand_getImm(op2));
|
||||
push_op_mem(bpf, MCOperand_getReg(op),
|
||||
(uint32_t)MCOperand_getImm(op2), true, false);
|
||||
|
||||
op = MCInst_getOperand(MI, 2);
|
||||
if (MCOperand_isImm(op))
|
||||
push_op_imm(bpf, MCOperand_getImm(op));
|
||||
push_op_imm(bpf, MCOperand_getImm(op), false);
|
||||
else if (MCOperand_isReg(op))
|
||||
push_op_reg(bpf, MCOperand_getReg(op), CS_AC_READ);
|
||||
return;
|
||||
}
|
||||
|
||||
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. j {x,k}, +jt, +jf // cBPF
|
||||
* 3. j dst_reg, {src_reg, k}, +off // eBPF
|
||||
*/
|
||||
if (BPF_OP(opcode) == BPF_JUMP_JA ||
|
||||
(!EBPF_MODE(MI->csh) && i >= 1) ||
|
||||
(EBPF_MODE(MI->csh) && i == 2))
|
||||
push_op_off(bpf, (uint32_t)MCOperand_getImm(op));
|
||||
else
|
||||
push_op_imm(bpf, MCOperand_getImm(op));
|
||||
}
|
||||
else if (MCOperand_isReg(op)) {
|
||||
push_op_reg(bpf, MCOperand_getReg(op), CS_AC_READ);
|
||||
{
|
||||
const bool is_jmp32 = EBPF_MODE(MI->csh->mode) &&
|
||||
(BPF_CLASS(opcode) == BPF_CLASS_JMP32);
|
||||
if (BPF_CLASS(opcode) == BPF_CLASS_JMP || is_jmp32) {
|
||||
for (size_t i = 0; i < mc_op_count; i++) {
|
||||
op = MCInst_getOperand(MI, i);
|
||||
if (MCOperand_isImm(op)) {
|
||||
/* Decide if we're using IMM or OFF here (and if OFF, then signed or unsigned):
|
||||
*
|
||||
* 1. any jump/jump32 + signed off (not including exit/call and ja on jump32) // eBPF
|
||||
* 2. exit/call/ja + k // eBPF
|
||||
* 3. ja + unsigned off // cBPF (cBPF programs can only jump forwards)
|
||||
* 4. any jump {x,k}, +jt, +jf // cBPF
|
||||
* */
|
||||
|
||||
if ((BPF_OP(opcode) == BPF_JUMP_JA &&
|
||||
!is_jmp32) ||
|
||||
(!EBPF_MODE(MI->csh->mode) &&
|
||||
i >= 1) ||
|
||||
(EBPF_MODE(MI->csh->mode) &&
|
||||
i == 2))
|
||||
push_op_off(
|
||||
bpf,
|
||||
MCOperand_getImm(op),
|
||||
EBPF_MODE(
|
||||
MI->csh->mode));
|
||||
else
|
||||
push_op_imm(
|
||||
bpf,
|
||||
MCOperand_getImm(op),
|
||||
true);
|
||||
} else if (MCOperand_isReg(op)) {
|
||||
push_op_reg(bpf, MCOperand_getReg(op),
|
||||
CS_AC_READ);
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (!EBPF_MODE(MI->csh)) {
|
||||
if (!EBPF_MODE(MI->csh->mode)) {
|
||||
/* In cBPF mode, all registers in operands are accessed as read */
|
||||
for (i = 0; i < mc_op_count; i++) {
|
||||
for (size_t i = 0; i < mc_op_count; i++) {
|
||||
op = MCInst_getOperand(MI, i);
|
||||
if (MCOperand_isImm(op))
|
||||
push_op_imm(bpf, MCOperand_getImm(op));
|
||||
push_op_imm(bpf, MCOperand_getImm(op), false);
|
||||
else if (MCOperand_isReg(op))
|
||||
push_op_reg(bpf, MCOperand_getReg(op), CS_AC_READ);
|
||||
push_op_reg(bpf, MCOperand_getReg(op),
|
||||
CS_AC_READ);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
|
@ -193,15 +245,16 @@ static void convert_operands(MCInst *MI, cs_bpf *bpf)
|
|||
*/
|
||||
if (mc_op_count == 1) {
|
||||
op = MCInst_getOperand(MI, 0);
|
||||
push_op_reg(bpf, MCOperand_getReg(op), CS_AC_READ | CS_AC_WRITE);
|
||||
}
|
||||
else { // if (mc_op_count == 2)
|
||||
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_op_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_op_imm(bpf, MCOperand_getImm(op));
|
||||
push_op_imm(bpf, MCOperand_getImm(op), false);
|
||||
else if (MCOperand_isReg(op))
|
||||
push_op_reg(bpf, MCOperand_getReg(op), CS_AC_READ);
|
||||
}
|
||||
|
|
@ -217,22 +270,60 @@ 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:
|
||||
SStream_concat(O, "0x%" PRIx64, op->imm);
|
||||
if (op->is_signed)
|
||||
printInt32Hex(O, op->imm);
|
||||
else
|
||||
SStream_concat(O, "0x%" PRIx64, op->imm);
|
||||
break;
|
||||
case BPF_OP_OFF:
|
||||
SStream_concat(O, "+0x%x", op->off);
|
||||
if (op->is_signed)
|
||||
printInt16HexOffset(O, op->off);
|
||||
else
|
||||
SStream_concat(O, "+0x%" PRIx32, op->off);
|
||||
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));
|
||||
if (op->mem.disp != 0) {
|
||||
|
||||
if (op->is_pkt && EBPF_MODE(MI->csh->mode)) {
|
||||
SStream_concat(O, "skb");
|
||||
|
||||
if (op->mem.base != BPF_REG_INVALID)
|
||||
SStream_concat(O, "+");
|
||||
SStream_concat(O, "0x%x", op->mem.disp);
|
||||
SStream_concat(O, "+%s",
|
||||
BPF_reg_name((csh)MI->csh,
|
||||
op->mem.base));
|
||||
else {
|
||||
if (op->is_signed)
|
||||
printInt32HexOffset(O, op->mem.disp);
|
||||
else
|
||||
SStream_concat(O, "+0x%" PRIx32,
|
||||
op->mem.disp);
|
||||
}
|
||||
} else {
|
||||
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) {
|
||||
// if operation is signed, then it always uses off, not k
|
||||
if (op->is_signed)
|
||||
printInt16HexOffset(
|
||||
O, op->mem.disp);
|
||||
else if (op->is_pkt)
|
||||
SStream_concat(O, "+0x%" PRIx32,
|
||||
op->mem.disp);
|
||||
else
|
||||
SStream_concat(O, "+0x%" PRIx16,
|
||||
op->mem.disp);
|
||||
} else
|
||||
SStream_concat(O, "0x%" PRIx32,
|
||||
op->mem.disp);
|
||||
}
|
||||
|
||||
if (op->mem.base == BPF_REG_INVALID &&
|
||||
op->mem.disp == 0)
|
||||
SStream_concat(O, "0x0");
|
||||
}
|
||||
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:
|
||||
|
|
@ -258,18 +349,12 @@ static void print_operand(MCInst *MI, struct SStream *O, const cs_bpf_op *op)
|
|||
* */
|
||||
void BPF_printInst(MCInst *MI, struct SStream *O, void *PrinterInfo)
|
||||
{
|
||||
int i;
|
||||
cs_insn insn;
|
||||
cs_bpf bpf;
|
||||
cs_bpf bpf = { 0 };
|
||||
|
||||
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);
|
||||
|
||||
SStream_concat(O, BPF_insn_name((csh)MI->csh, insn.id));
|
||||
SStream_concat(O, BPF_insn_name((csh)MI->csh, MCInst_getOpcodePub(MI)));
|
||||
convert_operands(MI, &bpf);
|
||||
for (i = 0; i < bpf.op_count; i++) {
|
||||
for (size_t i = 0; i < bpf.op_count; i++) {
|
||||
if (i == 0)
|
||||
SStream_concat(O, "\t");
|
||||
else
|
||||
|
|
@ -278,7 +363,7 @@ void BPF_printInst(MCInst *MI, struct SStream *O, void *PrinterInfo)
|
|||
}
|
||||
|
||||
#ifndef CAPSTONE_DIET
|
||||
if (MI->flat_insn->detail) {
|
||||
if (detail_is_set(MI)) {
|
||||
MI->flat_insn->detail->bpf = bpf;
|
||||
}
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -1,5 +1,7 @@
|
|||
/* Capstone Disassembly Engine */
|
||||
/* BPF Backend by david942j <david942j@gmail.com>, 2019 */
|
||||
/* SPDX-FileCopyrightText: 2024 Roee Toledano <roeetoledano10@gmail.com> */
|
||||
/* SPDX-License-Identifier: BSD-3 */
|
||||
|
||||
#include <string.h>
|
||||
|
||||
|
|
@ -12,12 +14,9 @@
|
|||
static const name_map group_name_maps[] = {
|
||||
{ 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_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
|
||||
|
|
@ -35,99 +34,100 @@ 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_ADD, "add" }, { BPF_INS_SUB, "sub" },
|
||||
{ BPF_INS_MUL, "mul" }, { BPF_INS_DIV, "div" },
|
||||
{ BPF_INS_SDIV, "sdiv" }, { 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_SMOD, "smod" },
|
||||
{ BPF_INS_XOR, "xor" }, { BPF_INS_MOV, "mov" },
|
||||
{ BPF_INS_MOVSB, "movsb" }, { BPF_INS_MOVSH, "movsh" },
|
||||
{ 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_ADD64, "add64" }, { BPF_INS_SUB64, "sub64" },
|
||||
{ BPF_INS_MUL64, "mul64" }, { BPF_INS_DIV64, "div64" },
|
||||
{ BPF_INS_SDIV64, "sdiv64" }, { 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_SMOD64, "smod64" },
|
||||
{ BPF_INS_XOR64, "xor64" }, { BPF_INS_MOV64, "mov64" },
|
||||
{ BPF_INS_MOVSB64, "movsb64" }, { BPF_INS_MOVSH64, "movsh64" },
|
||||
{ BPF_INS_MOVSW64, "movsw64" }, { 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_BSWAP16, "bswap16" },
|
||||
{ BPF_INS_BSWAP32, "bswap32" },
|
||||
{ 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_BSWAP16, "bswap16" }, { BPF_INS_BSWAP32, "bswap32" },
|
||||
{ BPF_INS_BSWAP64, "bswap64" },
|
||||
|
||||
{ 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_LDXDW, "ldxdw" },
|
||||
{ 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_LDXDW, "ldxdw" },
|
||||
{ BPF_INS_LDABSW, "ldabsw" }, { BPF_INS_LDABSH, "ldabsh" },
|
||||
{ BPF_INS_LDABSB, "ldabsb" }, { BPF_INS_LDINDW, "ldindw" },
|
||||
{ BPF_INS_LDINDH, "ldindh" }, { BPF_INS_LDINDB, "ldindb" },
|
||||
|
||||
{ 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_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" },
|
||||
{ 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_CALLX, "callx" },
|
||||
{ BPF_INS_EXIT, "exit" },
|
||||
{ BPF_INS_JLT, "jlt" },
|
||||
{ BPF_INS_JLE, "jle" },
|
||||
{ BPF_INS_JSLT, "jslt" },
|
||||
{ BPF_INS_JSLE, "jsle" },
|
||||
{ BPF_INS_JA, "ja" }, { 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_CALLX, "callx" },
|
||||
{ BPF_INS_EXIT, "exit" }, { BPF_INS_JLT, "jlt" },
|
||||
{ BPF_INS_JLE, "jle" }, { BPF_INS_JSLT, "jslt" },
|
||||
{ BPF_INS_JSLE, "jsle" },
|
||||
|
||||
{ BPF_INS_JAL, "jal" }, { BPF_INS_JEQ32, "jeq32" },
|
||||
{ BPF_INS_JGT32, "jgt32" }, { BPF_INS_JGE32, "jge32" },
|
||||
{ BPF_INS_JSET32, "jset32" }, { BPF_INS_JNE32, "jne32" },
|
||||
{ BPF_INS_JSGT32, "jsgt32" }, { BPF_INS_JSGE32, "jsge32" },
|
||||
{ BPF_INS_JLT32, "jlt32" }, { BPF_INS_JLE32, "jle32" },
|
||||
{ BPF_INS_JSLT32, "jslt32" }, { BPF_INS_JSLE32, "jsle32" },
|
||||
|
||||
{ BPF_INS_RET, "ret" },
|
||||
|
||||
{ BPF_INS_TAX, "tax" },
|
||||
{ BPF_INS_TXA, "txa" },
|
||||
{ BPF_INS_AADD, "aadd" }, { BPF_INS_AOR, "aor" },
|
||||
{ BPF_INS_AAND, "aand" }, { BPF_INS_AXOR, "axor" },
|
||||
{ BPF_INS_AFADD, "afadd" }, { BPF_INS_AFOR, "afor" },
|
||||
{ BPF_INS_AFAND, "afand" }, { BPF_INS_AFXOR, "afxor" },
|
||||
|
||||
{ BPF_INS_AXCHG64, "axchg64" }, { BPF_INS_ACMPXCHG64, "acmpxchg64" },
|
||||
{ BPF_INS_AADD64, "aadd64" }, { BPF_INS_AOR64, "aor64" },
|
||||
{ BPF_INS_AAND64, "aand64" }, { BPF_INS_AXOR64, "axor64" },
|
||||
{ BPF_INS_AFADD64, "afadd64" }, { BPF_INS_AFOR64, "afor64" },
|
||||
{ BPF_INS_AFAND64, "afand64" }, { BPF_INS_AFXOR64, "afxor64" },
|
||||
|
||||
{ BPF_INS_TAX, "tax" }, { BPF_INS_TXA, "txa" },
|
||||
};
|
||||
#endif
|
||||
|
||||
inline bool BPF_getFeature(const cs_mode mode, const cs_mode feature)
|
||||
{
|
||||
return (mode & feature);
|
||||
}
|
||||
|
||||
const char *BPF_insn_name(csh handle, unsigned int id)
|
||||
{
|
||||
#ifndef CAPSTONE_DIET
|
||||
/* 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)) {
|
||||
if (!EBPF_MODE(((cs_struct *)handle)->mode)) {
|
||||
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";
|
||||
case BPF_INS_LD:
|
||||
return "ld";
|
||||
case BPF_INS_LDX:
|
||||
return "ldx";
|
||||
case BPF_INS_ST:
|
||||
return "st";
|
||||
case BPF_INS_STX:
|
||||
return "stx";
|
||||
}
|
||||
}
|
||||
return id2name(insn_name_maps, ARR_SIZE(insn_name_maps), id);
|
||||
|
|
@ -139,14 +139,12 @@ const char *BPF_insn_name(csh handle, unsigned int id)
|
|||
const char *BPF_reg_name(csh handle, unsigned int reg)
|
||||
{
|
||||
#ifndef CAPSTONE_DIET
|
||||
if (EBPF_MODE(handle)) {
|
||||
if (EBPF_MODE(((cs_struct *)handle)->mode)) {
|
||||
if (reg < BPF_REG_R0 || reg > BPF_REG_R10)
|
||||
return NULL;
|
||||
static const char reg_names[11][4] = {
|
||||
"r0", "r1", "r2", "r3", "r4",
|
||||
"r5", "r6", "r7", "r8", "r9",
|
||||
"r10"
|
||||
};
|
||||
static const char reg_names[11][4] = { "r0", "r1", "r2", "r3",
|
||||
"r4", "r5", "r6", "r7",
|
||||
"r8", "r9", "r10" };
|
||||
return reg_names[reg - BPF_REG_R0];
|
||||
}
|
||||
|
||||
|
|
@ -162,326 +160,30 @@ const char *BPF_reg_name(csh handle, unsigned int reg)
|
|||
#endif
|
||||
}
|
||||
|
||||
static bpf_insn op2insn_ld(unsigned opcode)
|
||||
void BPF_get_insn_id(cs_struct *h, cs_insn *insn, unsigned int id)
|
||||
{
|
||||
#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(W);
|
||||
CASE(H);
|
||||
CASE(B);
|
||||
CASE(DW);
|
||||
}
|
||||
#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 */
|
||||
if (BPF_OP(opcode) == BPF_ALU_END) {
|
||||
if (BPF_CLASS(opcode) == BPF_CLASS_ALU64) {
|
||||
switch (opcode ^ BPF_CLASS_ALU64 ^ BPF_ALU_END ^ BPF_SRC_LITTLE) {
|
||||
case (16 << 4):
|
||||
return BPF_INS_BSWAP16;
|
||||
case (32 << 4):
|
||||
return BPF_INS_BSWAP32;
|
||||
case (64 << 4):
|
||||
return BPF_INS_BSWAP64;
|
||||
default:
|
||||
return BPF_INS_INVALID;
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
static bpf_insn op2insn_jmp(unsigned opcode)
|
||||
{
|
||||
if (opcode == (BPF_CLASS_JMP | BPF_JUMP_CALL | BPF_SRC_X)) {
|
||||
return BPF_INS_CALLX;
|
||||
}
|
||||
|
||||
#define CASE(c) case BPF_JUMP_##c: return BPF_INS_##c
|
||||
switch (BPF_OP(opcode)) {
|
||||
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);
|
||||
}
|
||||
#undef CASE
|
||||
|
||||
return BPF_INS_INVALID;
|
||||
}
|
||||
|
||||
#ifndef CAPSTONE_DIET
|
||||
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:
|
||||
* - legacy 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:
|
||||
if (BPF_MODE(opcode) == BPF_MODE_ABS || BPF_MODE(opcode) == BPF_MODE_IND) {
|
||||
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;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* 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_*.
|
||||
bpf_insn id = BPF_INS_INVALID;
|
||||
#ifndef CAPSTONE_DIET
|
||||
cs_detail *detail;
|
||||
bpf_insn_group grp;
|
||||
|
||||
detail = insn->detail;
|
||||
#define PUSH_GROUP(grp) do { \
|
||||
if (detail) { \
|
||||
detail->groups[detail->groups_count] = grp; \
|
||||
detail->groups_count++; \
|
||||
} \
|
||||
} while(0)
|
||||
#else
|
||||
#define PUSH_GROUP(grp) do {} while(0)
|
||||
#endif
|
||||
|
||||
switch (BPF_CLASS(opcode)) {
|
||||
default: // will never happen
|
||||
break;
|
||||
case BPF_CLASS_LD:
|
||||
case BPF_CLASS_LDX:
|
||||
id = op2insn_ld(opcode);
|
||||
PUSH_GROUP(BPF_GRP_LOAD);
|
||||
break;
|
||||
case BPF_CLASS_ST:
|
||||
case BPF_CLASS_STX:
|
||||
id = op2insn_st(opcode);
|
||||
PUSH_GROUP(BPF_GRP_STORE);
|
||||
break;
|
||||
case BPF_CLASS_ALU:
|
||||
id = op2insn_alu(opcode);
|
||||
PUSH_GROUP(BPF_GRP_ALU);
|
||||
break;
|
||||
case BPF_CLASS_JMP:
|
||||
id = op2insn_jmp(opcode);
|
||||
#ifndef CAPSTONE_DIET
|
||||
grp = BPF_GRP_JUMP;
|
||||
if (id == BPF_INS_CALL || id == BPF_INS_CALLX)
|
||||
grp = BPF_GRP_CALL;
|
||||
else if (id == BPF_INS_EXIT)
|
||||
grp = BPF_GRP_RETURN;
|
||||
PUSH_GROUP(grp);
|
||||
#endif
|
||||
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
|
||||
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 (BPF_MISCOP(opcode) == BPF_MISCOP_TXA)
|
||||
id = BPF_INS_TXA;
|
||||
else
|
||||
id = BPF_INS_TAX;
|
||||
PUSH_GROUP(BPF_GRP_MISC);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
insn->id = id;
|
||||
#undef PUSH_GROUP
|
||||
|
||||
#ifndef CAPSTONE_DIET
|
||||
if (detail) {
|
||||
update_regs_access(ud, detail, id, opcode);
|
||||
}
|
||||
#endif
|
||||
// Not used by BPF. Information is set after disassembly.
|
||||
}
|
||||
|
||||
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;
|
||||
int tmp;
|
||||
size_t iMin;
|
||||
size_t tmp;
|
||||
|
||||
/* a modified selection sort for sorting and making unique */
|
||||
for (j = 0; j < n; j++) {
|
||||
for (size_t j = 0; j < n; j++) {
|
||||
/* arr[iMin] will be min(arr[j .. n-1]) */
|
||||
iMin = j;
|
||||
for (i = j + 1; i < n; i++) {
|
||||
for (size_t 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 {
|
||||
} else {
|
||||
tmp = arr[iMin];
|
||||
arr[iMin] = arr[j];
|
||||
arr[j] = tmp;
|
||||
|
|
@ -490,9 +192,9 @@ static void sort_and_uniq(cs_regs arr, uint8_t n, uint8_t *new_n)
|
|||
|
||||
*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)
|
||||
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)
|
||||
{
|
||||
unsigned i;
|
||||
uint8_t read_count, write_count;
|
||||
|
|
@ -502,8 +204,10 @@ void BPF_reg_access(const cs_insn *insn,
|
|||
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]));
|
||||
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++) {
|
||||
const cs_bpf_op *op = &(bpf->operands[i]);
|
||||
|
|
|
|||
|
|
@ -8,14 +8,16 @@
|
|||
|
||||
#include "../../cs_priv.h"
|
||||
|
||||
#define EBPF_MODE(ud) (((cs_struct*)ud)->mode & CS_MODE_BPF_EXTENDED)
|
||||
bool BPF_getFeature(const cs_mode mode, const cs_mode feature);
|
||||
|
||||
#define EBPF_MODE(mode) BPF_getFeature(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);
|
||||
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);
|
||||
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
|
||||
|
|
|
|||
|
|
@ -7,13 +7,13 @@ from .bpf_const import *
|
|||
|
||||
class BPFOpMem(ctypes.Structure):
|
||||
_fields_ = (
|
||||
('base', ctypes.c_uint8),
|
||||
('base', ctypes.c_int),
|
||||
('disp', ctypes.c_int32),
|
||||
)
|
||||
|
||||
class BPFOpValue(ctypes.Union):
|
||||
_fields_ = (
|
||||
('reg', ctypes.c_uint8),
|
||||
('reg', ctypes.c_int),
|
||||
('imm', ctypes.c_uint64),
|
||||
('off', ctypes.c_uint32),
|
||||
('mem', BPFOpMem),
|
||||
|
|
@ -26,6 +26,8 @@ class BPFOp(ctypes.Structure):
|
|||
_fields_ = (
|
||||
('type', ctypes.c_uint),
|
||||
('value', BPFOpValue),
|
||||
('is_signed', ctypes.c_bool),
|
||||
('is_pkt', ctypes.c_bool),
|
||||
('access', ctypes.c_uint8),
|
||||
)
|
||||
|
||||
|
|
@ -57,7 +59,6 @@ class BPFOp(ctypes.Structure):
|
|||
def ext(self):
|
||||
return self.value.ext
|
||||
|
||||
|
||||
class CsBPF(ctypes.Structure):
|
||||
_fields_ = (
|
||||
('op_count', ctypes.c_uint8),
|
||||
|
|
|
|||
|
|
@ -83,7 +83,7 @@ BPF_INS_STXB = 50
|
|||
BPF_INS_STXDW = 51
|
||||
BPF_INS_XADDW = 52
|
||||
BPF_INS_XADDDW = 53
|
||||
BPF_INS_JMP = 54
|
||||
BPF_INS_JA = 54
|
||||
BPF_INS_JEQ = 55
|
||||
BPF_INS_JGT = 56
|
||||
BPF_INS_JGE = 57
|
||||
|
|
|
|||
|
|
@ -1192,6 +1192,10 @@ def test_expected_bpf(actual: CsInsn, expected: dict) -> bool:
|
|||
return False
|
||||
if not compare_enum(aop.access, eop.get("access"), "access"):
|
||||
return False
|
||||
if not compare_tbool(aop.is_pkt, eop.get("is_pkt"), "is_pkt"):
|
||||
return False
|
||||
if not compare_tbool(aop.is_signed, eop.get("is_signed"), "is_signed"):
|
||||
return False
|
||||
|
||||
if aop.type == BPF_OP_REG:
|
||||
if not compare_reg(actual, aop.reg, eop.get("reg"), "reg"):
|
||||
|
|
|
|||
|
|
@ -176,6 +176,14 @@ Nonetheless, we hope this additional information is useful to you.
|
|||
- Architecture support was added (based on LLVM-18).
|
||||
- Support for `LITBASE`. Set the `LITBASE` with `cs_option(handle, CS_OPT_LITBASE, litbase_value)`.
|
||||
|
||||
**BPF**
|
||||
|
||||
- Added support for eBPF `ATOMIC` class instructions (using Linux mnemonics, not GNU ones. E.g. `acmpxchg64` instead of `axchg`)
|
||||
- Added support for eBPF signed `ALU` class instructions (`sdiv`, `smod`, `movs` variants. E.g. `smod r9, 0xc9d1d20b`)
|
||||
- Added support for eBPF `JMP32` class instructions (E.g. `jslt32 r7, -0xa46e0bd, -0x33f1`)
|
||||
- Updated the syntax for eBPF legacy packet instructions (similar to LLVM mnemonics, not GNU ones (E.g. `ldabsw [skb-0x8]`). `skb` is the socket buffer.
|
||||
- Corrected the signedness interpretation of `immidiate` and `offset` operands
|
||||
|
||||
**UX**
|
||||
|
||||
- Instruction alias (see below).
|
||||
|
|
|
|||
|
|
@ -1,5 +1,7 @@
|
|||
/* Capstone Disassembly Engine */
|
||||
/* BPF Backend by david942j <david942j@gmail.com>, 2019 */
|
||||
/* SPDX-FileCopyrightText: 2024 Roee Toledano <roeetoledano10@gmail.com> */
|
||||
/* SPDX-License-Identifier: BSD-3 */
|
||||
|
||||
#ifndef CAPSTONE_BPF_H
|
||||
#define CAPSTONE_BPF_H
|
||||
|
|
@ -11,9 +13,10 @@ extern "C" {
|
|||
#include "platform.h"
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning(disable:4201)
|
||||
#pragma warning(disable : 4201)
|
||||
#endif
|
||||
|
||||
#define NUM_BPF_OPS 3
|
||||
/// Operand type for instruction's operands
|
||||
typedef enum bpf_op_type {
|
||||
BPF_OP_INVALID = 0,
|
||||
|
|
@ -22,9 +25,9 @@ typedef enum bpf_op_type {
|
|||
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
|
||||
BPF_OP_EXT, ///< cBPF's extension (not eBPF)
|
||||
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
|
||||
|
|
@ -54,8 +57,8 @@ typedef enum 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
|
||||
uint32_t disp; ///< offset value
|
||||
bpf_reg base; ///< base register
|
||||
uint32_t disp; ///< offset value
|
||||
} bpf_op_mem;
|
||||
|
||||
typedef enum bpf_ext_type {
|
||||
|
|
@ -71,13 +74,15 @@ typedef struct cs_bpf_op {
|
|||
uint8_t reg; ///< register value for REG operand
|
||||
uint64_t imm; ///< immediate value IMM operand
|
||||
uint32_t off; ///< offset value, used in jump & call
|
||||
bpf_op_mem mem; ///< base/disp value for MEM operand
|
||||
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
|
||||
uint32_t ext; ///< cBPF's extension (not eBPF)
|
||||
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)
|
||||
};
|
||||
|
||||
bool is_signed; ///< is this operand signed? It is set for memory, immediate and offset operands.
|
||||
bool is_pkt; ///< is this operand referring to packet data? It is set for memory operands.
|
||||
/// 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.
|
||||
|
|
@ -99,29 +104,38 @@ typedef enum bpf_insn {
|
|||
BPF_INS_SUB,
|
||||
BPF_INS_MUL,
|
||||
BPF_INS_DIV,
|
||||
BPF_INS_SDIV,
|
||||
BPF_INS_OR,
|
||||
BPF_INS_AND,
|
||||
BPF_INS_LSH,
|
||||
BPF_INS_RSH,
|
||||
BPF_INS_NEG,
|
||||
BPF_INS_MOD,
|
||||
BPF_INS_SMOD,
|
||||
BPF_INS_XOR,
|
||||
BPF_INS_MOV, ///< eBPF only
|
||||
BPF_INS_ARSH, ///< eBPF only
|
||||
BPF_INS_MOV, ///< eBPF only
|
||||
BPF_INS_MOVSB, ///< eBPF only
|
||||
BPF_INS_MOVSH, ///< eBPF only
|
||||
BPF_INS_ARSH, ///< eBPF only
|
||||
|
||||
///< ALU64, eBPF only
|
||||
BPF_INS_ADD64,
|
||||
BPF_INS_SUB64,
|
||||
BPF_INS_MUL64,
|
||||
BPF_INS_DIV64,
|
||||
BPF_INS_SDIV64,
|
||||
BPF_INS_OR64,
|
||||
BPF_INS_AND64,
|
||||
BPF_INS_LSH64,
|
||||
BPF_INS_RSH64,
|
||||
BPF_INS_NEG64,
|
||||
BPF_INS_MOD64,
|
||||
BPF_INS_SMOD64,
|
||||
BPF_INS_XOR64,
|
||||
BPF_INS_MOV64,
|
||||
BPF_INS_MOVSB64,
|
||||
BPF_INS_MOVSH64,
|
||||
BPF_INS_MOVSW64,
|
||||
BPF_INS_ARSH64,
|
||||
|
||||
///< Byteswap, eBPF only
|
||||
|
|
@ -136,14 +150,21 @@ typedef enum bpf_insn {
|
|||
BPF_INS_BSWAP64,
|
||||
|
||||
///< Load
|
||||
BPF_INS_LDW, ///< 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
|
||||
BPF_INS_LDXDW, ///< eBPF only
|
||||
BPF_INS_LDDW, ///< eBPF only: load 64-bit imm
|
||||
BPF_INS_LDXW, ///< eBPF only
|
||||
BPF_INS_LDXH, ///< eBPF only
|
||||
BPF_INS_LDXB, ///< eBPF only
|
||||
BPF_INS_LDXDW, ///< eBPF only
|
||||
///< Packet data access
|
||||
BPF_INS_LDABSW, ///< eBPF only
|
||||
BPF_INS_LDABSH, ///< eBPF only
|
||||
BPF_INS_LDABSB, ///< eBPF only
|
||||
BPF_INS_LDINDW, ///< eBPF only
|
||||
BPF_INS_LDINDH, ///< eBPF only
|
||||
BPF_INS_LDINDB, ///< eBPF only
|
||||
|
||||
///< Store
|
||||
BPF_INS_STW, ///< eBPF only
|
||||
|
|
@ -155,28 +176,64 @@ typedef enum bpf_insn {
|
|||
BPF_INS_STXB, ///< eBPF only
|
||||
BPF_INS_STXDW, ///< eBPF only
|
||||
BPF_INS_XADDW, ///< eBPF only
|
||||
BPF_INS_XADDDW, ///< eBPF only
|
||||
BPF_INS_XADDDW, ///< eBPF only
|
||||
|
||||
///< Jump
|
||||
BPF_INS_JMP,
|
||||
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_CALLX, ///< 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
|
||||
BPF_INS_JNE, ///< eBPF only
|
||||
BPF_INS_JSGT, ///< eBPF only
|
||||
BPF_INS_JSGE, ///< eBPF only
|
||||
BPF_INS_CALL, ///< eBPF only
|
||||
BPF_INS_CALLX, ///< 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
|
||||
|
||||
///< Jump32, eBPF only
|
||||
BPF_INS_JAL,
|
||||
BPF_INS_JEQ32,
|
||||
BPF_INS_JGT32,
|
||||
BPF_INS_JGE32,
|
||||
BPF_INS_JSET32,
|
||||
BPF_INS_JNE32,
|
||||
BPF_INS_JSGT32,
|
||||
BPF_INS_JSGE32,
|
||||
BPF_INS_JLT32,
|
||||
BPF_INS_JLE32,
|
||||
BPF_INS_JSLT32,
|
||||
BPF_INS_JSLE32,
|
||||
|
||||
///< Return, cBPF only
|
||||
BPF_INS_RET,
|
||||
|
||||
///< Atomic, eBPF only
|
||||
BPF_INS_AADD,
|
||||
BPF_INS_AOR,
|
||||
BPF_INS_AAND,
|
||||
BPF_INS_AXOR,
|
||||
BPF_INS_AFADD,
|
||||
BPF_INS_AFOR,
|
||||
BPF_INS_AFAND,
|
||||
BPF_INS_AFXOR,
|
||||
|
||||
///< Atomic 64-bit, eBPF only
|
||||
BPF_INS_AXCHG64,
|
||||
BPF_INS_ACMPXCHG64,
|
||||
BPF_INS_AADD64,
|
||||
BPF_INS_AOR64,
|
||||
BPF_INS_AAND64,
|
||||
BPF_INS_AXOR64,
|
||||
BPF_INS_AFADD64,
|
||||
BPF_INS_AFOR64,
|
||||
BPF_INS_AFAND64,
|
||||
BPF_INS_AFXOR64,
|
||||
|
||||
///< Misc, cBPF only
|
||||
BPF_INS_TAX,
|
||||
BPF_INS_TXA,
|
||||
|
|
@ -184,10 +241,10 @@ typedef enum bpf_insn {
|
|||
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_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
|
||||
|
|
|
|||
|
|
@ -18,6 +18,9 @@
|
|||
/// > 0 => true
|
||||
typedef int32_t tbool;
|
||||
|
||||
#define CYAML_FIELD_TBOOL(name, flags, type, member) \
|
||||
CYAML_FIELD_INT(name, flags, type, member)
|
||||
|
||||
/// Compares the @actual bool against the @expected tbool:
|
||||
/// It returns with @ret_val, if expected is set but the values mismatch.
|
||||
#define compare_tbool_ret(actual, expected, ret_val) \
|
||||
|
|
|
|||
|
|
@ -20,6 +20,8 @@ typedef struct {
|
|||
char *ext;
|
||||
char *mem_base;
|
||||
uint32_t mem_disp;
|
||||
tbool is_pkt;
|
||||
tbool is_signed;
|
||||
} TestDetailBPFOp;
|
||||
|
||||
static const cyaml_schema_field_t test_detail_bpf_op_mapping_schema[] = {
|
||||
|
|
@ -30,17 +32,21 @@ static const cyaml_schema_field_t test_detail_bpf_op_mapping_schema[] = {
|
|||
TestDetailBPFOp, access, 0, CYAML_UNLIMITED),
|
||||
CYAML_FIELD_STRING_PTR("reg", CYAML_FLAG_POINTER | CYAML_FLAG_OPTIONAL,
|
||||
TestDetailBPFOp, reg, 0, CYAML_UNLIMITED),
|
||||
CYAML_FIELD_INT("imm", CYAML_FLAG_OPTIONAL, TestDetailBPFOp, imm),
|
||||
CYAML_FIELD_INT("off", CYAML_FLAG_OPTIONAL, TestDetailBPFOp, off),
|
||||
CYAML_FIELD_INT("mmem", CYAML_FLAG_OPTIONAL, TestDetailBPFOp, mmem),
|
||||
CYAML_FIELD_INT("msh", CYAML_FLAG_OPTIONAL, TestDetailBPFOp, msh),
|
||||
CYAML_FIELD_UINT("imm", CYAML_FLAG_OPTIONAL, TestDetailBPFOp, imm),
|
||||
CYAML_FIELD_UINT("off", CYAML_FLAG_OPTIONAL, TestDetailBPFOp, off),
|
||||
CYAML_FIELD_UINT("mmem", CYAML_FLAG_OPTIONAL, TestDetailBPFOp, mmem),
|
||||
CYAML_FIELD_UINT("msh", CYAML_FLAG_OPTIONAL, TestDetailBPFOp, msh),
|
||||
CYAML_FIELD_STRING_PTR("ext", CYAML_FLAG_POINTER | CYAML_FLAG_OPTIONAL,
|
||||
TestDetailBPFOp, ext, 0, CYAML_UNLIMITED),
|
||||
CYAML_FIELD_STRING_PTR("mem_base",
|
||||
CYAML_FLAG_POINTER | CYAML_FLAG_OPTIONAL,
|
||||
TestDetailBPFOp, mem_base, 0, CYAML_UNLIMITED),
|
||||
CYAML_FIELD_INT("mem_disp", CYAML_FLAG_OPTIONAL, TestDetailBPFOp,
|
||||
CYAML_FIELD_UINT("mem_disp", CYAML_FLAG_OPTIONAL, TestDetailBPFOp,
|
||||
mem_disp),
|
||||
CYAML_FIELD_TBOOL("is_pkt", CYAML_FLAG_OPTIONAL, TestDetailBPFOp,
|
||||
is_pkt),
|
||||
CYAML_FIELD_TBOOL("is_signed", CYAML_FLAG_OPTIONAL, TestDetailBPFOp,
|
||||
is_signed),
|
||||
CYAML_FIELD_END
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -1,9 +1,9 @@
|
|||
// Copyright © 2024 Rot127 <unisono@quyllur.org>
|
||||
// SPDX-License-Identifier: BSD-3
|
||||
|
||||
#include "capstone/bpf.h"
|
||||
#include "test_compare.h"
|
||||
#include "test_detail_bpf.h"
|
||||
#include <capstone/bpf.h>
|
||||
#include <capstone/capstone.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
|
@ -61,6 +61,8 @@ TestDetailBPFOp *test_detail_bpf_op_clone(const TestDetailBPFOp *op)
|
|||
clone->ext = op->ext ? strdup(op->ext) : NULL;
|
||||
clone->mem_base = op->mem_base ? strdup(op->mem_base) : NULL;
|
||||
clone->mem_disp = op->mem_disp;
|
||||
clone->is_pkt = op->is_pkt;
|
||||
clone->is_signed = op->is_signed;
|
||||
|
||||
return clone;
|
||||
}
|
||||
|
|
@ -89,6 +91,8 @@ bool test_expected_bpf(csh *handle, const cs_bpf *actual,
|
|||
TestDetailBPFOp *eop = expected->operands[i];
|
||||
compare_enum_ret(op->type, eop->type, false);
|
||||
compare_enum_ret(op->access, eop->access, false);
|
||||
compare_tbool_ret(op->is_pkt, eop->is_pkt, false);
|
||||
compare_tbool_ret(op->is_signed, eop->is_signed, false);
|
||||
switch (op->type) {
|
||||
default:
|
||||
fprintf(stderr,
|
||||
|
|
|
|||
|
|
@ -34,7 +34,7 @@ test_cases:
|
|||
expected:
|
||||
insns:
|
||||
-
|
||||
asm_text: "jmp +0xd52cc837"
|
||||
asm_text: "ja +0xd52cc837"
|
||||
-
|
||||
input:
|
||||
bytes: [ 0x06, 0x00, 0xa7, 0x84, 0x25, 0x40, 0x28, 0x1c ]
|
||||
|
|
|
|||
|
|
@ -16,7 +16,7 @@ test_cases:
|
|||
expected:
|
||||
insns:
|
||||
-
|
||||
asm_text: "jmp +0xb071"
|
||||
asm_text: "ja -0x4f8f"
|
||||
-
|
||||
input:
|
||||
bytes: [ 0x07, 0x76, 0x01, 0x28, 0xc4, 0x09, 0xfe, 0x8b ]
|
||||
|
|
@ -115,7 +115,7 @@ test_cases:
|
|||
expected:
|
||||
insns:
|
||||
-
|
||||
asm_text: "ldw [0xca1a41da]"
|
||||
asm_text: "ldabsw [skb-0x35e5be26]"
|
||||
-
|
||||
input:
|
||||
bytes: [ 0x24, 0xb6, 0x69, 0x66, 0xe3, 0xef, 0xec, 0x25 ]
|
||||
|
|
@ -151,7 +151,7 @@ test_cases:
|
|||
expected:
|
||||
insns:
|
||||
-
|
||||
asm_text: "ldh [0xd0b48e8]"
|
||||
asm_text: "ldabsh [skb+0xd0b48e8]"
|
||||
-
|
||||
input:
|
||||
bytes: [ 0x2c, 0x78, 0x03, 0xf6, 0x29, 0x29, 0x15, 0xfc ]
|
||||
|
|
@ -169,7 +169,7 @@ test_cases:
|
|||
expected:
|
||||
insns:
|
||||
-
|
||||
asm_text: "jgt r8, r1, +0xfd5b"
|
||||
asm_text: "jgt r8, r1, -0x2a5"
|
||||
-
|
||||
input:
|
||||
bytes: [ 0x2f, 0x77, 0xc7, 0xa4, 0x4c, 0x32, 0x73, 0x2a ]
|
||||
|
|
@ -187,10 +187,10 @@ test_cases:
|
|||
expected:
|
||||
insns:
|
||||
-
|
||||
asm_text: "ldb [0x4b7c6685]"
|
||||
asm_text: "ldabsb [skb+0x4b7c6685]"
|
||||
-
|
||||
input:
|
||||
bytes: [ 0x34, 0x46, 0x49, 0x33, 0xe1, 0x72, 0xd4, 0xcb ]
|
||||
bytes: [ 0x34, 0x46, 0x00, 0x00, 0xe1, 0x72, 0xd4, 0xcb ]
|
||||
arch: "CS_ARCH_BPF"
|
||||
options: [ "CS_MODE_BPF_EXTENDED", "CS_MODE_LITTLE_ENDIAN" ]
|
||||
expected:
|
||||
|
|
@ -205,10 +205,10 @@ test_cases:
|
|||
expected:
|
||||
insns:
|
||||
-
|
||||
asm_text: "jge r5, 0x3da1375b, +0xb942"
|
||||
asm_text: "jge r5, 0x3da1375b, -0x46be"
|
||||
-
|
||||
input:
|
||||
bytes: [ 0x37, 0x84, 0xd8, 0xba, 0x3b, 0x84, 0x55, 0x1f ]
|
||||
bytes: [ 0x37, 0x84, 0x00, 0x00, 0x3b, 0x84, 0x55, 0x1f ]
|
||||
arch: "CS_ARCH_BPF"
|
||||
options: [ "CS_MODE_BPF_EXTENDED", "CS_MODE_LITTLE_ENDIAN" ]
|
||||
expected:
|
||||
|
|
@ -217,25 +217,7 @@ test_cases:
|
|||
asm_text: "div64 r4, 0x1f55843b"
|
||||
-
|
||||
input:
|
||||
bytes: [ 0x38, 0x8e, 0x3f, 0xd7, 0x1c, 0x3e, 0x3a, 0x7b ]
|
||||
arch: "CS_ARCH_BPF"
|
||||
options: [ "CS_MODE_BPF_EXTENDED", "CS_MODE_LITTLE_ENDIAN" ]
|
||||
expected:
|
||||
insns:
|
||||
-
|
||||
asm_text: "lddw [0x7b3a3e1c]"
|
||||
-
|
||||
input:
|
||||
bytes: [ 0x3d, 0x1a, 0xc3, 0x9b, 0x88, 0xa2, 0x3f, 0x65 ]
|
||||
arch: "CS_ARCH_BPF"
|
||||
options: [ "CS_MODE_BPF_EXTENDED", "CS_MODE_LITTLE_ENDIAN" ]
|
||||
expected:
|
||||
insns:
|
||||
-
|
||||
asm_text: "jge r10, r1, +0x9bc3"
|
||||
-
|
||||
input:
|
||||
bytes: [ 0x3f, 0x36, 0x99, 0x32, 0x7e, 0x07, 0x59, 0x7a ]
|
||||
bytes: [ 0x3f, 0x36, 0x00, 0x00, 0x7e, 0x07, 0x59, 0x7a ]
|
||||
arch: "CS_ARCH_BPF"
|
||||
options: [ "CS_MODE_BPF_EXTENDED", "CS_MODE_LITTLE_ENDIAN" ]
|
||||
expected:
|
||||
|
|
@ -250,7 +232,7 @@ test_cases:
|
|||
expected:
|
||||
insns:
|
||||
-
|
||||
asm_text: "ldw [r9+0xc4d7e76b]"
|
||||
asm_text: "ldindw [skb+r9]"
|
||||
-
|
||||
input:
|
||||
bytes: [ 0x44, 0x16, 0xf7, 0x98, 0xf7, 0x02, 0x92, 0x94 ]
|
||||
|
|
@ -268,7 +250,7 @@ test_cases:
|
|||
expected:
|
||||
insns:
|
||||
-
|
||||
asm_text: "jset r2, 0x1e2de714, +0xf2a2"
|
||||
asm_text: "jset r2, 0x1e2de714, -0xd5e"
|
||||
-
|
||||
input:
|
||||
bytes: [ 0x47, 0x36, 0xf4, 0xd5, 0xbe, 0x04, 0x58, 0x4d ]
|
||||
|
|
@ -286,7 +268,7 @@ test_cases:
|
|||
expected:
|
||||
insns:
|
||||
-
|
||||
asm_text: "ldh [r7+0xd5a0eeb]"
|
||||
asm_text: "ldindh [skb+r7]"
|
||||
-
|
||||
input:
|
||||
bytes: [ 0x4c, 0x81, 0x0a, 0x66, 0xfc, 0x32, 0x61, 0xc4 ]
|
||||
|
|
@ -322,7 +304,7 @@ test_cases:
|
|||
expected:
|
||||
insns:
|
||||
-
|
||||
asm_text: "ldb [r3+0x6cd17004]"
|
||||
asm_text: "ldindb [skb+r3]"
|
||||
-
|
||||
input:
|
||||
bytes: [ 0x54, 0x40, 0x0a, 0x6a, 0x4a, 0xe8, 0xab, 0xfb ]
|
||||
|
|
@ -340,7 +322,7 @@ test_cases:
|
|||
expected:
|
||||
insns:
|
||||
-
|
||||
asm_text: "jne r9, 0x96c8bc90, +0x80a3"
|
||||
asm_text: "jne r9, 0x96c8bc90, -0x7f5d"
|
||||
-
|
||||
input:
|
||||
bytes: [ 0x57, 0x30, 0x12, 0xe9, 0x7c, 0x06, 0x82, 0x27 ]
|
||||
|
|
@ -350,15 +332,6 @@ test_cases:
|
|||
insns:
|
||||
-
|
||||
asm_text: "and64 r0, 0x2782067c"
|
||||
-
|
||||
input:
|
||||
bytes: [ 0x58, 0x6d, 0xf1, 0x05, 0xd3, 0x50, 0x4b, 0xc0 ]
|
||||
arch: "CS_ARCH_BPF"
|
||||
options: [ "CS_MODE_BPF_EXTENDED", "CS_MODE_LITTLE_ENDIAN" ]
|
||||
expected:
|
||||
insns:
|
||||
-
|
||||
asm_text: "lddw [r6+0xc04b50d3]"
|
||||
-
|
||||
input:
|
||||
bytes: [ 0x5c, 0x02, 0x95, 0xb2, 0xbd, 0x3f, 0x38, 0x37 ]
|
||||
|
|
@ -394,7 +367,7 @@ test_cases:
|
|||
expected:
|
||||
insns:
|
||||
-
|
||||
asm_text: "ldxw r8, [r2+0xedb2]"
|
||||
asm_text: "ldxw r8, [r2-0x124e]"
|
||||
-
|
||||
input:
|
||||
bytes: [ 0x62, 0xa5, 0xdf, 0xe0, 0x14, 0x7d, 0x95, 0x78 ]
|
||||
|
|
@ -403,7 +376,7 @@ test_cases:
|
|||
expected:
|
||||
insns:
|
||||
-
|
||||
asm_text: "stw [r5+0xe0df], 0x78957d14"
|
||||
asm_text: "stw [r5-0x1f21], 0x78957d14"
|
||||
-
|
||||
input:
|
||||
bytes: [ 0x63, 0x77, 0x2f, 0xcf, 0x76, 0xb7, 0xd3, 0xfa ]
|
||||
|
|
@ -412,7 +385,7 @@ test_cases:
|
|||
expected:
|
||||
insns:
|
||||
-
|
||||
asm_text: "stxw [r7+0xcf2f], r7"
|
||||
asm_text: "stxw [r7-0x30d1], r7"
|
||||
-
|
||||
input:
|
||||
bytes: [ 0x64, 0x68, 0xc1, 0xf4, 0x88, 0x92, 0xd2, 0xeb ]
|
||||
|
|
@ -430,7 +403,7 @@ test_cases:
|
|||
expected:
|
||||
insns:
|
||||
-
|
||||
asm_text: "jsgt r8, 0xf88fbe87, +0xe197"
|
||||
asm_text: "jsgt r8, 0xf88fbe87, -0x1e69"
|
||||
-
|
||||
input:
|
||||
bytes: [ 0x67, 0x00, 0xd7, 0xc0, 0x05, 0xb0, 0xf6, 0x74 ]
|
||||
|
|
@ -448,7 +421,7 @@ test_cases:
|
|||
expected:
|
||||
insns:
|
||||
-
|
||||
asm_text: "ldxh r4, [r1+0x8ec7]"
|
||||
asm_text: "ldxh r4, [r1-0x7139]"
|
||||
-
|
||||
input:
|
||||
bytes: [ 0x6a, 0xb5, 0xbc, 0x8c, 0x4f, 0x5c, 0x94, 0x01 ]
|
||||
|
|
@ -457,7 +430,7 @@ test_cases:
|
|||
expected:
|
||||
insns:
|
||||
-
|
||||
asm_text: "sth [r5+0x8cbc], 0x1945c4f"
|
||||
asm_text: "sth [r5-0x7344], 0x1945c4f"
|
||||
-
|
||||
input:
|
||||
bytes: [ 0x6b, 0x34, 0x58, 0xf5, 0xc8, 0x27, 0x9e, 0x14 ]
|
||||
|
|
@ -466,7 +439,7 @@ test_cases:
|
|||
expected:
|
||||
insns:
|
||||
-
|
||||
asm_text: "stxh [r4+0xf558], r3"
|
||||
asm_text: "stxh [r4-0xaa8], r3"
|
||||
-
|
||||
input:
|
||||
bytes: [ 0x6c, 0x21, 0x10, 0x48, 0x01, 0x3e, 0x6e, 0xf8 ]
|
||||
|
|
@ -484,7 +457,7 @@ test_cases:
|
|||
expected:
|
||||
insns:
|
||||
-
|
||||
asm_text: "jsgt r8, r3, +0xe369"
|
||||
asm_text: "jsgt r8, r3, -0x1c97"
|
||||
-
|
||||
input:
|
||||
bytes: [ 0x6f, 0x64, 0x49, 0xd6, 0x07, 0xa9, 0x93, 0x13 ]
|
||||
|
|
@ -502,7 +475,7 @@ test_cases:
|
|||
expected:
|
||||
insns:
|
||||
-
|
||||
asm_text: "ldxb r0, [r10+0xfbeb]"
|
||||
asm_text: "ldxb r0, [r10-0x415]"
|
||||
-
|
||||
input:
|
||||
bytes: [ 0x72, 0xe2, 0xc1, 0x1b, 0x25, 0x2f, 0x4a, 0xdc ]
|
||||
|
|
@ -620,6 +593,15 @@ test_cases:
|
|||
insns:
|
||||
-
|
||||
asm_text: "call 0x5dbd3d83"
|
||||
-
|
||||
input:
|
||||
bytes: [ 0x85, 0x00, 0x00, 0xe2, 0x83, 0x3d, 0xbd, 0xfd ]
|
||||
arch: "CS_ARCH_BPF"
|
||||
options: [ "CS_MODE_BPF_EXTENDED", "CS_MODE_LITTLE_ENDIAN" ]
|
||||
expected:
|
||||
insns:
|
||||
-
|
||||
asm_text: "call -0x242c27d"
|
||||
-
|
||||
input:
|
||||
bytes: [ 0x87, 0xf5, 0x2b, 0xbe, 0xa9, 0xc7, 0x31, 0xa3 ]
|
||||
|
|
@ -631,7 +613,7 @@ test_cases:
|
|||
asm_text: "neg64 r5"
|
||||
-
|
||||
input:
|
||||
bytes: [ 0x94, 0x39, 0x0d, 0xdc, 0x0b, 0xd2, 0xd1, 0xc9 ]
|
||||
bytes: [ 0x94, 0x39, 0x00, 0x00, 0x0b, 0xd2, 0xd1, 0xc9 ]
|
||||
arch: "CS_ARCH_BPF"
|
||||
options: [ "CS_MODE_BPF_EXTENDED", "CS_MODE_LITTLE_ENDIAN" ]
|
||||
expected:
|
||||
|
|
@ -649,7 +631,7 @@ test_cases:
|
|||
asm_text: "exit"
|
||||
-
|
||||
input:
|
||||
bytes: [ 0x97, 0xc8, 0xa6, 0x75, 0xd2, 0x09, 0x98, 0x09 ]
|
||||
bytes: [ 0x97, 0xc8, 0x00, 0x00, 0xd2, 0x09, 0x98, 0x09 ]
|
||||
arch: "CS_ARCH_BPF"
|
||||
options: [ "CS_MODE_BPF_EXTENDED", "CS_MODE_LITTLE_ENDIAN" ]
|
||||
expected:
|
||||
|
|
@ -658,7 +640,7 @@ test_cases:
|
|||
asm_text: "mod64 r8, 0x99809d2"
|
||||
-
|
||||
input:
|
||||
bytes: [ 0x9c, 0x96, 0xe7, 0x16, 0x0f, 0x69, 0x13, 0x90 ]
|
||||
bytes: [ 0x9c, 0x96, 0x00, 0x00, 0x0f, 0x69, 0x13, 0x90 ]
|
||||
arch: "CS_ARCH_BPF"
|
||||
options: [ "CS_MODE_BPF_EXTENDED", "CS_MODE_LITTLE_ENDIAN" ]
|
||||
expected:
|
||||
|
|
@ -667,7 +649,7 @@ test_cases:
|
|||
asm_text: "mod r6, r9"
|
||||
-
|
||||
input:
|
||||
bytes: [ 0x9f, 0x35, 0x5a, 0x59, 0xd6, 0x70, 0xd9, 0x5e ]
|
||||
bytes: [ 0x9f, 0x35, 0x00, 0x00, 0xd6, 0x70, 0xd9, 0x5e ]
|
||||
arch: "CS_ARCH_BPF"
|
||||
options: [ "CS_MODE_BPF_EXTENDED", "CS_MODE_LITTLE_ENDIAN" ]
|
||||
expected:
|
||||
|
|
@ -721,7 +703,7 @@ test_cases:
|
|||
asm_text: "xor64 r1, r4"
|
||||
-
|
||||
input:
|
||||
bytes: [ 0xb4, 0xa1, 0x9c, 0x78, 0xf9, 0x3f, 0x77, 0x1f ]
|
||||
bytes: [ 0xb4, 0xa1, 0x00, 0x00, 0xf9, 0x3f, 0x77, 0x1f ]
|
||||
arch: "CS_ARCH_BPF"
|
||||
options: [ "CS_MODE_BPF_EXTENDED", "CS_MODE_LITTLE_ENDIAN" ]
|
||||
expected:
|
||||
|
|
@ -739,7 +721,7 @@ test_cases:
|
|||
asm_text: "jle r2, 0x33fc3349, +0x5a5d"
|
||||
-
|
||||
input:
|
||||
bytes: [ 0xb7, 0x70, 0x59, 0x4d, 0x5b, 0x52, 0x2a, 0x99 ]
|
||||
bytes: [ 0xb7, 0x70, 0x00, 0x00, 0x5b, 0x52, 0x2a, 0x99 ]
|
||||
arch: "CS_ARCH_BPF"
|
||||
options: [ "CS_MODE_BPF_EXTENDED", "CS_MODE_LITTLE_ENDIAN" ]
|
||||
expected:
|
||||
|
|
@ -748,7 +730,7 @@ test_cases:
|
|||
asm_text: "mov64 r0, 0x992a525b"
|
||||
-
|
||||
input:
|
||||
bytes: [ 0xbc, 0x72, 0x3e, 0x6c, 0xc9, 0x8a, 0x56, 0xd6 ]
|
||||
bytes: [ 0xbc, 0x72, 0x00, 0x00, 0xc9, 0x8a, 0x56, 0xd6 ]
|
||||
arch: "CS_ARCH_BPF"
|
||||
options: [ "CS_MODE_BPF_EXTENDED", "CS_MODE_LITTLE_ENDIAN" ]
|
||||
expected:
|
||||
|
|
@ -763,10 +745,10 @@ test_cases:
|
|||
expected:
|
||||
insns:
|
||||
-
|
||||
asm_text: "jle r9, r1, +0xe880"
|
||||
asm_text: "jle r9, r1, -0x1780"
|
||||
-
|
||||
input:
|
||||
bytes: [ 0xbf, 0x86, 0x55, 0x58, 0xb2, 0x6d, 0x14, 0x03 ]
|
||||
bytes: [ 0xbf, 0x86, 0x00, 0x00, 0xb2, 0x6d, 0x14, 0x03 ]
|
||||
arch: "CS_ARCH_BPF"
|
||||
options: [ "CS_MODE_BPF_EXTENDED", "CS_MODE_LITTLE_ENDIAN" ]
|
||||
expected:
|
||||
|
|
@ -790,7 +772,7 @@ test_cases:
|
|||
expected:
|
||||
insns:
|
||||
-
|
||||
asm_text: "jslt r2, 0x4fcec0ba, +0xe4eb"
|
||||
asm_text: "jslt r2, 0x4fcec0ba, -0x1b15"
|
||||
-
|
||||
input:
|
||||
bytes: [ 0xc7, 0xe8, 0xba, 0xff, 0x1f, 0xef, 0xc0, 0x88 ]
|
||||
|
|
@ -817,7 +799,7 @@ test_cases:
|
|||
expected:
|
||||
insns:
|
||||
-
|
||||
asm_text: "jslt r0, r9, +0x8867"
|
||||
asm_text: "jslt r0, r9, -0x7799"
|
||||
-
|
||||
input:
|
||||
bytes: [ 0xcf, 0x82, 0xe1, 0xcd, 0xbe, 0xc3, 0x2d, 0x7c ]
|
||||
|
|
@ -844,7 +826,7 @@ test_cases:
|
|||
expected:
|
||||
insns:
|
||||
-
|
||||
asm_text: "jsle r9, 0xe5b0fd50, +0xb2f6"
|
||||
asm_text: "jsle r9, 0xe5b0fd50, -0x4d0a"
|
||||
-
|
||||
input:
|
||||
bytes: [ 0xdc, 0xb2, 0xa3, 0x50, 0x20, 0x00, 0x00, 0x00 ]
|
||||
|
|
@ -862,7 +844,16 @@ test_cases:
|
|||
expected:
|
||||
insns:
|
||||
-
|
||||
asm_text: "jsle r5, r9, +0xb1bf"
|
||||
asm_text: "jsle r5, r9, -0x4e41"
|
||||
-
|
||||
input:
|
||||
bytes: [ 0x2d, 0x18, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00 ]
|
||||
arch: "CS_ARCH_BPF"
|
||||
options: [ "CS_MODE_BPF_EXTENDED", "CS_MODE_LITTLE_ENDIAN" ]
|
||||
expected:
|
||||
insns:
|
||||
-
|
||||
asm_text: "jgt r8, r1, +0x7"
|
||||
-
|
||||
input:
|
||||
bytes: [ 0x8d, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00 ]
|
||||
|
|
@ -872,3 +863,355 @@ test_cases:
|
|||
insns:
|
||||
-
|
||||
asm_text: "callx r2"
|
||||
|
||||
- input:
|
||||
bytes: [ 0x06, 0xc7, 0x0f, 0xcc, 0x43, 0x1f, 0xb9, 0xf5 ]
|
||||
arch: "CS_ARCH_BPF"
|
||||
options: [ "CS_MODE_BPF_EXTENDED", "CS_MODE_LITTLE_ENDIAN" ]
|
||||
expected:
|
||||
insns:
|
||||
-
|
||||
asm_text: "jal -0xa46e0bd"
|
||||
|
||||
- input:
|
||||
bytes: [ 0x16, 0xc7, 0x0f, 0xcc, 0x43, 0x1f, 0xb9, 0xf5 ]
|
||||
arch: "CS_ARCH_BPF"
|
||||
options: [ "CS_MODE_BPF_EXTENDED", "CS_MODE_LITTLE_ENDIAN" ]
|
||||
expected:
|
||||
insns:
|
||||
-
|
||||
asm_text: "jeq32 r7, -0xa46e0bd, -0x33f1"
|
||||
|
||||
- input:
|
||||
bytes: [ 0x26, 0xc7, 0x0f, 0xcc, 0x43, 0x1f, 0xb9, 0xf5 ]
|
||||
arch: "CS_ARCH_BPF"
|
||||
options: [ "CS_MODE_BPF_EXTENDED", "CS_MODE_LITTLE_ENDIAN" ]
|
||||
expected:
|
||||
insns:
|
||||
-
|
||||
asm_text: "jgt32 r7, -0xa46e0bd, -0x33f1"
|
||||
|
||||
- input:
|
||||
bytes: [ 0x36, 0xc7, 0x0f, 0xcc, 0x43, 0x1f, 0xb9, 0xf5 ]
|
||||
arch: "CS_ARCH_BPF"
|
||||
options: [ "CS_MODE_BPF_EXTENDED", "CS_MODE_LITTLE_ENDIAN" ]
|
||||
expected:
|
||||
insns:
|
||||
-
|
||||
asm_text: "jge32 r7, -0xa46e0bd, -0x33f1"
|
||||
|
||||
- input:
|
||||
bytes: [ 0x46, 0xc7, 0x0f, 0xcc, 0x43, 0x1f, 0xb9, 0xf5 ]
|
||||
arch: "CS_ARCH_BPF"
|
||||
options: [ "CS_MODE_BPF_EXTENDED", "CS_MODE_LITTLE_ENDIAN" ]
|
||||
expected:
|
||||
insns:
|
||||
-
|
||||
asm_text: "jset32 r7, -0xa46e0bd, -0x33f1"
|
||||
|
||||
- input:
|
||||
bytes: [ 0x56, 0xc7, 0x0f, 0xcc, 0x43, 0x1f, 0xb9, 0xf5 ]
|
||||
arch: "CS_ARCH_BPF"
|
||||
options: [ "CS_MODE_BPF_EXTENDED", "CS_MODE_LITTLE_ENDIAN" ]
|
||||
expected:
|
||||
insns:
|
||||
-
|
||||
asm_text: "jne32 r7, -0xa46e0bd, -0x33f1"
|
||||
|
||||
- input:
|
||||
bytes: [ 0x66, 0xc7, 0x0f, 0xcc, 0x43, 0x1f, 0xb9, 0xf5 ]
|
||||
arch: "CS_ARCH_BPF"
|
||||
options: [ "CS_MODE_BPF_EXTENDED", "CS_MODE_LITTLE_ENDIAN" ]
|
||||
expected:
|
||||
insns:
|
||||
-
|
||||
asm_text: "jsgt32 r7, -0xa46e0bd, -0x33f1"
|
||||
|
||||
- input:
|
||||
bytes: [ 0x76, 0xc7, 0x0f, 0xcc, 0x43, 0x1f, 0xb9, 0xf5 ]
|
||||
arch: "CS_ARCH_BPF"
|
||||
options: [ "CS_MODE_BPF_EXTENDED", "CS_MODE_LITTLE_ENDIAN" ]
|
||||
expected:
|
||||
insns:
|
||||
-
|
||||
asm_text: "jsge32 r7, -0xa46e0bd, -0x33f1"
|
||||
|
||||
- input:
|
||||
bytes: [ 0xa6, 0xc7, 0x0f, 0xcc, 0x43, 0x1f, 0xb9, 0xf5 ]
|
||||
arch: "CS_ARCH_BPF"
|
||||
options: [ "CS_MODE_BPF_EXTENDED", "CS_MODE_LITTLE_ENDIAN" ]
|
||||
expected:
|
||||
insns:
|
||||
-
|
||||
asm_text: "jlt32 r7, -0xa46e0bd, -0x33f1"
|
||||
|
||||
- input:
|
||||
bytes: [ 0xb6, 0xc7, 0x0f, 0xcc, 0x43, 0x1f, 0xb9, 0xf5 ]
|
||||
arch: "CS_ARCH_BPF"
|
||||
options: [ "CS_MODE_BPF_EXTENDED", "CS_MODE_LITTLE_ENDIAN" ]
|
||||
expected:
|
||||
insns:
|
||||
-
|
||||
asm_text: "jle32 r7, -0xa46e0bd, -0x33f1"
|
||||
|
||||
- input:
|
||||
bytes: [ 0xc6, 0xc7, 0x0f, 0xcc, 0x43, 0x1f, 0xb9, 0xf5 ]
|
||||
arch: "CS_ARCH_BPF"
|
||||
options: [ "CS_MODE_BPF_EXTENDED", "CS_MODE_LITTLE_ENDIAN" ]
|
||||
expected:
|
||||
insns:
|
||||
-
|
||||
asm_text: "jslt32 r7, -0xa46e0bd, -0x33f1"
|
||||
|
||||
- input:
|
||||
bytes: [ 0xd6, 0xc7, 0x0f, 0xcc, 0x43, 0x1f, 0xb9, 0xf5 ]
|
||||
arch: "CS_ARCH_BPF"
|
||||
options: [ "CS_MODE_BPF_EXTENDED", "CS_MODE_LITTLE_ENDIAN" ]
|
||||
expected:
|
||||
insns:
|
||||
-
|
||||
asm_text: "jsle32 r7, -0xa46e0bd, -0x33f1"
|
||||
-
|
||||
input:
|
||||
bytes: [ 0x37, 0x84, 0x01, 0x00, 0x3b, 0x84, 0x55, 0x1f ]
|
||||
arch: "CS_ARCH_BPF"
|
||||
options: [ "CS_MODE_BPF_EXTENDED", "CS_MODE_LITTLE_ENDIAN" ]
|
||||
expected:
|
||||
insns:
|
||||
-
|
||||
asm_text: "sdiv64 r4, 0x1f55843b"
|
||||
-
|
||||
input:
|
||||
bytes: [ 0x34, 0x46, 0x01, 0x00, 0xe1, 0x72, 0xd4, 0xcb ]
|
||||
arch: "CS_ARCH_BPF"
|
||||
options: [ "CS_MODE_BPF_EXTENDED", "CS_MODE_LITTLE_ENDIAN" ]
|
||||
expected:
|
||||
insns:
|
||||
-
|
||||
asm_text: "sdiv r6, 0xcbd472e1"
|
||||
-
|
||||
input:
|
||||
bytes: [ 0x94, 0x39, 0x01, 0x00, 0x0b, 0xd2, 0xd1, 0xc9 ]
|
||||
arch: "CS_ARCH_BPF"
|
||||
options: [ "CS_MODE_BPF_EXTENDED", "CS_MODE_LITTLE_ENDIAN" ]
|
||||
expected:
|
||||
insns:
|
||||
-
|
||||
asm_text: "smod r9, 0xc9d1d20b"
|
||||
|
||||
-
|
||||
input:
|
||||
bytes: [ 0x9f, 0x35, 0x01, 0x00, 0xd6, 0x70, 0xd9, 0x5e ]
|
||||
arch: "CS_ARCH_BPF"
|
||||
options: [ "CS_MODE_BPF_EXTENDED", "CS_MODE_LITTLE_ENDIAN" ]
|
||||
expected:
|
||||
insns:
|
||||
-
|
||||
asm_text: "smod64 r5, r3"
|
||||
|
||||
- input:
|
||||
bytes: [ 0xbf, 0x31, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00 ]
|
||||
arch: "CS_ARCH_BPF"
|
||||
options: [ "CS_MODE_BPF_EXTENDED", "CS_MODE_LITTLE_ENDIAN" ]
|
||||
expected:
|
||||
insns:
|
||||
-
|
||||
asm_text: "movsb64 r1, r3"
|
||||
|
||||
- input:
|
||||
bytes: [ 0xbf, 0x31, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00 ]
|
||||
arch: "CS_ARCH_BPF"
|
||||
options: [ "CS_MODE_BPF_EXTENDED", "CS_MODE_LITTLE_ENDIAN" ]
|
||||
expected:
|
||||
insns:
|
||||
-
|
||||
asm_text: "movsh64 r1, r3"
|
||||
|
||||
- input:
|
||||
bytes: [ 0xbf, 0x31, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00 ]
|
||||
arch: "CS_ARCH_BPF"
|
||||
options: [ "CS_MODE_BPF_EXTENDED", "CS_MODE_LITTLE_ENDIAN" ]
|
||||
expected:
|
||||
insns:
|
||||
-
|
||||
asm_text: "movsw64 r1, r3"
|
||||
|
||||
- input:
|
||||
bytes: [ 0xbc, 0x31, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00 ]
|
||||
arch: "CS_ARCH_BPF"
|
||||
options: [ "CS_MODE_BPF_EXTENDED", "CS_MODE_LITTLE_ENDIAN" ]
|
||||
expected:
|
||||
insns:
|
||||
-
|
||||
asm_text: "movsb r1, r3"
|
||||
|
||||
- input:
|
||||
bytes: [ 0xbc, 0x31, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00 ]
|
||||
arch: "CS_ARCH_BPF"
|
||||
options: [ "CS_MODE_BPF_EXTENDED", "CS_MODE_LITTLE_ENDIAN" ]
|
||||
expected:
|
||||
insns:
|
||||
-
|
||||
asm_text: "movsh r1, r3"
|
||||
|
||||
- input:
|
||||
bytes: [ 0xdb, 0x1a, 0xfc, 0xff, 0x00, 0x00, 0x00, 0x00 ]
|
||||
arch: "CS_ARCH_BPF"
|
||||
options: [ "CS_MODE_BPF_EXTENDED", "CS_MODE_LITTLE_ENDIAN" ]
|
||||
expected:
|
||||
insns:
|
||||
-
|
||||
asm_text: "aadd64 [r10-0x4], r1"
|
||||
|
||||
- input:
|
||||
bytes: [ 0xdb, 0x1a, 0xfc, 0xff, 0x01, 0x00, 0x00, 0x00 ]
|
||||
arch: "CS_ARCH_BPF"
|
||||
options: [ "CS_MODE_BPF_EXTENDED", "CS_MODE_LITTLE_ENDIAN" ]
|
||||
expected:
|
||||
insns:
|
||||
-
|
||||
asm_text: "afadd64 [r10-0x4], r1"
|
||||
|
||||
- input:
|
||||
bytes: [ 0xdb, 0x1a, 0xfc, 0xff, 0x40, 0x00, 0x00, 0x00 ]
|
||||
arch: "CS_ARCH_BPF"
|
||||
options: [ "CS_MODE_BPF_EXTENDED", "CS_MODE_LITTLE_ENDIAN" ]
|
||||
expected:
|
||||
insns:
|
||||
-
|
||||
asm_text: "aor64 [r10-0x4], r1"
|
||||
|
||||
- input:
|
||||
bytes: [ 0xdb, 0x1a, 0xfc, 0xff, 0x41, 0x00, 0x00, 0x00 ]
|
||||
arch: "CS_ARCH_BPF"
|
||||
options: [ "CS_MODE_BPF_EXTENDED", "CS_MODE_LITTLE_ENDIAN" ]
|
||||
expected:
|
||||
insns:
|
||||
-
|
||||
asm_text: "afor64 [r10-0x4], r1"
|
||||
|
||||
- input:
|
||||
bytes: [ 0xdb, 0x1a, 0xfc, 0xff, 0x50, 0x00, 0x00, 0x00 ]
|
||||
arch: "CS_ARCH_BPF"
|
||||
options: [ "CS_MODE_BPF_EXTENDED", "CS_MODE_LITTLE_ENDIAN" ]
|
||||
expected:
|
||||
insns:
|
||||
-
|
||||
asm_text: "aand64 [r10-0x4], r1"
|
||||
|
||||
- input:
|
||||
bytes: [ 0xdb, 0x1a, 0xfc, 0xff, 0x51, 0x00, 0x00, 0x00 ]
|
||||
arch: "CS_ARCH_BPF"
|
||||
options: [ "CS_MODE_BPF_EXTENDED", "CS_MODE_LITTLE_ENDIAN" ]
|
||||
expected:
|
||||
insns:
|
||||
-
|
||||
asm_text: "afand64 [r10-0x4], r1"
|
||||
|
||||
- input:
|
||||
bytes: [ 0xdb, 0x1a, 0xfc, 0xff, 0xa0, 0x00, 0x00, 0x00 ]
|
||||
arch: "CS_ARCH_BPF"
|
||||
options: [ "CS_MODE_BPF_EXTENDED", "CS_MODE_LITTLE_ENDIAN" ]
|
||||
expected:
|
||||
insns:
|
||||
-
|
||||
asm_text: "axor64 [r10-0x4], r1"
|
||||
|
||||
- input:
|
||||
bytes: [ 0xdb, 0x1a, 0xfc, 0xff, 0xa1, 0x00, 0x00, 0x00 ]
|
||||
arch: "CS_ARCH_BPF"
|
||||
options: [ "CS_MODE_BPF_EXTENDED", "CS_MODE_LITTLE_ENDIAN" ]
|
||||
expected:
|
||||
insns:
|
||||
-
|
||||
asm_text: "afxor64 [r10-0x4], r1"
|
||||
|
||||
- input:
|
||||
bytes: [ 0xdb, 0x1a, 0xfc, 0xff, 0xe1, 0x00, 0x00, 0x00 ]
|
||||
arch: "CS_ARCH_BPF"
|
||||
options: [ "CS_MODE_BPF_EXTENDED", "CS_MODE_LITTLE_ENDIAN" ]
|
||||
expected:
|
||||
insns:
|
||||
-
|
||||
asm_text: "axchg64 [r10-0x4], r1"
|
||||
|
||||
- input:
|
||||
bytes: [ 0xdb, 0x1a, 0xfc, 0xff, 0xf1, 0x00, 0x00, 0x00 ]
|
||||
arch: "CS_ARCH_BPF"
|
||||
options: [ "CS_MODE_BPF_EXTENDED", "CS_MODE_LITTLE_ENDIAN" ]
|
||||
expected:
|
||||
insns:
|
||||
-
|
||||
asm_text: "acmpxchg64 [r10-0x4], r1"
|
||||
|
||||
- input:
|
||||
bytes: [ 0xc3, 0x1a, 0xfc, 0xff, 0x00, 0x00, 0x00, 0x00 ]
|
||||
arch: "CS_ARCH_BPF"
|
||||
options: [ "CS_MODE_BPF_EXTENDED", "CS_MODE_LITTLE_ENDIAN" ]
|
||||
expected:
|
||||
insns:
|
||||
-
|
||||
asm_text: "aadd [r10-0x4], r1"
|
||||
|
||||
- input:
|
||||
bytes: [ 0xc3, 0x1a, 0xfc, 0xff, 0x01, 0x00, 0x00, 0x00 ]
|
||||
arch: "CS_ARCH_BPF"
|
||||
options: [ "CS_MODE_BPF_EXTENDED", "CS_MODE_LITTLE_ENDIAN" ]
|
||||
expected:
|
||||
insns:
|
||||
-
|
||||
asm_text: "afadd [r10-0x4], r1"
|
||||
|
||||
- input:
|
||||
bytes: [ 0xc3, 0x1a, 0xfc, 0xff, 0x40, 0x00, 0x00, 0x00 ]
|
||||
arch: "CS_ARCH_BPF"
|
||||
options: [ "CS_MODE_BPF_EXTENDED", "CS_MODE_LITTLE_ENDIAN" ]
|
||||
expected:
|
||||
insns:
|
||||
-
|
||||
asm_text: "aor [r10-0x4], r1"
|
||||
|
||||
- input:
|
||||
bytes: [ 0xc3, 0x1a, 0xfc, 0xff, 0x41, 0x00, 0x00, 0x00 ]
|
||||
arch: "CS_ARCH_BPF"
|
||||
options: [ "CS_MODE_BPF_EXTENDED", "CS_MODE_LITTLE_ENDIAN" ]
|
||||
expected:
|
||||
insns:
|
||||
-
|
||||
asm_text: "afor [r10-0x4], r1"
|
||||
|
||||
- input:
|
||||
bytes: [ 0xc3, 0x1a, 0xfc, 0xff, 0x50, 0x00, 0x00, 0x00 ]
|
||||
arch: "CS_ARCH_BPF"
|
||||
options: [ "CS_MODE_BPF_EXTENDED", "CS_MODE_LITTLE_ENDIAN" ]
|
||||
expected:
|
||||
insns:
|
||||
-
|
||||
asm_text: "aand [r10-0x4], r1"
|
||||
|
||||
- input:
|
||||
bytes: [ 0xc3, 0x1a, 0xfc, 0xff, 0x51, 0x00, 0x00, 0x00 ]
|
||||
arch: "CS_ARCH_BPF"
|
||||
options: [ "CS_MODE_BPF_EXTENDED", "CS_MODE_LITTLE_ENDIAN" ]
|
||||
expected:
|
||||
insns:
|
||||
-
|
||||
asm_text: "afand [r10-0x4], r1"
|
||||
|
||||
- input:
|
||||
bytes: [ 0xc3, 0x1a, 0xfc, 0xff, 0xa0, 0x00, 0x00, 0x00 ]
|
||||
arch: "CS_ARCH_BPF"
|
||||
options: [ "CS_MODE_BPF_EXTENDED", "CS_MODE_LITTLE_ENDIAN" ]
|
||||
expected:
|
||||
insns:
|
||||
-
|
||||
asm_text: "axor [r10-0x4], r1"
|
||||
|
||||
- input:
|
||||
bytes: [ 0xc3, 0x1a, 0xfc, 0xff, 0xa1, 0x00, 0x00, 0x00 ]
|
||||
arch: "CS_ARCH_BPF"
|
||||
options: [ "CS_MODE_BPF_EXTENDED", "CS_MODE_LITTLE_ENDIAN" ]
|
||||
expected:
|
||||
insns:
|
||||
-
|
||||
asm_text: "afxor [r10-0x4], r1"
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ test_cases:
|
|||
expected:
|
||||
insns:
|
||||
-
|
||||
asm_text: "ldb [0x0]"
|
||||
asm_text: "ldabsb [skb+0x0]"
|
||||
-
|
||||
input:
|
||||
bytes: [ 0x28, 0x00, 0x00, 0x00, 0xfa, 0x00, 0x00, 0xff ]
|
||||
|
|
@ -16,7 +16,7 @@ test_cases:
|
|||
expected:
|
||||
insns:
|
||||
-
|
||||
asm_text: "ldh [0xfa0000ff]"
|
||||
asm_text: "ldabsh [skb-0x5ffff01]"
|
||||
-
|
||||
input:
|
||||
bytes: [ 0x40, 0x10, 0x00, 0x00, 0xcc, 0x00, 0x00, 0x00 ]
|
||||
|
|
@ -25,7 +25,7 @@ test_cases:
|
|||
expected:
|
||||
insns:
|
||||
-
|
||||
asm_text: "ldw [r1+0xcc000000]"
|
||||
asm_text: "ldindw [skb+r1]"
|
||||
-
|
||||
input:
|
||||
bytes: [ 0x18, 0x00, 0x00, 0x00, 0x0c, 0xb0, 0xce, 0xfa, 0x00, 0x00, 0x00, 0x00, 0xef, 0xbe, 0xad, 0xde ]
|
||||
|
|
@ -88,7 +88,7 @@ test_cases:
|
|||
expected:
|
||||
insns:
|
||||
-
|
||||
asm_text: "jmp +0x800"
|
||||
asm_text: "ja +0x800"
|
||||
-
|
||||
input:
|
||||
bytes: [ 0xdd, 0x35, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00 ]
|
||||
|
|
@ -107,24 +107,6 @@ test_cases:
|
|||
insns:
|
||||
-
|
||||
asm_text: "jlt r5, 0x10000000, +0x3000"
|
||||
-
|
||||
input:
|
||||
bytes: [ 0xc3, 0x12, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00 ]
|
||||
arch: "CS_ARCH_BPF"
|
||||
options: [ "CS_MODE_BPF_EXTENDED", "CS_MODE_BIG_ENDIAN" ]
|
||||
expected:
|
||||
insns:
|
||||
-
|
||||
asm_text: "xaddw [r2+0x10], r1"
|
||||
-
|
||||
input:
|
||||
bytes: [ 0xdb, 0xa9, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00 ]
|
||||
arch: "CS_ARCH_BPF"
|
||||
options: [ "CS_MODE_BPF_EXTENDED", "CS_MODE_BIG_ENDIAN" ]
|
||||
expected:
|
||||
insns:
|
||||
-
|
||||
asm_text: "xadddw [r9+0x1], r10"
|
||||
-
|
||||
input:
|
||||
bytes: [ 0x8d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02 ]
|
||||
|
|
|
|||
|
|
@ -84,7 +84,7 @@ test_cases:
|
|||
regs_read: [ r2 ]
|
||||
regs_write: [ r2 ]
|
||||
-
|
||||
asm_text: "ldb [0x0]"
|
||||
asm_text: "ldabsb [skb+0x0]"
|
||||
details:
|
||||
groups: [ BPF_GRP_LOAD ]
|
||||
bpf:
|
||||
|
|
@ -94,7 +94,7 @@ test_cases:
|
|||
mem_disp: 0x0
|
||||
regs_write: [ r0 ]
|
||||
-
|
||||
asm_text: "xadddw [r10+0x100], r3"
|
||||
asm_text: "aadd64 [r10+0x100], r3"
|
||||
details:
|
||||
groups: [ BPF_GRP_STORE ]
|
||||
bpf:
|
||||
|
|
@ -134,4 +134,47 @@ test_cases:
|
|||
type: BPF_OP_OFF
|
||||
off: 0x217
|
||||
regs_read: [ r3 ]
|
||||
-
|
||||
input:
|
||||
bytes: [ 0x28, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0xfa, 0x07, 0x76, 0x01, 0x28, 0xff, 0xff, 0xff, 0xff, 0x85, 0xd3, 0xa5, 0xe2, 0xff, 0xff, 0xff, 0xff ]
|
||||
arch: "bpf"
|
||||
options: [ CS_OPT_DETAIL, CS_MODE_BPF_EXTENDED ]
|
||||
address: 0x0
|
||||
expected:
|
||||
insns:
|
||||
-
|
||||
asm_text: "ldabsh [skb-0x5ffff01]"
|
||||
details:
|
||||
groups: [ BPF_GRP_LOAD ]
|
||||
bpf:
|
||||
operands:
|
||||
-
|
||||
type: BPF_OP_MEM
|
||||
mem_disp: 0xfa0000ff
|
||||
is_pkt: 1
|
||||
is_signed: 1
|
||||
-
|
||||
asm_text: "add64 r6, 0xffffffff"
|
||||
details:
|
||||
groups: [ BPF_GRP_ALU ]
|
||||
bpf:
|
||||
operands:
|
||||
-
|
||||
type: BPF_OP_REG
|
||||
reg: r6
|
||||
-
|
||||
type: BPF_OP_IMM
|
||||
imm: 0xffffffff
|
||||
is_signed: -1
|
||||
-
|
||||
asm_text: "call -0x1"
|
||||
details:
|
||||
groups: [ BPF_GRP_CALL ]
|
||||
bpf:
|
||||
operands:
|
||||
-
|
||||
type: BPF_OP_IMM
|
||||
imm: 0xffffffff
|
||||
is_signed: 1
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -1039,15 +1039,15 @@ test_cases:
|
|||
details:
|
||||
groups: [ alu ]
|
||||
-
|
||||
asm_text: "ldb [0x0]"
|
||||
mnemonic: ldb
|
||||
op_str: "[0x0]"
|
||||
asm_text: "ldabsb [skb+0x0]"
|
||||
mnemonic: ldabsb
|
||||
op_str: "[skb+0x0]"
|
||||
details:
|
||||
regs_write: [ r0 ]
|
||||
groups: [ load ]
|
||||
-
|
||||
asm_text: "xadddw [r10+0x100], r3"
|
||||
mnemonic: xadddw
|
||||
asm_text: "aadd64 [r10+0x100], r3"
|
||||
mnemonic: aadd64
|
||||
op_str: "[r10+0x100], r3"
|
||||
details:
|
||||
groups: [ store ]
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue