1 // SPDX-License-Identifier: (Apache-2.0 OR MIT)
2 // Copyright 2017 Jan-Erik Rediger <badboy@archlinux.us>
3 //
4 // Adopted from tests in `tests/assembler.rs`
5
6 extern crate rbpf;
7 mod common;
8
9 use rbpf::{assembler::assemble, disassembler::to_insn_vec};
10
11 // Using a macro to keep actual line numbers in failure output
12 macro_rules! disasm {
13 ($src:expr) => {{
14 let src = $src;
15 let asm = assemble(src).expect("Can't assemble from string");
16 let insn = to_insn_vec(&asm);
17 let reasm = insn
18 .into_iter()
19 .map(|ins| ins.desc)
20 .collect::<Vec<_>>()
21 .join("\n");
22
23 assert_eq!(src, reasm);
24 }};
25 }
26
27 #[test]
test_empty()28 fn test_empty() {
29 disasm!("");
30 }
31
32 // Example for InstructionType::NoOperand.
33 #[test]
test_exit()34 fn test_exit() {
35 disasm!("exit");
36 }
37
38 // Example for InstructionType::AluBinary.
39 #[test]
test_add64()40 fn test_add64() {
41 disasm!("add64 r1, r3");
42 disasm!("add64 r1, 0x5");
43 }
44
45 // Example for InstructionType::AluUnary.
46 #[test]
test_neg64()47 fn test_neg64() {
48 disasm!("neg64 r1");
49 }
50
51 // Example for InstructionType::LoadReg.
52 #[test]
test_ldxw()53 fn test_ldxw() {
54 disasm!("ldxw r1, [r2+0x5]");
55 }
56
57 // Example for InstructionType::StoreImm.
58 #[test]
test_stw()59 fn test_stw() {
60 disasm!("stw [r2+0x5], 0x7");
61 }
62
63 // Example for InstructionType::StoreReg.
64 #[test]
test_stxw()65 fn test_stxw() {
66 disasm!("stxw [r2+0x5], r8");
67 }
68
69 // Example for InstructionType::JumpUnconditional.
70 #[test]
test_ja()71 fn test_ja() {
72 disasm!("ja +0x8");
73 }
74
75 // Example for InstructionType::JumpConditional.
76 #[test]
test_jeq()77 fn test_jeq() {
78 disasm!("jeq r1, 0x4, +0x8");
79 disasm!("jeq r1, r3, +0x8");
80 }
81
82 // Example for InstructionType::Call.
83 #[test]
test_call()84 fn test_call() {
85 disasm!("call 0x3");
86 }
87
88 // Example for InstructionType::Endian.
89 #[test]
test_be32()90 fn test_be32() {
91 disasm!("be32 r1");
92 }
93
94 // Example for InstructionType::LoadImm.
95 #[test]
test_lddw()96 fn test_lddw() {
97 disasm!("lddw r1, 0x1234abcd5678eeff");
98 disasm!("lddw r1, 0xff11ee22dd33cc44");
99 }
100
101 // Example for InstructionType::LoadAbs.
102 #[test]
test_ldabsw()103 fn test_ldabsw() {
104 disasm!("ldabsw 0x1");
105 }
106
107 // Example for InstructionType::LoadInd.
108 #[test]
test_ldindw()109 fn test_ldindw() {
110 disasm!("ldindw r1, 0x2");
111 }
112
113 // Example for InstructionType::LoadReg.
114 #[test]
test_ldxdw()115 fn test_ldxdw() {
116 disasm!("ldxdw r1, [r2+0x3]");
117 }
118
119 // Example for InstructionType::StoreImm.
120 #[test]
test_sth()121 fn test_sth() {
122 disasm!("sth [r1+0x2], 0x3");
123 }
124
125 // Example for InstructionType::StoreReg.
126 #[test]
test_stxh()127 fn test_stxh() {
128 disasm!("stxh [r1+0x2], r3");
129 }
130
131 // Test all supported AluBinary mnemonics.
132 #[test]
test_alu_binary()133 fn test_alu_binary() {
134 disasm!(
135 "add64 r1, r2
136 sub64 r1, r2
137 mul64 r1, r2
138 div64 r1, r2
139 or64 r1, r2
140 and64 r1, r2
141 lsh64 r1, r2
142 rsh64 r1, r2
143 mod64 r1, r2
144 xor64 r1, r2
145 mov64 r1, r2
146 arsh64 r1, r2"
147 );
148
149 disasm!(
150 "add64 r1, 0x2
151 sub64 r1, 0x2
152 mul64 r1, 0x2
153 div64 r1, 0x2
154 or64 r1, 0x2
155 and64 r1, 0x2
156 lsh64 r1, 0x2
157 rsh64 r1, 0x2
158 mod64 r1, 0x2
159 xor64 r1, 0x2
160 mov64 r1, 0x2
161 arsh64 r1, 0x2"
162 );
163
164 disasm!(
165 "add32 r1, r2
166 sub32 r1, r2
167 mul32 r1, r2
168 div32 r1, r2
169 or32 r1, r2
170 and32 r1, r2
171 lsh32 r1, r2
172 rsh32 r1, r2
173 mod32 r1, r2
174 xor32 r1, r2
175 mov32 r1, r2
176 arsh32 r1, r2"
177 );
178
179 disasm!(
180 "add32 r1, 0x2
181 sub32 r1, 0x2
182 mul32 r1, 0x2
183 div32 r1, 0x2
184 or32 r1, 0x2
185 and32 r1, 0x2
186 lsh32 r1, 0x2
187 rsh32 r1, 0x2
188 mod32 r1, 0x2
189 xor32 r1, 0x2
190 mov32 r1, 0x2
191 arsh32 r1, 0x2"
192 );
193 }
194
195 // Test all supported AluUnary mnemonics.
196 #[test]
test_alu_unary()197 fn test_alu_unary() {
198 disasm!(
199 "neg64 r1
200 neg32 r1"
201 );
202 }
203
204 // Test all supported LoadAbs mnemonics.
205 #[test]
test_load_abs()206 fn test_load_abs() {
207 disasm!(
208 "ldabsw 0x1
209 ldabsh 0x1
210 ldabsb 0x1
211 ldabsdw 0x1"
212 );
213 }
214
215 // Test all supported LoadInd mnemonics.
216 #[test]
test_load_ind()217 fn test_load_ind() {
218 disasm!(
219 "ldindw r1, 0x2
220 ldindh r1, 0x2
221 ldindb r1, 0x2
222 ldinddw r1, 0x2"
223 );
224 }
225
226 // Test all supported LoadReg mnemonics.
227 #[test]
test_load_reg()228 fn test_load_reg() {
229 disasm!(
230 r"ldxw r1, [r2+0x3]
231 ldxh r1, [r2+0x3]
232 ldxb r1, [r2+0x3]
233 ldxdw r1, [r2+0x3]"
234 );
235 }
236
237 // Test all supported StoreImm mnemonics.
238 #[test]
test_store_imm()239 fn test_store_imm() {
240 disasm!(
241 "stw [r1+0x2], 0x3
242 sth [r1+0x2], 0x3
243 stb [r1+0x2], 0x3
244 stdw [r1+0x2], 0x3"
245 );
246 }
247
248 // Test all supported StoreReg mnemonics.
249 #[test]
test_store_reg()250 fn test_store_reg() {
251 disasm!(
252 "stxw [r1+0x2], r3
253 stxh [r1+0x2], r3
254 stxb [r1+0x2], r3
255 stxdw [r1+0x2], r3"
256 );
257 }
258
259 // Test all supported JumpConditional mnemonics.
260 #[test]
test_jump_conditional()261 fn test_jump_conditional() {
262 disasm!(
263 "jeq r1, r2, +0x3
264 jgt r1, r2, +0x3
265 jge r1, r2, +0x3
266 jlt r1, r2, +0x3
267 jle r1, r2, +0x3
268 jset r1, r2, +0x3
269 jne r1, r2, +0x3
270 jsgt r1, r2, +0x3
271 jsge r1, r2, -0x3
272 jslt r1, r2, +0x3
273 jsle r1, r2, -0x3"
274 );
275
276 disasm!(
277 "jeq r1, 0x2, +0x3
278 jgt r1, 0x2, +0x3
279 jge r1, 0x2, +0x3
280 jlt r1, 0x2, +0x3
281 jle r1, 0x2, +0x3
282 jset r1, 0x2, +0x3
283 jne r1, 0x2, +0x3
284 jsgt r1, 0x2, +0x3
285 jsge r1, 0x2, -0x3
286 jslt r1, 0x2, +0x3
287 jsle r1, 0x2, -0x3"
288 );
289
290 disasm!(
291 "jeq32 r1, r2, +0x3
292 jgt32 r1, r2, +0x3
293 jge32 r1, r2, +0x3
294 jlt32 r1, r2, +0x3
295 jle32 r1, r2, +0x3
296 jset32 r1, r2, +0x3
297 jne32 r1, r2, +0x3
298 jsgt32 r1, r2, +0x3
299 jsge32 r1, r2, -0x3
300 jslt32 r1, r2, +0x3
301 jsle32 r1, r2, -0x3"
302 );
303
304 disasm!(
305 "jeq32 r1, 0x2, +0x3
306 jgt32 r1, 0x2, +0x3
307 jge32 r1, 0x2, +0x3
308 jlt32 r1, 0x2, +0x3
309 jle32 r1, 0x2, +0x3
310 jset32 r1, 0x2, +0x3
311 jne32 r1, 0x2, +0x3
312 jsgt32 r1, 0x2, +0x3
313 jsge32 r1, 0x2, -0x3
314 jslt32 r1, 0x2, +0x3
315 jsle32 r1, 0x2, -0x3"
316 );
317 }
318
319 // Test all supported Endian mnemonics.
320 #[test]
test_endian()321 fn test_endian() {
322 disasm!(
323 "be16 r1
324 be32 r1
325 be64 r1
326 le16 r1
327 le32 r1
328 le64 r1"
329 );
330 }
331
332 #[test]
test_large_immediate()333 fn test_large_immediate() {
334 disasm!("add64 r1, 0x7fffffff");
335 disasm!("add64 r1, 0x7fffffff");
336 }
337
338 // Non-regression tests for overflow when trying to negate offset 0x8000i16.
339 #[test]
test_offset_overflow()340 fn test_offset_overflow() {
341 let insns = [
342 0x62, 0x01, 0x00, 0x80, 0x01, 0x00, 0x00, 0x00, // stw
343 0x6a, 0x01, 0x00, 0x80, 0x01, 0x00, 0x00, 0x00, // sth
344 0x72, 0x01, 0x00, 0x80, 0x01, 0x00, 0x00, 0x00, // stb
345 0x7a, 0x01, 0x00, 0x80, 0x01, 0x00, 0x00, 0x00, // stdw
346 0x61, 0x01, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, // ldxw
347 0x69, 0x01, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, // ldxh
348 0x71, 0x01, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, // ldxb
349 0x79, 0x01, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, // ldxdw
350 0x15, 0x01, 0x00, 0x80, 0x02, 0x00, 0x00, 0x00, // jeq (imm)
351 0x1d, 0x21, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, // jeq (reg)
352 0x16, 0x01, 0x00, 0x80, 0x02, 0x00, 0x00, 0x00, // jeq32 (imm)
353 0x1e, 0x21, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, // jeq32 (reg)
354 ];
355
356 let expected_output = "stw [r1-0x8000], 0x1
357 sth [r1-0x8000], 0x1
358 stb [r1-0x8000], 0x1
359 stdw [r1-0x8000], 0x1
360 ldxw r1, [r0-0x8000]
361 ldxh r1, [r0-0x8000]
362 ldxb r1, [r0-0x8000]
363 ldxdw r1, [r0-0x8000]
364 jeq r1, 0x2, -0x8000
365 jeq r1, r2, -0x8000
366 jeq32 r1, 0x2, -0x8000
367 jeq32 r1, r2, -0x8000";
368
369 let prog = to_insn_vec(&insns);
370 let asm = prog
371 .into_iter()
372 .map(|ins| ins.desc)
373 .collect::<Vec<_>>()
374 .join("\n");
375
376 assert_eq!(asm, expected_output);
377 }
378