1mod formats;
52mod optimizer;
53
54pub mod compiler;
55pub mod error;
56pub mod types;
57
58#[cfg(test)]
59mod tests {
60 use crate::compiler::Compiler;
61 use crate::error::Result;
62 use crate::types::{AddToTypeDatabase, Field, TypeDatabase};
63 use bpf_ins::{Instruction, Register};
64
65 #[repr(C, align(1))]
66 struct LargeType {
67 pub a: u64,
68 pub b: u32,
69 pub c: u16,
70 pub d: u8,
71 }
72
73 impl AddToTypeDatabase for LargeType {
74 fn add_to_database(database: &mut TypeDatabase) -> Result<usize> {
75 let a_id = u64::add_to_database(database)?;
76 let b_id = u32::add_to_database(database)?;
77 let c_id = u16::add_to_database(database)?;
78 let d_id = u8::add_to_database(database)?;
79 database.add_struct_by_ids(
80 Some("LargeType"),
81 &[("a", a_id), ("b", b_id), ("c", c_id), ("d", d_id)],
82 )
83 }
84 }
85
86 fn compile_and_compare(prog: &str, expected: &[Instruction]) {
87 let mut database = TypeDatabase::default();
88
89 LargeType::add_to_database(&mut database).expect("Failed to add type.");
90
91 database
92 .add_integer(Some("int"), 4, true)
93 .expect("Failed to add type.");
94
95 let u64id = database
96 .add_integer(Some("__u64"), 8, false)
97 .expect("Failed to add type.");
98
99 let iov_base = Field {
100 offset: 0,
101 type_id: u64id,
102 };
103
104 let iov_len = Field {
105 offset: 64,
106 type_id: u64id,
107 };
108
109 database
110 .add_struct(
111 Some("iovec"),
112 &[("iov_base", iov_base), ("iov_len", iov_len)],
113 )
114 .expect("Failed to add type.");
115
116 let mut compiler = Compiler::create(&database);
117 compiler.compile(prog).unwrap();
118
119 let instructions = compiler.get_instructions();
120 assert_eq!(instructions.len(), expected.len());
121 for (i, ins) in instructions.iter().enumerate() {
122 assert_eq!(ins, &expected[i]);
123 }
124 }
125
126 #[test]
127 fn empty_program() {
128 let prog = r#"
129 fn()
130 "#;
131
132 let expected = [
133 Instruction::mov64(Register::R0, 0), Instruction::exit(), ];
136
137 compile_and_compare(prog, &expected);
138 }
139
140 #[test]
141 fn return_immediate() {
142 let prog = r#"
143 fn()
144 return 300
145 "#;
146
147 let expected = [
148 Instruction::mov64(Register::R0, 300), Instruction::exit(), ];
151
152 compile_and_compare(prog, &expected);
153 }
154
155 #[test]
156 fn return_input_value() {
157 let prog = r#"
158 fn(a: int)
159 return a
160 "#;
161
162 let expected = [
163 Instruction::storex64(Register::R10, -8, Register::R1), Instruction::loadx32(Register::R0, Register::R10, -8), Instruction::exit(), ];
167
168 compile_and_compare(prog, &expected);
169 }
170
171 #[test]
172 fn assign_fields() {
173 let prog = r#"
174 fn()
175 vec: iovec = 0
176 vec.iov_base = 100
177 vec.iov_len = 200
178 "#;
179
180 let expected = [
181 Instruction::store64(Register::R10, -16, 0), Instruction::store64(Register::R10, -8, 0), Instruction::store64(Register::R10, -16, 100), Instruction::store64(Register::R10, -8, 200), Instruction::mov64(Register::R0, 0), Instruction::exit(), ];
188
189 compile_and_compare(prog, &expected);
190 }
191
192 #[test]
193 fn assign_fields_from_fields() {
194 let prog = r#"
195 fn(vec: &iovec)
196 vec_copy: iovec = 0
197 vec_copy.iov_base = vec.iov_base
198 vec_copy.iov_len = vec.iov_len
199 return 50
200 "#;
201
202 let expected = [
203 Instruction::storex64(Register::R10, -8, Register::R1), Instruction::store64(Register::R10, -24, 0), Instruction::store64(Register::R10, -16, 0), Instruction::loadx64(Register::R6, Register::R10, -8), Instruction::movx64(Register::R1, Register::R10), Instruction::add64(Register::R1, -24), Instruction::mov64(Register::R2, 8), Instruction::movx64(Register::R3, Register::R6), Instruction::call(4), Instruction::loadx64(Register::R6, Register::R10, -8), Instruction::add64(Register::R6, 8), Instruction::movx64(Register::R1, Register::R10), Instruction::add64(Register::R1, -16), Instruction::mov64(Register::R2, 8), Instruction::movx64(Register::R3, Register::R6), Instruction::call(4), Instruction::mov64(Register::R0, 50), Instruction::exit(), ];
222
223 compile_and_compare(prog, &expected);
224 }
225
226 #[test]
227 fn assign_function_call() {
228 let prog = r#"
229 fn()
230 a: __u64 = get_current_uid_gid()
231 "#;
232
233 let expected = [
234 Instruction::call(15), Instruction::storex64(Register::R10, -8, Register::R0), Instruction::mov64(Register::R0, 0), Instruction::exit(), ];
239
240 compile_and_compare(prog, &expected);
241 }
242
243 #[test]
244 fn return_function_call() {
245 let prog = r#"
246 fn()
247 a: __u64 = 100
248 return get_current_uid_gid()
249 "#;
250
251 let expected = [
252 Instruction::store64(Register::R10, -8, 100), Instruction::call(15), Instruction::exit(), ];
256
257 compile_and_compare(prog, &expected);
258 }
259
260 #[test]
261 fn return_nested_function_call() {
262 let prog = r#"
263 fn()
264 return get_current_uid_gid(get_current_uid_gid())
265 "#;
266
267 let expected = [
268 Instruction::call(15), Instruction::movx64(Register::R1, Register::R0), Instruction::call(15), Instruction::exit(), ];
273
274 compile_and_compare(prog, &expected);
275 }
276
277 #[test]
278 fn test_zero_init() {
279 let prog = r#"
280 fn()
281 type: LargeType = 0
282 "#;
283
284 let expected = [
285 Instruction::store64(Register::R10, -15, 0), Instruction::store32(Register::R10, -7, 0), Instruction::store16(Register::R10, -3, 0), Instruction::store8(Register::R10, -1, 0), Instruction::mov64(Register::R0, 0), Instruction::exit(), ];
292
293 compile_and_compare(prog, &expected);
294 }
295}