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