1use crate::{
2 decode::{
3 decode_binary_immediate, decode_binary_register, decode_call_immediate,
4 decode_call_register, decode_exit, decode_jump, decode_jump_immediate,
5 decode_jump_register, decode_load_immediate, decode_load_memory, decode_store_immediate,
6 decode_store_register, decode_unary,
7 },
8 errors::SBPFError,
9 instruction::Instruction,
10 opcode::{
11 BIN_IMM_OPS, BIN_REG_OPS, CALL_IMM_OPS, CALL_REG_OPS, EXIT_OPS, JUMP_IMM_OPS, JUMP_OPS,
12 JUMP_REG_OPS, LOAD_IMM_OPS, LOAD_MEMORY_OPS, Opcode, OperationType, STORE_IMM_OPS,
13 STORE_REG_OPS, UNARY_OPS,
14 },
15 validate::{
16 validate_binary_immediate, validate_binary_register, validate_call_immediate,
17 validate_call_register, validate_exit, validate_jump, validate_jump_immediate,
18 validate_jump_register, validate_load_immediate, validate_load_memory,
19 validate_store_immediate, validate_store_register, validate_unary,
20 },
21};
22
23type DecodeFn = fn(&[u8]) -> Result<Instruction, SBPFError>;
24type ValidateFn = fn(&Instruction) -> Result<(), SBPFError>;
25
26pub struct InstructionHandler {
27 pub decode: DecodeFn,
28 pub validate: ValidateFn,
29}
30
31use {once_cell::sync::Lazy, std::collections::HashMap};
32
33pub static OPCODE_TO_HANDLER: Lazy<HashMap<Opcode, InstructionHandler>> = Lazy::new(|| {
34 let mut map = HashMap::new();
36
37 fn register_group(
38 map: &mut HashMap<Opcode, InstructionHandler>,
39 ops: &[Opcode],
40 decode: DecodeFn,
41 validate: ValidateFn,
42 ) {
43 for &op in ops {
44 map.insert(op, InstructionHandler { decode, validate });
45 }
46 }
47
48 register_group(
49 &mut map,
50 LOAD_IMM_OPS,
51 decode_load_immediate,
52 validate_load_immediate,
53 );
54 register_group(
55 &mut map,
56 LOAD_MEMORY_OPS,
57 decode_load_memory,
58 validate_load_memory,
59 );
60 register_group(
61 &mut map,
62 STORE_IMM_OPS,
63 decode_store_immediate,
64 validate_store_immediate,
65 );
66 register_group(
67 &mut map,
68 STORE_REG_OPS,
69 decode_store_register,
70 validate_store_register,
71 );
72 register_group(
73 &mut map,
74 BIN_IMM_OPS,
75 decode_binary_immediate,
76 validate_binary_immediate,
77 );
78 register_group(
79 &mut map,
80 BIN_REG_OPS,
81 decode_binary_register,
82 validate_binary_register,
83 );
84 register_group(&mut map, UNARY_OPS, decode_unary, validate_unary);
85 register_group(&mut map, JUMP_OPS, decode_jump, validate_jump);
86 register_group(
87 &mut map,
88 JUMP_IMM_OPS,
89 decode_jump_immediate,
90 validate_jump_immediate,
91 );
92 register_group(
93 &mut map,
94 JUMP_REG_OPS,
95 decode_jump_register,
96 validate_jump_register,
97 );
98 register_group(
99 &mut map,
100 CALL_IMM_OPS,
101 decode_call_immediate,
102 validate_call_immediate,
103 );
104 register_group(
105 &mut map,
106 CALL_REG_OPS,
107 decode_call_register,
108 validate_call_register,
109 );
110 register_group(&mut map, EXIT_OPS, decode_exit, validate_exit);
111
112 map
113});
114
115pub static OPCODE_TO_TYPE: Lazy<HashMap<Opcode, OperationType>> = Lazy::new(|| {
116 let mut map = HashMap::new();
117
118 fn register_group(
119 map: &mut HashMap<Opcode, OperationType>,
120 ops: &[Opcode],
121 op_type: OperationType,
122 ) {
123 for &op in ops {
124 map.insert(op, op_type);
125 }
126 }
127
128 register_group(&mut map, LOAD_IMM_OPS, OperationType::LoadImmediate);
129 register_group(&mut map, LOAD_MEMORY_OPS, OperationType::LoadMemory);
130 register_group(&mut map, STORE_IMM_OPS, OperationType::StoreImmediate);
131 register_group(&mut map, STORE_REG_OPS, OperationType::StoreRegister);
132 register_group(&mut map, BIN_IMM_OPS, OperationType::BinaryImmediate);
133 register_group(&mut map, BIN_REG_OPS, OperationType::BinaryRegister);
134 register_group(&mut map, UNARY_OPS, OperationType::Unary);
135 register_group(&mut map, JUMP_OPS, OperationType::Jump);
136 register_group(&mut map, JUMP_IMM_OPS, OperationType::JumpImmediate);
137 register_group(&mut map, JUMP_REG_OPS, OperationType::JumpRegister);
138 register_group(&mut map, CALL_IMM_OPS, OperationType::CallImmediate);
139 register_group(&mut map, CALL_REG_OPS, OperationType::CallRegister);
140 register_group(&mut map, EXIT_OPS, OperationType::Exit);
141
142 map
143});