From 8f8568a95d7ed414cb1b9afb56da65c2c0511f09 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alexander=20Mei=C3=9Fner?= Date: Fri, 29 Sep 2023 14:57:33 +0200 Subject: [PATCH] Adds macro declare_builtin_function. (#530) --- benches/elf_loader.rs | 2 +- src/elf.rs | 4 +- src/jit.rs | 2 +- src/program.rs | 30 ++++ src/syscalls.rs | 393 ++++++++++++++++-------------------------- src/vm.rs | 10 +- tests/execution.rs | 141 +++++++-------- 7 files changed, 250 insertions(+), 332 deletions(-) diff --git a/benches/elf_loader.rs b/benches/elf_loader.rs index a8d2b1b8..ea621400 100644 --- a/benches/elf_loader.rs +++ b/benches/elf_loader.rs @@ -22,7 +22,7 @@ use test::Bencher; fn loader() -> Arc> { let mut function_registry = FunctionRegistry::>::default(); function_registry - .register_function_hashed(*b"log", syscalls::bpf_syscall_string) + .register_function_hashed(*b"log", syscalls::SyscallString::vm) .unwrap(); Arc::new(BuiltinProgram::new_loader( Config::default(), diff --git a/src/elf.rs b/src/elf.rs index caf408e1..d47fcc73 100644 --- a/src/elf.rs +++ b/src/elf.rs @@ -1203,10 +1203,10 @@ mod test { let mut function_registry = FunctionRegistry::>::default(); function_registry - .register_function_hashed(*b"log", syscalls::bpf_syscall_string) + .register_function_hashed(*b"log", syscalls::SyscallString::vm) .unwrap(); function_registry - .register_function_hashed(*b"log_64", syscalls::bpf_syscall_u64) + .register_function_hashed(*b"log_64", syscalls::SyscallU64::vm) .unwrap(); Arc::new(BuiltinProgram::new_loader( Config::default(), diff --git a/src/jit.rs b/src/jit.rs index b10f87eb..7587d1c3 100644 --- a/src/jit.rs +++ b/src/jit.rs @@ -1660,7 +1660,7 @@ mod tests { let mut function_registry = FunctionRegistry::>::default(); function_registry - .register_function_hashed(*b"gather_bytes", syscalls::bpf_gather_bytes) + .register_function_hashed(*b"gather_bytes", syscalls::SyscallGatherBytes::vm) .unwrap(); let loader = BuiltinProgram::new_loader( Config { diff --git a/src/program.rs b/src/program.rs index 866ef887..c2c343e1 100644 --- a/src/program.rs +++ b/src/program.rs @@ -287,3 +287,33 @@ impl std::fmt::Debug for BuiltinProgram { Ok(()) } } + +/// Generates an adapter for a BuiltinFunction between the Rust and the VM interface +#[macro_export] +macro_rules! declare_builtin_function { + ($(#[$attr:meta])* $name:ident, $rust:item) => { + $(#[$attr])* + pub struct $name {} + impl $name { + /// Rust interface + $rust + /// VM interface + #[allow(clippy::too_many_arguments)] + pub fn vm( + context_object: &mut TestContextObject, + arg_a: u64, + arg_b: u64, + arg_c: u64, + arg_d: u64, + arg_e: u64, + memory_mapping: &mut $crate::memory_region::MemoryMapping, + program_result: &mut $crate::vm::ProgramResult, + ) { + let converted_result: $crate::vm::ProgramResult = Self::rust( + context_object, arg_a, arg_b, arg_c, arg_d, arg_e, memory_mapping, + ).into(); + *program_result = converted_result; + } + } + }; +} diff --git a/src/syscalls.rs b/src/syscalls.rs index df8c805a..09b9adf7 100644 --- a/src/syscalls.rs +++ b/src/syscalls.rs @@ -22,269 +22,174 @@ //! respect this convention. use crate::{ + declare_builtin_function, + error::EbpfError, memory_region::{AccessType, MemoryMapping}, - vm::{ProgramResult, TestContextObject}, + vm::TestContextObject, }; use std::{slice::from_raw_parts, str::from_utf8}; -/// Error handling for syscall methods -macro_rules! question_mark { - ( $value:expr, $result:ident ) => {{ - let value = $value; - match value { - ProgramResult::Err(err) => { - *$result = ProgramResult::Err(err.into()); - return; +declare_builtin_function!( + /// Prints its **last three** arguments to standard output. The **first two** arguments are + /// **unused**. Returns the number of bytes written. + SyscallTracePrintf, + fn rust( + _context_object: &mut TestContextObject, + _arg1: u64, + _arg2: u64, + arg3: u64, + arg4: u64, + arg5: u64, + _memory_mapping: &mut MemoryMapping, + ) -> Result { + println!("bpf_trace_printf: {arg3:#x}, {arg4:#x}, {arg5:#x}"); + let size_arg = |x| { + if x == 0 { + 1 + } else { + (x as f64).log(16.0).floor() as u64 + 1 } - ProgramResult::Ok(value) => value, - } - }}; -} - -// bpf_trace_printk() - -/// Index of syscall `bpf_trace_printk()`, equivalent to `bpf_trace_printf`, in Linux kernel, see -/// . -pub const BPF_TRACE_PRINTK_IDX: u32 = 6; - -/// Prints its **last three** arguments to standard output. The **first two** arguments are -/// **unused**. Returns the number of bytes written. -/// -/// By ignoring the first two arguments, it creates a syscall that will have a behavior similar to -/// the one of the equivalent syscall `bpf_trace_printk()` from Linux kernel. -/// -/// # Examples -/// -/// ``` -/// use solana_rbpf::{program::SBPFVersion, memory_region::{MemoryRegion, MemoryMapping}, syscalls::bpf_trace_printf, vm::{Config, ProgramResult, TestContextObject}}; -/// -/// let mut result = ProgramResult::Ok(0); -/// let config = Config::default(); -/// let mut memory_mapping = MemoryMapping::new(vec![], &config, &SBPFVersion::V2).unwrap(); -/// bpf_trace_printf(&mut TestContextObject::default(), 0, 0, 1, 15, 32, &mut memory_mapping, &mut result); -/// assert_eq!(result.unwrap() as usize, "bpf_trace_printf: 0x1, 0xf, 0x20\n".len()); -/// ``` -/// -/// This will print `bpf_trace_printf: 0x1, 0xf, 0x20`. -/// -/// The eBPF code needed to perform the call in this example would be nearly identical to the code -/// obtained by compiling the following code from C to eBPF with clang: -/// -/// ```c -/// #include -/// #include "path/to/linux/samples/bpf/bpf_syscalls.h" -/// -/// int main(struct __sk_buff *skb) -/// { -/// // Only %d %u %x %ld %lu %lx %lld %llu %llx %p %s conversion specifiers allowed. -/// // See . -/// char *fmt = "bpf_trace_printk %llx, %llx, %llx\n"; -/// return bpf_trace_printk(fmt, sizeof(fmt), 1, 15, 32); -/// } -/// ``` -/// -/// This would equally print the three numbers in `/sys/kernel/debug/tracing` file each time the -/// program is run. -pub fn bpf_trace_printf( - _context_object: &mut TestContextObject, - _arg1: u64, - _arg2: u64, - arg3: u64, - arg4: u64, - arg5: u64, - _memory_mapping: &mut MemoryMapping, - result: &mut ProgramResult, -) { - println!("bpf_trace_printf: {arg3:#x}, {arg4:#x}, {arg5:#x}"); - let size_arg = |x| { - if x == 0 { - 1 - } else { - (x as f64).log(16.0).floor() as u64 + 1 - } - }; - *result = ProgramResult::Ok( - "bpf_trace_printf: 0x, 0x, 0x\n".len() as u64 + }; + Ok("bpf_trace_printf: 0x, 0x, 0x\n".len() as u64 + size_arg(arg3) + size_arg(arg4) - + size_arg(arg5), - ); -} - -// syscalls coming from uBPF + + size_arg(arg5)) + } +); -/// The idea is to assemble five bytes into a single `u64`. For compatibility with the syscalls API, -/// each argument must be a `u64`. -/// -/// # Examples -/// -/// ``` -/// use solana_rbpf::{program::SBPFVersion, memory_region::{MemoryRegion, MemoryMapping}, syscalls::bpf_gather_bytes, vm::{Config, ProgramResult, TestContextObject}}; -/// -/// let mut result = ProgramResult::Ok(0); -/// let config = Config::default(); -/// let mut memory_mapping = MemoryMapping::new(vec![], &config, &SBPFVersion::V2).unwrap(); -/// bpf_gather_bytes(&mut TestContextObject::default(), 0x11, 0x22, 0x33, 0x44, 0x55, &mut memory_mapping, &mut result); -/// assert_eq!(result.unwrap(), 0x1122334455); -/// ``` -pub fn bpf_gather_bytes( - _context_object: &mut TestContextObject, - arg1: u64, - arg2: u64, - arg3: u64, - arg4: u64, - arg5: u64, - _memory_mapping: &mut MemoryMapping, - result: &mut ProgramResult, -) { - *result = ProgramResult::Ok( - arg1.wrapping_shl(32) +declare_builtin_function!( + /// The idea is to assemble five bytes into a single `u64`. For compatibility with the syscalls API, + /// each argument must be a `u64`. + SyscallGatherBytes, + fn rust( + _context_object: &mut TestContextObject, + arg1: u64, + arg2: u64, + arg3: u64, + arg4: u64, + arg5: u64, + _memory_mapping: &mut MemoryMapping, + ) -> Result { + Ok(arg1.wrapping_shl(32) | arg2.wrapping_shl(24) | arg3.wrapping_shl(16) | arg4.wrapping_shl(8) - | arg5, - ); -} + | arg5) + } +); -/// Same as `void *memfrob(void *s, size_t n);` in `string.h` in C. See the GNU manual page (in -/// section 3) for `memfrob`. The memory is directly modified, and the syscall returns 0 in all -/// cases. Arguments 3 to 5 are unused. -/// -/// # Examples -/// -/// ``` -/// use solana_rbpf::{program::SBPFVersion, memory_region::{MemoryRegion, MemoryMapping}, syscalls::bpf_mem_frob, vm::{Config, ProgramResult, TestContextObject}}; -/// -/// let mut val = &mut [0x00, 0x00, 0x00, 0x00, 0x00, 0x11, 0x22, 0x33]; -/// let val_va = 0x100000000; -/// -/// let mut result = ProgramResult::Ok(0); -/// let config = Config::default(); -/// let mut memory_mapping = MemoryMapping::new(vec![MemoryRegion::new_writable(val, val_va)], &config, &SBPFVersion::V2).unwrap(); -/// bpf_mem_frob(&mut TestContextObject::default(), val_va, 8, 0, 0, 0, &mut memory_mapping, &mut result); -/// assert_eq!(val, &[0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x3b, 0x08, 0x19]); -/// bpf_mem_frob(&mut TestContextObject::default(), val_va, 8, 0, 0, 0, &mut memory_mapping, &mut result); -/// assert_eq!(val, &[0x00, 0x00, 0x00, 0x00, 0x00, 0x11, 0x22, 0x33]); -/// ``` -pub fn bpf_mem_frob( - _context_object: &mut TestContextObject, - vm_addr: u64, - len: u64, - _arg3: u64, - _arg4: u64, - _arg5: u64, - memory_mapping: &mut MemoryMapping, - result: &mut ProgramResult, -) { - let host_addr = question_mark!(memory_mapping.map(AccessType::Store, vm_addr, len), result); - for i in 0..len { - unsafe { - let p = (host_addr + i) as *mut u8; - *p ^= 0b101010; +declare_builtin_function!( + /// Same as `void *memfrob(void *s, size_t n);` in `string.h` in C. See the GNU manual page (in + /// section 3) for `memfrob`. The memory is directly modified, and the syscall returns 0 in all + /// cases. Arguments 3 to 5 are unused. + SyscallMemFrob, + fn rust( + _context_object: &mut TestContextObject, + vm_addr: u64, + len: u64, + _arg3: u64, + _arg4: u64, + _arg5: u64, + memory_mapping: &mut MemoryMapping, + ) -> Result { + let host_addr: Result = + memory_mapping.map(AccessType::Store, vm_addr, len).into(); + let host_addr = host_addr?; + for i in 0..len { + unsafe { + let p = (host_addr + i) as *mut u8; + *p ^= 0b101010; + } } + Ok(0) } - *result = ProgramResult::Ok(0); -} +); -/// C-like `strcmp`, return 0 if the strings are equal, and a non-null value otherwise. -/// -/// # Examples -/// -/// ``` -/// use solana_rbpf::{program::SBPFVersion, memory_region::{MemoryRegion, MemoryMapping}, syscalls::bpf_str_cmp, vm::{Config, ProgramResult, TestContextObject}}; -/// -/// let foo = "This is a string."; -/// let bar = "This is another sting."; -/// let va_foo = 0x100000000; -/// let va_bar = 0x200000000; -/// -/// let mut result = ProgramResult::Ok(0); -/// let config = Config::default(); -/// let mut memory_mapping = MemoryMapping::new(vec![MemoryRegion::new_readonly(foo.as_bytes(), va_foo)], &config, &SBPFVersion::V2).unwrap(); -/// bpf_str_cmp(&mut TestContextObject::default(), va_foo, va_foo, 0, 0, 0, &mut memory_mapping, &mut result); -/// assert!(result.unwrap() == 0); -/// let mut result = ProgramResult::Ok(0); -/// let mut memory_mapping = MemoryMapping::new(vec![MemoryRegion::new_readonly(foo.as_bytes(), va_foo), MemoryRegion::new_readonly(bar.as_bytes(), va_bar)], &config, &SBPFVersion::V2).unwrap(); -/// bpf_str_cmp(&mut TestContextObject::default(), va_foo, va_bar, 0, 0, 0, &mut memory_mapping, &mut result); -/// assert!(result.unwrap() != 0); -/// ``` -pub fn bpf_str_cmp( - _context_object: &mut TestContextObject, - arg1: u64, - arg2: u64, - _arg3: u64, - _arg4: u64, - _arg5: u64, - memory_mapping: &mut MemoryMapping, - result: &mut ProgramResult, -) { - // C-like strcmp, maybe shorter than converting the bytes to string and comparing? - if arg1 == 0 || arg2 == 0 { - *result = ProgramResult::Ok(u64::MAX); - return; - } - let mut a = question_mark!(memory_mapping.map(AccessType::Load, arg1, 1), result); - let mut b = question_mark!(memory_mapping.map(AccessType::Load, arg2, 1), result); - unsafe { - let mut a_val = *(a as *const u8); - let mut b_val = *(b as *const u8); - while a_val == b_val && a_val != 0 && b_val != 0 { - a += 1; - b += 1; - a_val = *(a as *const u8); - b_val = *(b as *const u8); +declare_builtin_function!( + /// C-like `strcmp`, return 0 if the strings are equal, and a non-null value otherwise. + SyscallStrCmp, + fn rust( + _context_object: &mut TestContextObject, + arg1: u64, + arg2: u64, + _arg3: u64, + _arg4: u64, + _arg5: u64, + memory_mapping: &mut MemoryMapping, + ) -> Result { + // C-like strcmp, maybe shorter than converting the bytes to string and comparing? + if arg1 == 0 || arg2 == 0 { + return Ok(u64::MAX); + } + let a: Result = memory_mapping.map(AccessType::Load, arg1, 1).into(); + let mut a = a?; + let b: Result = memory_mapping.map(AccessType::Load, arg2, 1).into(); + let mut b = b?; + unsafe { + let mut a_val = *(a as *const u8); + let mut b_val = *(b as *const u8); + while a_val == b_val && a_val != 0 && b_val != 0 { + a += 1; + b += 1; + a_val = *(a as *const u8); + b_val = *(b as *const u8); + } + if a_val >= b_val { + Ok((a_val - b_val) as u64) + } else { + Ok((b_val - a_val) as u64) + } } - *result = if a_val >= b_val { - ProgramResult::Ok((a_val - b_val) as u64) - } else { - ProgramResult::Ok((b_val - a_val) as u64) - }; } -} - -// Some additional syscalls +); -/// Prints a NULL-terminated UTF-8 string. -pub fn bpf_syscall_string( - _context_object: &mut TestContextObject, - vm_addr: u64, - len: u64, - _arg3: u64, - _arg4: u64, - _arg5: u64, - memory_mapping: &mut MemoryMapping, - result: &mut ProgramResult, -) { - let host_addr = question_mark!(memory_mapping.map(AccessType::Load, vm_addr, len), result); - let c_buf: *const i8 = host_addr as *const i8; - unsafe { - for i in 0..len { - let c = std::ptr::read(c_buf.offset(i as isize)); - if c == 0 { - break; +declare_builtin_function!( + /// Prints a NULL-terminated UTF-8 string. + SyscallString, + fn rust( + _context_object: &mut TestContextObject, + vm_addr: u64, + len: u64, + _arg3: u64, + _arg4: u64, + _arg5: u64, + memory_mapping: &mut MemoryMapping, + ) -> Result { + let host_addr: Result = + memory_mapping.map(AccessType::Load, vm_addr, len).into(); + let host_addr = host_addr?; + let c_buf: *const i8 = host_addr as *const i8; + unsafe { + for i in 0..len { + let c = std::ptr::read(c_buf.offset(i as isize)); + if c == 0 { + break; + } } + let message = from_utf8(from_raw_parts(host_addr as *const u8, len as usize)) + .unwrap_or("Invalid UTF-8 String"); + println!("log: {message}"); } - let message = from_utf8(from_raw_parts(host_addr as *const u8, len as usize)) - .unwrap_or("Invalid UTF-8 String"); - println!("log: {message}"); + Ok(0) } - *result = ProgramResult::Ok(0); -} +); -/// Prints the five arguments formated as u64 in decimal. -pub fn bpf_syscall_u64( - _context_object: &mut TestContextObject, - arg1: u64, - arg2: u64, - arg3: u64, - arg4: u64, - arg5: u64, - memory_mapping: &mut MemoryMapping, - result: &mut ProgramResult, -) { - println!( - "dump_64: {:#x}, {:#x}, {:#x}, {:#x}, {:#x}, {:?}", - arg1, arg2, arg3, arg4, arg5, memory_mapping as *const _ - ); - *result = ProgramResult::Ok(0); -} +declare_builtin_function!( + /// Prints the five arguments formated as u64 in decimal. + SyscallU64, + fn rust( + _context_object: &mut TestContextObject, + arg1: u64, + arg2: u64, + arg3: u64, + arg4: u64, + arg5: u64, + memory_mapping: &mut MemoryMapping, + ) -> Result { + println!( + "dump_64: {:#x}, {:#x}, {:#x}, {:#x}, {:#x}, {:?}", + arg1, arg2, arg3, arg4, arg5, memory_mapping as *const _ + ); + Ok(0) + } +); diff --git a/src/vm.rs b/src/vm.rs index 2684cc1d..7b677d12 100644 --- a/src/vm.rs +++ b/src/vm.rs @@ -505,23 +505,23 @@ mod tests { let mut function_registry_a = FunctionRegistry::>::default(); function_registry_a - .register_function_hashed(*b"log", syscalls::bpf_syscall_string) + .register_function_hashed(*b"log", syscalls::SyscallString::vm) .unwrap(); function_registry_a - .register_function_hashed(*b"log_64", syscalls::bpf_syscall_u64) + .register_function_hashed(*b"log_64", syscalls::SyscallU64::vm) .unwrap(); let mut function_registry_b = FunctionRegistry::>::default(); function_registry_b - .register_function_hashed(*b"log_64", syscalls::bpf_syscall_u64) + .register_function_hashed(*b"log_64", syscalls::SyscallU64::vm) .unwrap(); function_registry_b - .register_function_hashed(*b"log", syscalls::bpf_syscall_string) + .register_function_hashed(*b"log", syscalls::SyscallString::vm) .unwrap(); let mut function_registry_c = FunctionRegistry::>::default(); function_registry_c - .register_function_hashed(*b"log_64", syscalls::bpf_syscall_u64) + .register_function_hashed(*b"log_64", syscalls::SyscallU64::vm) .unwrap(); let builtin_program_a = BuiltinProgram::new_loader(Config::default(), function_registry_a); let builtin_program_b = BuiltinProgram::new_loader(Config::default(), function_registry_b); diff --git a/tests/execution.rs b/tests/execution.rs index 0cf7f8c4..92cb0762 100644 --- a/tests/execution.rs +++ b/tests/execution.rs @@ -17,7 +17,7 @@ use byteorder::{ByteOrder, LittleEndian}; use rand::{rngs::SmallRng, RngCore, SeedableRng}; use solana_rbpf::{ assembler::assemble, - ebpf, + declare_builtin_function, ebpf, elf::Executable, error::EbpfError, memory_region::{AccessType, MemoryMapping, MemoryRegion}, @@ -1891,8 +1891,8 @@ fn test_stack2() { exit", [], ( - "bpf_mem_frob" => syscalls::bpf_mem_frob, - "bpf_gather_bytes" => syscalls::bpf_gather_bytes, + "bpf_mem_frob" => syscalls::SyscallMemFrob::vm, + "bpf_gather_bytes" => syscalls::SyscallGatherBytes::vm, ), TestContextObject::new(16), ProgramResult::Ok(0x01020304), @@ -1933,7 +1933,7 @@ fn test_string_stack() { exit", [], ( - "bpf_str_cmp" => syscalls::bpf_str_cmp, + "bpf_str_cmp" => syscalls::SyscallStrCmp::vm, ), TestContextObject::new(28), ProgramResult::Ok(0x0), @@ -2247,7 +2247,7 @@ fn test_syscall_parameter_on_stack() { exit", [], ( - "bpf_syscall_string" => syscalls::bpf_syscall_string, + "bpf_syscall_string" => syscalls::SyscallString::vm, ), TestContextObject::new(6), ProgramResult::Ok(0), @@ -2412,7 +2412,7 @@ fn test_err_syscall_string() { exit", [72, 101, 108, 108, 111], ( - "bpf_syscall_string" => syscalls::bpf_syscall_string, + "bpf_syscall_string" => syscalls::SyscallString::vm, ), TestContextObject::new(2), ProgramResult::Err(EbpfError::AccessViolation(AccessType::Load, 0, 0, "unknown")), @@ -2429,7 +2429,7 @@ fn test_syscall_string() { exit", [72, 101, 108, 108, 111], ( - "bpf_syscall_string" => syscalls::bpf_syscall_string, + "bpf_syscall_string" => syscalls::SyscallString::vm, ), TestContextObject::new(4), ProgramResult::Ok(0), @@ -2450,7 +2450,7 @@ fn test_syscall() { exit", [], ( - "bpf_syscall_u64" => syscalls::bpf_syscall_u64, + "bpf_syscall_u64" => syscalls::SyscallU64::vm, ), TestContextObject::new(8), ProgramResult::Ok(0), @@ -2470,7 +2470,7 @@ fn test_call_gather_bytes() { exit", [], ( - "bpf_gather_bytes" => syscalls::bpf_gather_bytes, + "bpf_gather_bytes" => syscalls::SyscallGatherBytes::vm, ), TestContextObject::new(7), ProgramResult::Ok(0x0102030405), @@ -2492,84 +2492,67 @@ fn test_call_memfrob() { 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, // ], ( - "bpf_mem_frob" => syscalls::bpf_mem_frob, + "bpf_mem_frob" => syscalls::SyscallMemFrob::vm, ), TestContextObject::new(7), ProgramResult::Ok(0x102292e2f2c0708), ); } -#[allow(clippy::too_many_arguments)] -fn nested_vm_syscall( - _context_object: &mut TestContextObject, - depth: u64, - throw: u64, - _arg3: u64, - _arg4: u64, - _arg5: u64, - _memory_mapping: &mut MemoryMapping, - result: &mut ProgramResult, -) { - *result = if throw == 0 { - ProgramResult::Ok(42) - } else { - ProgramResult::Err(EbpfError::CallDepthExceeded) - }; - #[allow(unused_mut)] - if depth > 0 { - let mut function_registry = - FunctionRegistry::>::default(); - function_registry - .register_function_hashed(*b"nested_vm_syscall", nested_vm_syscall) +declare_builtin_function!( + /// For test_nested_vm_syscall() + SyscallNestedVm, + fn rust( + _context_object: &mut TestContextObject, + depth: u64, + throw: u64, + _arg3: u64, + _arg4: u64, + _arg5: u64, + _memory_mapping: &mut MemoryMapping, + ) -> Result { + let result = if throw == 0 { + ProgramResult::Ok(42) + } else { + ProgramResult::Err(EbpfError::CallDepthExceeded) + }; + #[allow(unused_mut)] + if depth > 0 { + let mut function_registry = + FunctionRegistry::>::default(); + function_registry + .register_function_hashed(*b"nested_vm_syscall", SyscallNestedVm::vm) + .unwrap(); + let loader = BuiltinProgram::new_loader(Config::default(), function_registry); + let mem = [depth as u8 - 1, throw as u8]; + let mut executable = assemble::( + " + ldxb r2, [r1+1] + ldxb r1, [r1] + syscall nested_vm_syscall + exit", + Arc::new(loader), + ) .unwrap(); - let loader = BuiltinProgram::new_loader(Config::default(), function_registry); - let mem = [depth as u8 - 1, throw as u8]; - let mut executable = assemble::( - " - ldxb r2, [r1+1] - ldxb r1, [r1] - syscall nested_vm_syscall - exit", - Arc::new(loader), - ) - .unwrap(); - test_interpreter_and_jit!( - executable, - mem, - TestContextObject::new(if throw == 0 { 4 } else { 3 }), - *result, - ); + test_interpreter_and_jit!( + executable, + mem, + TestContextObject::new(if throw == 0 { 4 } else { 3 }), + result, + ); + } + result.into() } -} +); #[test] fn test_nested_vm_syscall() { let config = Config::default(); let mut context_object = TestContextObject::default(); let mut memory_mapping = MemoryMapping::new(vec![], &config, &SBPFVersion::V2).unwrap(); - let mut result = ProgramResult::Ok(0); - nested_vm_syscall( - &mut context_object, - 1, - 0, - 0, - 0, - 0, - &mut memory_mapping, - &mut result, - ); + let result = SyscallNestedVm::rust(&mut context_object, 1, 0, 0, 0, 0, &mut memory_mapping); assert!(result.unwrap() == 42); - let mut result = ProgramResult::Ok(0); - nested_vm_syscall( - &mut context_object, - 1, - 1, - 0, - 0, - 0, - &mut memory_mapping, - &mut result, - ); + let result = SyscallNestedVm::rust(&mut context_object, 1, 1, 0, 0, 0, &mut memory_mapping); assert_error!(result, "CallDepthExceeded"); } @@ -2646,7 +2629,7 @@ fn test_instruction_count_syscall() { exit", [72, 101, 108, 108, 111], ( - "bpf_syscall_string" => syscalls::bpf_syscall_string, + "bpf_syscall_string" => syscalls::SyscallString::vm, ), TestContextObject::new(4), ProgramResult::Ok(0), @@ -2663,7 +2646,7 @@ fn test_err_instruction_count_syscall_capped() { exit", [72, 101, 108, 108, 111], ( - "bpf_syscall_string" => syscalls::bpf_syscall_string, + "bpf_syscall_string" => syscalls::SyscallString::vm, ), TestContextObject::new(3), ProgramResult::Err(EbpfError::ExceededMaxInstructions), @@ -2707,7 +2690,7 @@ fn test_err_non_terminate_capped() { exit", [], ( - "bpf_trace_printf" => syscalls::bpf_trace_printf, + "bpf_trace_printf" => syscalls::SyscallTracePrintf::vm, ), TestContextObject::new(7), ProgramResult::Err(EbpfError::ExceededMaxInstructions), @@ -2726,7 +2709,7 @@ fn test_err_non_terminate_capped() { exit", [], ( - "bpf_trace_printf" => syscalls::bpf_trace_printf, + "bpf_trace_printf" => syscalls::SyscallTracePrintf::vm, ), TestContextObject::new(1000), ProgramResult::Err(EbpfError::ExceededMaxInstructions), @@ -2826,7 +2809,7 @@ fn test_symbol_relocation() { exit", [72, 101, 108, 108, 111], ( - "bpf_syscall_string" => syscalls::bpf_syscall_string + "bpf_syscall_string" => syscalls::SyscallString::vm, ), TestContextObject::new(6), ProgramResult::Ok(0), @@ -2858,7 +2841,7 @@ fn test_syscall_reloc_64_32() { "tests/elfs/syscall_reloc_64_32.so", [], ( - "log" => syscalls::bpf_syscall_string, + "log" => syscalls::SyscallString::vm, ), TestContextObject::new(5), ProgramResult::Ok(0), @@ -2871,7 +2854,7 @@ fn test_syscall_static() { "tests/elfs/syscall_static.so", [], ( - "log" => syscalls::bpf_syscall_string, + "log" => syscalls::SyscallString::vm, ), TestContextObject::new(6), ProgramResult::Ok(0),