opcode-macros 0.1.0

Macros for opcodes encoded in bit fields
Documentation
use ebpf_consts::*;
use opcode_macros::opcode_match;

#[test]
pub fn match_test() {
    println!("{}", match_number(BPF_ALU | BPF_X | BPF_ADD));
    assert!(match_number(BPF_ALU | BPF_X | BPF_ADD) == 0xFFFFFFFF);
    assert!(match_number(BPF_ALU | BPF_X | BPF_RSH) == 0);
    assert!(match_number(BPF_ALU | BPF_X | BPF_LSH) == 0);
}

pub fn match_number(opcode: u8) -> u64 {
    println!("{opcode:#x}");
    opcode_match! {
        opcode,
        [[BPF_ALU: ALU, BPF_ALU64: ALU64], [BPF_X: X, BPF_K: K],
        [
            BPF_ADD: "+",
            BPF_AND: "&",
            BPF_OR : "|",
            BPF_XOR: "^",
            BPF_LSH: "<<",
            BPF_RSH: ">>",
         ]] => {
            let dst = 0xFFF00FFF0000u64;
            #?((X))   let src = 0x000FF000FFFFu64; ##
            #?((K))   let src = 0u64;              ##
            #?((ALU)) let src = src as u32;        ##
            #?((ALU))
                let dst = dst as u32;
            ##
            #?(("<<")|(">>"))
                let limit = #?((ALU)) 31 ## #?((ALU64)) 63 ##;
                let src = src & limit;
            ##
            let res = dst #=2 src;
            let s = #2;
            println!("Expr: {dst:#x} {s} {src:#x}");
            res #?((ALU)) as u64 ##
        }
        _ => {
            let v = vec![0, 1, 2];
            v[0]
        }
    }
}

#[test]
fn test_replacing_in_parenthesis() {
    let opcode = 0u8;
    let values = vec![1, 2, 3, 4];
    let value = opcode_match! {
        opcode as u8 in ebpf_consts,
        [[BPF_ADD: "+"]] => {
            // (1 + 2) * 3 -> 9
            let value = (1 #=0 2) * 3;
            // 9 + (10 + 10)
            value + if values[1 #=0 2] == 4 {
                10 #=0 10
            } else {
                0
            }
        }
        _ => {
            0
        }
    };
    assert_eq!(value, 29);
}

#[test]
fn test_multiple_aliases() {
    let opcode = 0u8;
    assert_eq!(
        opcode_match! {
            opcode as u8 in ebpf_consts,
            [[BPF_ADD: [1, 2, 3, 4, 5]]] => {
                #:0:=0 * (#:1:=0 + #:2:=0 + #:3:=0) * #:4:=0
            }
            _ => 0,
        },
        45
    );
}

#[test]
fn test_with_same_aliases() {
    mod consts {
        pub const A: u8 = 0;
        pub const B: u8 = 1;
    }
    for i in 0u8..2 {
        opcode_match! {
            i as u8 in consts,
            [[A: ["do_a", "do_final"], B: ["do_b", "do_final"]]] => {
                #?((!do_final)) panic!(); ##
                #?((do_final))
                    assert_eq!(#:1:0, "do_final");
                    assert!(#0.starts_with("do_"));
                ##
            }
            _ => panic!(),
        }
    }
}