Skip to content

Commit

Permalink
Reduces having one syscall context object per syscall to having one p…
Browse files Browse the repository at this point in the history
…er vm instance (#387)

* Reduces having one syscall context object per syscall to having one per vm instance.

* Removes DynTraitVtable and DynTraitFatPointer.
  • Loading branch information
Lichtso authored Oct 3, 2022
1 parent 2502fc2 commit 2e9ec24
Show file tree
Hide file tree
Showing 9 changed files with 316 additions and 523 deletions.
10 changes: 3 additions & 7 deletions benches/elf_loader.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,20 +12,16 @@ extern crate test_utils;

use solana_rbpf::{
elf::Executable,
syscalls::{BpfSyscallContext, BpfSyscallU64},
vm::{Config, SyscallObject, SyscallRegistry, TestInstructionMeter},
syscalls::BpfSyscallU64,
vm::{Config, SyscallRegistry, TestInstructionMeter},
};
use std::{fs::File, io::Read};
use test::Bencher;

fn syscall_registry() -> SyscallRegistry {
let mut syscall_registry = SyscallRegistry::default();
syscall_registry
.register_syscall_by_name(
b"log_64",
BpfSyscallU64::init::<BpfSyscallContext>,
BpfSyscallU64::call,
)
.register_syscall_by_name(b"log_64", BpfSyscallU64::call)
.unwrap();
syscall_registry
}
Expand Down
35 changes: 6 additions & 29 deletions cli/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,39 +4,15 @@ use solana_rbpf::{
debugger, ebpf,
elf::Executable,
interpreter::Interpreter,
memory_region::{MemoryMapping, MemoryRegion},
memory_region::MemoryRegion,
static_analysis::Analysis,
verifier::RequisiteVerifier,
vm::{
Config, DynamicAnalysis, EbpfVm, ProgramResult, SyscallObject, SyscallRegistry,
TestInstructionMeter, VerifiedExecutable,
Config, DynamicAnalysis, EbpfVm, SyscallRegistry, TestInstructionMeter, VerifiedExecutable,
},
};
use std::{fs::File, io::Read, path::Path};

#[derive(Clone)]
struct MockSyscall {
name: String,
}
impl SyscallObject for MockSyscall {
fn call(
&mut self,
arg1: u64,
arg2: u64,
arg3: u64,
arg4: u64,
arg5: u64,
_memory_mapping: &mut MemoryMapping,
result: &mut ProgramResult,
) {
println!(
"Syscall {}: {:#x}, {:#x}, {:#x}, {:#x}, {:#x}",
self.name, arg1, arg2, arg3, arg4, arg5,
);
*result = ProgramResult::Ok(0);
}
}

fn main() {
let matches = App::new("Solana RBPF CLI")
.version(crate_version!())
Expand Down Expand Up @@ -210,7 +186,7 @@ fn main() {
_ => {}
}

vm.bind_syscall_context_objects(0).unwrap();
vm.bind_syscall_context_object(&mut ());
let result = if matches.value_of("use").unwrap() == "debugger" {
let mut interpreter = Interpreter::new(&mut vm, &mut instruction_meter).unwrap();
let port = matches.value_of("port").unwrap().parse::<u16>().unwrap();
Expand All @@ -225,12 +201,13 @@ fn main() {
if matches.is_present("trace") {
println!("Trace:\n");
let stdout = std::io::stdout();
vm.get_tracer()
vm.get_program_environment()
.tracer
.write(&mut stdout.lock(), analysis.as_ref().unwrap())
.unwrap();
}
if matches.is_present("profile") {
let tracer = &vm.get_tracer();
let tracer = &vm.get_program_environment().tracer;
let dynamic_analysis = DynamicAnalysis::new(tracer, analysis.as_ref().unwrap());
let mut file = File::create("profile.dot").unwrap();
analysis
Expand Down
18 changes: 5 additions & 13 deletions src/elf.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1213,8 +1213,8 @@ mod test {
types::{Elf64Ehdr, Elf64Shdr},
},
fuzz::fuzz,
syscalls::{BpfSyscallContext, BpfSyscallString, BpfSyscallU64},
vm::{ProgramResult, SyscallObject, TestInstructionMeter},
syscalls::{BpfSyscallString, BpfSyscallU64},
vm::{ProgramResult, TestInstructionMeter},
};
use rand::{distributions::Uniform, Rng};
use std::{fs::File, io::Read};
Expand All @@ -1223,18 +1223,10 @@ mod test {
fn syscall_registry() -> SyscallRegistry {
let mut syscall_registry = SyscallRegistry::default();
syscall_registry
.register_syscall_by_name(
b"log",
BpfSyscallString::init::<BpfSyscallContext>,
BpfSyscallString::call,
)
.register_syscall_by_name(b"log", BpfSyscallString::call)
.unwrap();
syscall_registry
.register_syscall_by_name(
b"log_64",
BpfSyscallU64::init::<BpfSyscallContext>,
BpfSyscallU64::call,
)
.register_syscall_by_name(b"log_64", BpfSyscallU64::call)
.unwrap();
syscall_registry
}
Expand Down Expand Up @@ -2242,6 +2234,6 @@ mod test {
Executable::jit_compile(&mut executable).unwrap();
}

assert_eq!(18656, executable.mem_size());
assert_eq!(18464, executable.mem_size());
}
}
6 changes: 3 additions & 3 deletions src/interpreter.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ use crate::{
error::EbpfError,
memory_region::AccessType,
verifier::Verifier,
vm::{EbpfVm, InstructionMeter, ProgramResult, SyscallFunction},
vm::{EbpfVm, InstructionMeter, ProgramResult},
};

/// Translates a vm_addr into a host_addr and sets the pc in the error if one occurs
Expand Down Expand Up @@ -457,8 +457,8 @@ impl<'a, 'b, V: Verifier, I: InstructionMeter> Interpreter<'a, 'b, V, I> {
}
self.due_insn_count = 0;
let mut result = ProgramResult::Ok(0);
(unsafe { std::mem::transmute::<u64, SyscallFunction::<*mut u8>>(syscall.function) })(
self.vm.program_environment.syscall_context_objects[syscall.context_object_slot],
syscall(
self.vm.program_environment.syscall_context_object,
self.reg[1],
self.reg[2],
self.reg[3],
Expand Down
13 changes: 6 additions & 7 deletions src/jit.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ use rand::{rngs::SmallRng, Rng, SeedableRng};

use crate::{
elf::Executable,
vm::{Config, ProgramResult, InstructionMeter, Tracer, ProgramEnvironment},
vm::{Config, ProgramResult, InstructionMeter, Tracer, ProgramEnvironment, SyscallFunction},
ebpf::{self, INSN_SIZE, FIRST_SCRATCH_REG, SCRATCH_REGS, FRAME_PTR_REG, MM_STACK_START, STACK_PTR_REG},
error::EbpfError,
memory_region::{AccessType, MemoryMapping},
Expand Down Expand Up @@ -946,7 +946,7 @@ impl JitCompiler {
if config.encrypt_environment_registers {
(
diversification_rng.gen::<i32>() / 16, // -3 bits for 8 Byte alignment, and -1 bit to have encoding space for EnvironmentStackSlot::SlotCount
diversification_rng.gen::<i32>() / 2, // -1 bit to have encoding space for (ProgramEnvironment::SYSCALLS_OFFSET + syscall.context_object_slot) * 8
diversification_rng.gen::<i32>() / 2, // -1 bit to have encoding space for (ProgramEnvironment::SYSCALL_CONTEXT_OBJECT + syscall.context_object_slot) * 8
)
} else { (0, 0) };

Expand Down Expand Up @@ -1226,8 +1226,8 @@ impl JitCompiler {
if self.config.enable_instruction_meter {
emit_validate_and_profile_instruction_count(self, true, Some(0));
}
emit_ins(self, X86Instruction::load_immediate(OperandSize::S64, R11, syscall.function as *const u8 as i64));
emit_ins(self, X86Instruction::load(OperandSize::S64, R10, RAX, X86IndirectAccess::Offset(ProgramEnvironment::SYSCALLS_OFFSET as i32 + syscall.context_object_slot as i32 * 8 + self.program_argument_key)));
emit_ins(self, X86Instruction::load_immediate(OperandSize::S64, R11, syscall as *const SyscallFunction<*mut ()> as i64));
emit_ins(self, X86Instruction::load(OperandSize::S64, R10, RAX, X86IndirectAccess::Offset(ProgramEnvironment::SYSCALL_CONTEXT_OBJECT as i32 + self.program_argument_key)));
emit_ins(self, X86Instruction::call_immediate(self.relative_to_anchor(ANCHOR_SYSCALL, 5)));
if self.config.enable_instruction_meter {
emit_undo_profile_instruction_count(self, 0);
Expand Down Expand Up @@ -1503,7 +1503,7 @@ impl JitCompiler {
Argument { index: 3, value: Value::Register(ARGUMENT_REGISTERS[3]) },
Argument { index: 2, value: Value::Register(ARGUMENT_REGISTERS[2]) },
Argument { index: 1, value: Value::Register(ARGUMENT_REGISTERS[1]) },
Argument { index: 0, value: Value::Register(RAX) }, // "&mut self" in the "call" method of the SyscallObject
Argument { index: 0, value: Value::Register(RAX) }, // "&mut self" in the "call" method of the syscall
], None);
if self.config.enable_instruction_meter {
emit_rust_call(self, Value::Constant64(I::get_remaining as *const u8 as i64, false), &[
Expand Down Expand Up @@ -1699,7 +1699,7 @@ impl JitCompiler {
#[cfg(all(test, target_arch = "x86_64", not(target_os = "windows")))]
mod tests {
use super::*;
use crate::{syscalls, vm::{SyscallRegistry, SyscallObject, TestInstructionMeter}, elf::register_bpf_function};
use crate::{syscalls, vm::{SyscallRegistry, TestInstructionMeter}, elf::register_bpf_function};
use std::collections::BTreeMap;
use byteorder::{LittleEndian, ByteOrder};

Expand All @@ -1712,7 +1712,6 @@ mod tests {
syscall_registry
.register_syscall_by_hash(
0xFFFFFFFF,
syscalls::BpfGatherBytes::init::<syscalls::BpfSyscallContext>,
syscalls::BpfGatherBytes::call,
)
.unwrap();
Expand Down
81 changes: 22 additions & 59 deletions src/syscalls.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
#![allow(clippy::integer_arithmetic)]
#![allow(clippy::too_many_arguments)]
// Copyright 2015 Big Switch Networks, Inc
// (Algorithms for uBPF syscalls, originally in C)
// Copyright 2016 6WIND S.A. <[email protected]>
Expand All @@ -22,11 +23,11 @@
use crate::{
memory_region::{AccessType, MemoryMapping},
vm::{ProgramResult, SyscallObject},
vm::ProgramResult,
};
use std::{slice::from_raw_parts, str::from_utf8};

/// Error handling for SyscallObject::call methods
/// Error handling for syscall methods
macro_rules! question_mark {
( $value:expr, $result:ident ) => {{
let value = $value;
Expand All @@ -40,9 +41,6 @@ macro_rules! question_mark {
}};
}

/// Test syscall context
pub type BpfSyscallContext = u64;

// bpf_trace_printk()

/// Index of syscall `bpf_trace_printk()`, equivalent to `bpf_trace_printf`, in Linux kernel, see
Expand All @@ -60,7 +58,7 @@ pub const BPF_TRACE_PRINTK_IDX: u32 = 6;
/// ```
/// use solana_rbpf::syscalls::BpfTracePrintf;
/// use solana_rbpf::memory_region::{MemoryRegion, MemoryMapping};
/// use solana_rbpf::vm::{Config, SyscallObject, ProgramResult};
/// use solana_rbpf::vm::{Config, ProgramResult};
///
/// let mut result = ProgramResult::Ok(0);
/// let config = Config::default();
Expand Down Expand Up @@ -91,13 +89,8 @@ pub const BPF_TRACE_PRINTK_IDX: u32 = 6;
/// program is run.
pub struct BpfTracePrintf {}
impl BpfTracePrintf {
/// new
pub fn init<C>(_unused: C) -> Box<dyn SyscallObject> {
Box::new(Self {})
}
}
impl SyscallObject for BpfTracePrintf {
fn call(
/// Syscall handler method
pub fn call(
&mut self,
_arg1: u64,
_arg2: u64,
Expand Down Expand Up @@ -134,7 +127,7 @@ impl SyscallObject for BpfTracePrintf {
/// ```
/// use solana_rbpf::syscalls::BpfGatherBytes;
/// use solana_rbpf::memory_region::{MemoryRegion, MemoryMapping};
/// use solana_rbpf::vm::{Config, SyscallObject, ProgramResult};
/// use solana_rbpf::vm::{Config, ProgramResult};
///
/// let mut result = ProgramResult::Ok(0);
/// let config = Config::default();
Expand All @@ -144,13 +137,8 @@ impl SyscallObject for BpfTracePrintf {
/// ```
pub struct BpfGatherBytes {}
impl BpfGatherBytes {
/// new
pub fn init<C>(_unused: C) -> Box<dyn SyscallObject> {
Box::new(Self {})
}
}
impl SyscallObject for BpfGatherBytes {
fn call(
/// Syscall handler method
pub fn call(
&mut self,
arg1: u64,
arg2: u64,
Expand Down Expand Up @@ -179,7 +167,7 @@ impl SyscallObject for BpfGatherBytes {
/// ```
/// use solana_rbpf::syscalls::BpfMemFrob;
/// use solana_rbpf::memory_region::{MemoryRegion, MemoryMapping};
/// use solana_rbpf::vm::{Config, SyscallObject, ProgramResult};
/// use solana_rbpf::vm::{Config, ProgramResult};
///
/// let mut val = &mut [0x00, 0x00, 0x00, 0x00, 0x00, 0x11, 0x22, 0x33];
/// let val_va = 0x100000000;
Expand All @@ -194,13 +182,8 @@ impl SyscallObject for BpfGatherBytes {
/// ```
pub struct BpfMemFrob {}
impl BpfMemFrob {
/// new
pub fn init<C>(_unused: C) -> Box<dyn SyscallObject> {
Box::new(Self {})
}
}
impl SyscallObject for BpfMemFrob {
fn call(
/// Syscall handler method
pub fn call(
&mut self,
vm_addr: u64,
len: u64,
Expand Down Expand Up @@ -228,7 +211,7 @@ impl SyscallObject for BpfMemFrob {
/// ```
/// use solana_rbpf::syscalls::BpfStrCmp;
/// use solana_rbpf::memory_region::{MemoryRegion, MemoryMapping};
/// use solana_rbpf::vm::{Config, SyscallObject, ProgramResult};
/// use solana_rbpf::vm::{Config, ProgramResult};
///
/// let foo = "This is a string.";
/// let bar = "This is another sting.";
Expand All @@ -247,13 +230,8 @@ impl SyscallObject for BpfMemFrob {
/// ```
pub struct BpfStrCmp {}
impl BpfStrCmp {
/// new
pub fn init<C>(_unused: C) -> Box<dyn SyscallObject> {
Box::new(Self {})
}
}
impl SyscallObject for BpfStrCmp {
fn call(
/// Syscall handler method
pub fn call(
&mut self,
arg1: u64,
arg2: u64,
Expand Down Expand Up @@ -293,13 +271,8 @@ impl SyscallObject for BpfStrCmp {
/// Prints a NULL-terminated UTF-8 string.
pub struct BpfSyscallString {}
impl BpfSyscallString {
/// new
pub fn init<C>(_unused: C) -> Box<dyn SyscallObject> {
Box::new(Self {})
}
}
impl SyscallObject for BpfSyscallString {
fn call(
/// Syscall handler method
pub fn call(
&mut self,
vm_addr: u64,
len: u64,
Expand Down Expand Up @@ -329,13 +302,8 @@ impl SyscallObject for BpfSyscallString {
/// Prints the five arguments formated as u64 in decimal.
pub struct BpfSyscallU64 {}
impl BpfSyscallU64 {
/// new
pub fn init<C>(_unused: C) -> Box<dyn SyscallObject> {
Box::new(Self {})
}
}
impl SyscallObject for BpfSyscallU64 {
fn call(
/// Syscall handler method
pub fn call(
&mut self,
arg1: u64,
arg2: u64,
Expand All @@ -356,16 +324,11 @@ impl SyscallObject for BpfSyscallU64 {
/// Example of a syscall with internal state.
pub struct SyscallWithContext {
/// Mutable state
pub context: BpfSyscallContext,
pub context: u64,
}
impl SyscallWithContext {
/// new
pub fn init<C>(context: BpfSyscallContext) -> Box<dyn SyscallObject> {
Box::new(Self { context })
}
}
impl SyscallObject for SyscallWithContext {
fn call(
/// Syscall handler method
pub fn call(
&mut self,
arg1: u64,
arg2: u64,
Expand Down
Loading

0 comments on commit 2e9ec24

Please sign in to comment.