use libbpf_sys as sys;
use num_enum::{IntoPrimitive, TryFromPrimitive};
#[repr(u8)]
#[derive(Debug, TryFromPrimitive, IntoPrimitive, Clone, Copy, PartialEq, Eq, Hash)]
pub enum Class {
LD = sys::BPF_LD as u8,
LDX = sys::BPF_LDX as u8,
ST = sys::BPF_ST as u8,
STX = sys::BPF_STX as u8,
ALU = sys::BPF_ALU as u8,
ALU64 = sys::BPF_ALU64 as u8,
JMP = sys::BPF_JMP as u8,
JMP32 = sys::BPF_JMP32 as u8,
}
#[repr(u8)]
#[derive(Debug, TryFromPrimitive, IntoPrimitive, Clone, Copy, PartialEq, Eq, Hash)]
pub enum Register {
R0 = sys::BPF_REG_0 as u8,
R1 = sys::BPF_REG_1 as u8,
R2 = sys::BPF_REG_2 as u8,
R3 = sys::BPF_REG_3 as u8,
R4 = sys::BPF_REG_4 as u8,
R5 = sys::BPF_REG_5 as u8,
R6 = sys::BPF_REG_6 as u8,
R7 = sys::BPF_REG_7 as u8,
R8 = sys::BPF_REG_8 as u8,
R9 = sys::BPF_REG_9 as u8,
R10 = sys::BPF_REG_10 as u8,
}
#[repr(u8)]
#[derive(Debug, TryFromPrimitive, IntoPrimitive, Clone, Copy, PartialEq, Eq, Hash)]
pub enum AluOp {
ADD = sys::BPF_ADD as u8,
SUB = sys::BPF_SUB as u8,
MUL = sys::BPF_MUL as u8,
DIV = sys::BPF_DIV as u8,
OR = sys::BPF_OR as u8,
AND = sys::BPF_AND as u8,
LSH = sys::BPF_LSH as u8,
RSH = sys::BPF_RSH as u8,
NEG = sys::BPF_NEG as u8,
MOD = sys::BPF_MOD as u8,
XOR = sys::BPF_XOR as u8,
MOV = sys::BPF_MOV as u8,
ARSH = sys::BPF_ARSH as u8,
END = sys::BPF_END as u8,
}
#[repr(u8)]
#[derive(Debug, TryFromPrimitive, IntoPrimitive, Clone, Copy, PartialEq, Eq, Hash)]
pub enum JmpOp {
JA = sys::BPF_JA as u8,
JEQ = sys::BPF_JEQ as u8,
JGT = sys::BPF_JGT as u8,
JGE = sys::BPF_JGE as u8,
JSET = sys::BPF_JSET as u8,
JNE = sys::BPF_JNE as u8,
JSGT = sys::BPF_JSGT as u8,
JSGE = sys::BPF_JSGE as u8,
CALL = sys::BPF_CALL as u8,
EXIT = sys::BPF_EXIT as u8,
JLT = sys::BPF_JLT as u8,
JLE = sys::BPF_JLE as u8,
JSLT = sys::BPF_JSLT as u8,
JSLE = sys::BPF_JSLE as u8,
}
#[repr(u8)]
#[derive(Debug, TryFromPrimitive, IntoPrimitive, Clone, Copy, PartialEq, Eq, Hash)]
pub enum SrcOp {
K = sys::BPF_K as u8,
X = sys::BPF_X as u8,
}
fn create_bpf_insn(code: u8, dst: u8, src: u8, off: i16, imm: i32) -> sys::bpf_insn {
sys::bpf_insn {
code,
_bitfield_align_1: [],
_bitfield_1: sys::bpf_insn::new_bitfield_1(dst, src),
off,
imm,
}
}
pub fn alu64_imm(op: AluOp, dst: Register, imm: i32) -> sys::bpf_insn {
create_bpf_insn(
u8::from(op) | u8::from(SrcOp::K) | u8::from(Class::ALU64),
dst.into(),
0,
0,
imm,
)
}
pub fn mov64_imm(dst: Register, imm: i32) -> sys::bpf_insn {
alu64_imm(AluOp::MOV, dst, imm)
}
pub fn alu64_reg(op: AluOp, dst: Register, src: Register) -> sys::bpf_insn {
create_bpf_insn(
u8::from(op) | u8::from(SrcOp::X) | u8::from(Class::ALU64),
dst.into(),
src.into(),
0,
0,
)
}
pub fn mov64_reg(dst: Register, src: Register) -> sys::bpf_insn {
alu64_reg(AluOp::MOV, dst, src)
}
pub fn jmp_imm(jmp: JmpOp, dst: Register, imm: i32, off: i16) -> sys::bpf_insn {
create_bpf_insn(
u8::from(jmp) | u8::from(SrcOp::K) | u8::from(Class::JMP),
dst.into(),
0,
off,
imm,
)
}
pub fn jmp32_imm(jmp: JmpOp, dst: Register, imm: i32, off: i16) -> sys::bpf_insn {
create_bpf_insn(
u8::from(jmp) | u8::from(SrcOp::K) | u8::from(Class::JMP32),
dst.into(),
0,
off,
imm,
)
}
pub fn exit() -> sys::bpf_insn {
create_bpf_insn(u8::from(JmpOp::EXIT) | u8::from(Class::JMP), 0, 0, 0, 0)
}
#[cfg(test)]
mod tests {
use super::*;
use bpfdeploy_libbpf_sys as sys;
#[test]
fn test_abi_compat() {
let dst = Register::R2;
let imm = 123123;
vec![
(
unsafe { sys::_BPF_MOV64_IMM(dst.into(), imm) },
mov64_imm(dst, imm),
),
(
unsafe { sys::_BPF_ALU64_IMM(AluOp::MOV.into(), dst.into(), imm) },
alu64_imm(AluOp::MOV, dst, imm),
),
(
unsafe { sys::_BPF_JMP_IMM(JmpOp::JNE.into(), dst.into(), 32, 10) },
jmp_imm(JmpOp::JNE, dst, 32, 10),
),
(
unsafe { sys::_BPF_JMP32_IMM(JmpOp::JNE.into(), dst.into(), 1000, 500) },
jmp32_imm(JmpOp::JNE, dst, 1000, 500),
),
(unsafe { sys::_BPF_EXIT_INSN() }, exit()),
]
.iter()
.for_each(|(expected_insn, observed_insn)| {
assert_eq!(expected_insn.code, observed_insn.code);
assert_eq!(expected_insn.dst_reg(), observed_insn.dst_reg());
assert_eq!(expected_insn.src_reg(), observed_insn.src_reg());
assert_eq!(expected_insn.off, observed_insn.off);
assert_eq!(expected_insn.imm, observed_insn.imm);
})
}
}