#![allow(clippy::arithmetic_side_effects)]
#![allow(clippy::too_many_arguments)]
use crate::{
declare_builtin_function,
error::EbpfError,
memory_region::{AccessType, MemoryMapping},
vm::TestContextObject,
};
use std::{slice::from_raw_parts, str::from_utf8};
declare_builtin_function!(
SyscallTracePrintf,
fn rust(
_context_object: &mut TestContextObject,
_arg1: u64,
_arg2: u64,
arg3: u64,
arg4: u64,
arg5: u64,
_memory_mapping: &mut MemoryMapping,
) -> Result<u64, Box<dyn std::error::Error>> {
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
}
};
Ok("bpf_trace_printf: 0x, 0x, 0x\n".len() as u64
+ size_arg(arg3)
+ size_arg(arg4)
+ size_arg(arg5))
}
);
declare_builtin_function!(
SyscallGatherBytes,
fn rust(
_context_object: &mut TestContextObject,
arg1: u64,
arg2: u64,
arg3: u64,
arg4: u64,
arg5: u64,
_memory_mapping: &mut MemoryMapping,
) -> Result<u64, Box<dyn std::error::Error>> {
Ok(arg1.wrapping_shl(32)
| arg2.wrapping_shl(24)
| arg3.wrapping_shl(16)
| arg4.wrapping_shl(8)
| arg5)
}
);
declare_builtin_function!(
SyscallMemFrob,
fn rust(
_context_object: &mut TestContextObject,
vm_addr: u64,
len: u64,
_arg3: u64,
_arg4: u64,
_arg5: u64,
memory_mapping: &mut MemoryMapping,
) -> Result<u64, Box<dyn std::error::Error>> {
let host_addr: Result<u64, EbpfError> =
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)
}
);
declare_builtin_function!(
SyscallStrCmp,
fn rust(
_context_object: &mut TestContextObject,
arg1: u64,
arg2: u64,
_arg3: u64,
_arg4: u64,
_arg5: u64,
memory_mapping: &mut MemoryMapping,
) -> Result<u64, Box<dyn std::error::Error>> {
if arg1 == 0 || arg2 == 0 {
return Ok(u64::MAX);
}
let a: Result<u64, EbpfError> = memory_mapping.map(AccessType::Load, arg1, 1).into();
let mut a = a?;
let b: Result<u64, EbpfError> = 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)
}
}
}
);
declare_builtin_function!(
SyscallString,
fn rust(
_context_object: &mut TestContextObject,
vm_addr: u64,
len: u64,
_arg3: u64,
_arg4: u64,
_arg5: u64,
memory_mapping: &mut MemoryMapping,
) -> Result<u64, Box<dyn std::error::Error>> {
let host_addr: Result<u64, EbpfError> =
memory_mapping.map(AccessType::Load, vm_addr, len).into();
let host_addr = host_addr?;
unsafe {
let c_buf = from_raw_parts(host_addr as *const u8, len as usize);
let len = c_buf.iter().position(|c| *c == 0).unwrap_or(len as usize);
let message = from_utf8(&c_buf[0..len]).unwrap_or("Invalid UTF-8 String");
println!("log: {message}");
}
Ok(0)
}
);
declare_builtin_function!(
SyscallU64,
fn rust(
_context_object: &mut TestContextObject,
arg1: u64,
arg2: u64,
arg3: u64,
arg4: u64,
arg5: u64,
memory_mapping: &mut MemoryMapping,
) -> Result<u64, Box<dyn std::error::Error>> {
println!(
"dump_64: {:#x}, {:#x}, {:#x}, {:#x}, {:#x}, {:?}",
arg1, arg2, arg3, arg4, arg5, memory_mapping as *const _
);
Ok(0)
}
);