opcode-macros
This crate provides a opcode_match
macro, which generates a complex match statement
for opcodes encoded in bit fields.
Format
The basic format is like this:
use opcode_match;
let opcode = 0u8;
let result =
opcode_match!
;
assert_eq!;
It generates something like this:
let opcode = 0u8;
const A_1_B_1: u8 = A_1 | B_1;
const A_1_B_2: u8 = A_1 | B_2;
const A_2_B_1: u8 = A_2 | B_1;
const A_2_B_2: u8 = A_2 | B_2;
match opcode
Match Arm Headers
Match arm headers is something like [[A_1: a1, A_2: a2], [B_1: b1, B_2: b2]]
.
For example, in eBPF opcodes, BPF_ALU | BPF_K | BPF_ADD
is an opcode for
32-bit addition with constants, while BPF_ALU | BPF_K | BPF_SUB
is an opcode
for 32-bit subtraction with constants. To match against these opcodes,
we use the following code:
use opcode_match;
use *;
let opcode = 0x04u8;
let mut result = 0u64;
let dst = 10u64;
let imm = 10u64;
opcode_match!
assert_eq!;
We will talk about the templating rules later.
In the example above, you can also use some other variants:
[BPF_ADD: "add", BPF_SUB: "sub"]
[BPF_ADD: [add], BPF_SUB: [sub]]
[BPF_ADD: ["add"], BPF_SUB: ["sub"]]
[BPF_ADD: ["add", "extra1"], BPF_SUB: ["sub", "extra2"]]
If you want to substitutes parts of the code with symbols like "+",
you will need to quote the symbols like [BPF_ADD: "+"]
.
Code Template
Substitution
This is not a real life example.
use opcode_match;
use *;
use Add;
let opcode = 0u8;
opcode_match!
Conditional Blocks
use opcode_match;
use *;
let opcode = BPF_X | BPF_ALU;
opcode_match! ;
The grammar is #?((cond1, cond2)|(cond3|cond4)|...) CODE ##
,
making the code only injected if the opcode matches
(cond1 && cond2) || (cond3 && cond4) || ...
.
A condition can be negated with an exclamation mark !cond1
.
We don't allow nested conditions.