1*fae6e9adSlinfeng // Copyright Microsoft Corporation
2*fae6e9adSlinfeng // SPDX-License-Identifier: (Apache-2.0 OR MIT)
3*fae6e9adSlinfeng
4*fae6e9adSlinfeng // Path: examples/rbpf_plugin.rs
5*fae6e9adSlinfeng use std::io::Read;
6*fae6e9adSlinfeng
7*fae6e9adSlinfeng // Helper function used by https://github.com/Alan-Jowett/bpf_conformance/blob/main/tests/call_unwind_fail.data
_unwind(a: u64, _b: u64, _c: u64, _d: u64, _e: u64) -> u648*fae6e9adSlinfeng fn _unwind(a: u64, _b: u64, _c: u64, _d: u64, _e: u64) -> u64 {
9*fae6e9adSlinfeng a
10*fae6e9adSlinfeng }
11*fae6e9adSlinfeng
12*fae6e9adSlinfeng // This is a plugin for the bpf_conformance test suite (https://github.com/Alan-Jowett/bpf_conformance)
13*fae6e9adSlinfeng // It accepts a single argument, the memory contents to pass to the VM.
14*fae6e9adSlinfeng // It reads the program from stdin.
main()15*fae6e9adSlinfeng fn main() {
16*fae6e9adSlinfeng let mut args: Vec<String> = std::env::args().collect();
17*fae6e9adSlinfeng #[allow(unused_mut)] // In no_std the jit variable isn't mutated.
18*fae6e9adSlinfeng let mut jit: bool = false;
19*fae6e9adSlinfeng let mut cranelift: bool = false;
20*fae6e9adSlinfeng let mut program_text = String::new();
21*fae6e9adSlinfeng let mut memory_text = String::new();
22*fae6e9adSlinfeng
23*fae6e9adSlinfeng args.remove(0);
24*fae6e9adSlinfeng
25*fae6e9adSlinfeng // Memory is always the first argument.
26*fae6e9adSlinfeng if !args.is_empty() {
27*fae6e9adSlinfeng memory_text.clone_from(&args[0]);
28*fae6e9adSlinfeng // Strip whitespace
29*fae6e9adSlinfeng memory_text.retain(|c| !c.is_whitespace());
30*fae6e9adSlinfeng args.remove(0);
31*fae6e9adSlinfeng }
32*fae6e9adSlinfeng
33*fae6e9adSlinfeng // Process the rest of the arguments.
34*fae6e9adSlinfeng while !args.is_empty() {
35*fae6e9adSlinfeng match args[0].as_str() {
36*fae6e9adSlinfeng "--help" => {
37*fae6e9adSlinfeng println!("Usage: rbpf_plugin [memory] < program");
38*fae6e9adSlinfeng return;
39*fae6e9adSlinfeng }
40*fae6e9adSlinfeng "--jit" => {
41*fae6e9adSlinfeng #[cfg(any(windows, not(feature = "std")))]
42*fae6e9adSlinfeng {
43*fae6e9adSlinfeng println!("JIT not supported");
44*fae6e9adSlinfeng return;
45*fae6e9adSlinfeng }
46*fae6e9adSlinfeng #[cfg(all(not(windows), feature = "std"))]
47*fae6e9adSlinfeng {
48*fae6e9adSlinfeng jit = true;
49*fae6e9adSlinfeng }
50*fae6e9adSlinfeng }
51*fae6e9adSlinfeng "--cranelift" => {
52*fae6e9adSlinfeng cranelift = true;
53*fae6e9adSlinfeng
54*fae6e9adSlinfeng #[cfg(not(feature = "cranelift"))]
55*fae6e9adSlinfeng {
56*fae6e9adSlinfeng let _ = cranelift;
57*fae6e9adSlinfeng println!("Cranelift is not enabled");
58*fae6e9adSlinfeng return;
59*fae6e9adSlinfeng }
60*fae6e9adSlinfeng }
61*fae6e9adSlinfeng "--program" => {
62*fae6e9adSlinfeng if args.len() < 2 {
63*fae6e9adSlinfeng println!("Missing argument to --program");
64*fae6e9adSlinfeng return;
65*fae6e9adSlinfeng }
66*fae6e9adSlinfeng args.remove(0);
67*fae6e9adSlinfeng if !args.is_empty() {
68*fae6e9adSlinfeng program_text.clone_from(&args[0]);
69*fae6e9adSlinfeng args.remove(0);
70*fae6e9adSlinfeng }
71*fae6e9adSlinfeng }
72*fae6e9adSlinfeng _ => panic!("Unknown argument {}", args[0]),
73*fae6e9adSlinfeng }
74*fae6e9adSlinfeng args.remove(0);
75*fae6e9adSlinfeng }
76*fae6e9adSlinfeng
77*fae6e9adSlinfeng if program_text.is_empty() {
78*fae6e9adSlinfeng // Read program text from stdin
79*fae6e9adSlinfeng std::io::stdin().read_to_string(&mut program_text).unwrap();
80*fae6e9adSlinfeng }
81*fae6e9adSlinfeng
82*fae6e9adSlinfeng // Strip whitespace
83*fae6e9adSlinfeng program_text.retain(|c| !c.is_whitespace());
84*fae6e9adSlinfeng
85*fae6e9adSlinfeng // Convert program from hex to bytecode
86*fae6e9adSlinfeng let bytecode = hex::decode(program_text).unwrap();
87*fae6e9adSlinfeng
88*fae6e9adSlinfeng // Convert memory from hex to bytes
89*fae6e9adSlinfeng let mut memory: Vec<u8> = hex::decode(memory_text).unwrap();
90*fae6e9adSlinfeng
91*fae6e9adSlinfeng // Create rbpf vm
92*fae6e9adSlinfeng let mut vm = rbpf::EbpfVmRaw::new(Some(&bytecode)).unwrap();
93*fae6e9adSlinfeng
94*fae6e9adSlinfeng // Register the helper function used by call_unwind_fail.data test.
95*fae6e9adSlinfeng vm.register_helper(5, _unwind).unwrap();
96*fae6e9adSlinfeng
97*fae6e9adSlinfeng let result: u64;
98*fae6e9adSlinfeng if jit {
99*fae6e9adSlinfeng #[cfg(any(windows, not(feature = "std")))]
100*fae6e9adSlinfeng {
101*fae6e9adSlinfeng println!("JIT not supported");
102*fae6e9adSlinfeng return;
103*fae6e9adSlinfeng }
104*fae6e9adSlinfeng #[cfg(all(not(windows), feature = "std"))]
105*fae6e9adSlinfeng {
106*fae6e9adSlinfeng unsafe {
107*fae6e9adSlinfeng vm.jit_compile().unwrap();
108*fae6e9adSlinfeng result = vm.execute_program_jit(&mut memory).unwrap();
109*fae6e9adSlinfeng }
110*fae6e9adSlinfeng }
111*fae6e9adSlinfeng } else if cranelift {
112*fae6e9adSlinfeng #[cfg(not(feature = "cranelift"))]
113*fae6e9adSlinfeng {
114*fae6e9adSlinfeng println!("Cranelift is not enabled");
115*fae6e9adSlinfeng return;
116*fae6e9adSlinfeng }
117*fae6e9adSlinfeng #[cfg(feature = "cranelift")]
118*fae6e9adSlinfeng {
119*fae6e9adSlinfeng vm.cranelift_compile().unwrap();
120*fae6e9adSlinfeng result = vm.execute_program_cranelift(&mut memory).unwrap();
121*fae6e9adSlinfeng }
122*fae6e9adSlinfeng } else {
123*fae6e9adSlinfeng result = vm.execute_program(&mut memory).unwrap();
124*fae6e9adSlinfeng }
125*fae6e9adSlinfeng println!("{result:x}");
126*fae6e9adSlinfeng }
127