Skip to main content

sbpf_common/execute/
endian.rs

1use {
2    super::{ExecutionResult, Vm, helpers::*},
3    crate::{errors::ExecutionError, instruction::Instruction, opcode::Opcode},
4};
5
6pub fn execute_endian(vm: &mut dyn Vm, inst: &Instruction) -> ExecutionResult<()> {
7    let dst = get_dst(inst)?;
8    let imm = get_imm_i64(inst)?;
9
10    if imm != 16 && imm != 32 && imm != 64 {
11        return Err(ExecutionError::InvalidOperand);
12    }
13
14    vm.set_register(
15        dst,
16        match inst.opcode {
17            Opcode::Le => match imm {
18                16 => (vm.get_register(dst) as u16).to_le() as u64,
19                32 => (vm.get_register(dst) as u32).to_le() as u64,
20                64 => vm.get_register(dst).to_le(),
21                _ => unreachable!(),
22            },
23            Opcode::Be => match imm {
24                16 => (vm.get_register(dst) as u16).to_be() as u64,
25                32 => (vm.get_register(dst) as u32).to_be() as u64,
26                64 => vm.get_register(dst).to_be(),
27                _ => unreachable!(),
28            },
29            _ => return Err(ExecutionError::InvalidInstruction),
30        },
31    );
32
33    vm.advance_pc();
34    Ok(())
35}
36
37#[cfg(test)]
38mod tests {
39    use {
40        super::*,
41        crate::{
42            errors::ExecutionError,
43            execute::{MockVm, make_test_instruction},
44            inst_param::{Number, Register},
45        },
46        either::Either,
47    };
48
49    #[test]
50    fn test_le() {
51        let test_cases = [
52            (16, 0xFFFFFFFF_FFFF1234u64, 0x1234u64),
53            (32, 0xFFFFFFFF_12345678u64, 0x12345678u64),
54            (64, 0xFFFFFFFF_12345678u64, 0xFFFFFFFF_12345678u64),
55        ];
56
57        for (imm, input, expected) in test_cases {
58            let inst = make_test_instruction(
59                Opcode::Le,
60                Some(Register { n: 0 }),
61                None,
62                None,
63                Some(Either::Right(Number::Int(imm))),
64            );
65            let mut vm = MockVm::new();
66            vm.registers[0] = input;
67
68            execute_endian(&mut vm, &inst).unwrap();
69
70            assert_eq!(
71                vm.registers[0], expected,
72                "le{} failed: input=0x{:X}, expected=0x{:X}, got=0x{:X}",
73                imm, input, expected, vm.registers[0]
74            );
75        }
76    }
77
78    #[test]
79    fn test_be() {
80        let test_cases = [
81            (16, 0x1234u64, 0x3412u64),
82            (32, 0x12345678u64, 0x78563412u64),
83            (64, 0x0123456789ABCDEFu64, 0xEFCDAB8967452301u64),
84        ];
85
86        for (imm, input, expected) in test_cases {
87            let inst = make_test_instruction(
88                Opcode::Be,
89                Some(Register { n: 0 }),
90                None,
91                None,
92                Some(Either::Right(Number::Int(imm))),
93            );
94            let mut vm = MockVm::new();
95            vm.registers[0] = input;
96
97            execute_endian(&mut vm, &inst).unwrap();
98
99            assert_eq!(
100                vm.registers[0], expected,
101                "be{} failed: input=0x{:X}, expected=0x{:X}, got=0x{:X}",
102                imm, input, expected, vm.registers[0]
103            );
104        }
105    }
106
107    #[test]
108    fn test_invalid_imm() {
109        let inst = make_test_instruction(
110            Opcode::Le,
111            Some(Register { n: 0 }),
112            None,
113            None,
114            Some(Either::Right(Number::Int(8))),
115        );
116        let mut vm = MockVm::new();
117
118        let result = execute_endian(&mut vm, &inst);
119
120        assert!(matches!(result, Err(ExecutionError::InvalidOperand)));
121    }
122}