diff --git a/Cargo.lock b/Cargo.lock index 4046a91b59..bd0282bca2 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -84,9 +84,9 @@ checksum = "cff77d8686867eceff3105329d4698d96c2391c176d5d03adc90c7389162b5b8" [[package]] name = "ascii" -version = "0.7.1" +version = "0.9.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3ae7d751998c189c1d4468cf0a39bb2eae052a9c58d50ebb3b9591ee3813ad50" +checksum = "eab1c04a571841102f5345a8fc0f6bb3d31c315dec879b5c6e42e40ce7ffa34e" [[package]] name = "assert_cmd" @@ -572,12 +572,15 @@ dependencies = [ [[package]] name = "combine" -version = "2.5.2" +version = "3.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1645a65a99c7c8d345761f4b75a6ffe5be3b3b27a93ee731fccc5050ba6be97c" +checksum = "da3da6baa321ec19e1cc41d31bf599f00c783d0517095cdaf0332e3fe8d20680" dependencies = [ "ascii", "byteorder", + "either", + "memchr 2.3.3", + "unreachable", ] [[package]] @@ -5151,9 +5154,9 @@ dependencies = [ [[package]] name = "solana_rbpf" -version = "0.2.0" +version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09e18fa1e1b6cac20a5f2571882b7580a65ae685b1413fc498f975d07d4c968f" +checksum = "8fad65297e2bd080468cb57a97e6a62e9a92928a45960496338e997e8270fa00" dependencies = [ "byteorder", "combine", @@ -6289,6 +6292,15 @@ dependencies = [ "libc", ] +[[package]] +name = "unreachable" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "382810877fe448991dfc7f0dd6e3ae5d58088fd0ea5e35189655f84e6814fa56" +dependencies = [ + "void", +] + [[package]] name = "untrusted" version = "0.7.1" diff --git a/cli/Cargo.toml b/cli/Cargo.toml index 1964234c5c..1f1690bf81 100644 --- a/cli/Cargo.toml +++ b/cli/Cargo.toml @@ -37,7 +37,7 @@ solana-config-program = { path = "../programs/config", version = "1.5.0" } solana-faucet = { path = "../faucet", version = "1.5.0" } solana-logger = { path = "../logger", version = "1.5.0" } solana-net-utils = { path = "../net-utils", version = "1.5.0" } -solana_rbpf = "=0.2.0" +solana_rbpf = "=0.2.1" solana-remote-wallet = { path = "../remote-wallet", version = "1.5.0" } solana-sdk = { path = "../sdk", version = "1.5.0" } solana-stake-program = { path = "../programs/stake", version = "1.5.0" } diff --git a/cli/src/cli.rs b/cli/src/cli.rs index b983838a87..c42a16c283 100644 --- a/cli/src/cli.rs +++ b/cli/src/cli.rs @@ -9,7 +9,7 @@ use log::*; use num_traits::FromPrimitive; use serde_json::{self, json, Value}; use solana_account_decoder::{UiAccount, UiAccountEncoding}; -use solana_bpf_loader_program::{bpf_verifier, BPFError}; +use solana_bpf_loader_program::{bpf_verifier, BPFError, ThisInstructionMeter}; use solana_clap_utils::{ self, commitment::commitment_arg_with_default, @@ -39,7 +39,7 @@ use solana_client::{ use solana_faucet::faucet::request_airdrop_transaction; #[cfg(test)] use solana_faucet::faucet_mock::request_airdrop_transaction; -use solana_rbpf::vm::Executable; +use solana_rbpf::vm::{Config, Executable}; use solana_remote_wallet::remote_wallet::RemoteWalletManager; use solana_sdk::{ bpf_loader, bpf_loader_deprecated, @@ -1227,8 +1227,12 @@ fn do_process_deploy( CliError::DynamicProgramError(format!("Unable to read program file: {}", err)) })?; - Executable::::from_elf(&program_data, Some(|x| bpf_verifier::check(x, false))) - .map_err(|err| CliError::DynamicProgramError(format!("ELF error: {}", err)))?; + Executable::::from_elf( + &program_data, + Some(|x| bpf_verifier::check(x, false)), + Config::default(), + ) + .map_err(|err| CliError::DynamicProgramError(format!("ELF error: {}", err)))?; let loader_id = if use_deprecated_loader { bpf_loader_deprecated::id() diff --git a/programs/bpf/Cargo.lock b/programs/bpf/Cargo.lock index 3b50e4038f..9b2d6ff88a 100644 --- a/programs/bpf/Cargo.lock +++ b/programs/bpf/Cargo.lock @@ -57,9 +57,9 @@ checksum = "cff77d8686867eceff3105329d4698d96c2391c176d5d03adc90c7389162b5b8" [[package]] name = "ascii" -version = "0.7.1" +version = "0.9.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3ae7d751998c189c1d4468cf0a39bb2eae052a9c58d50ebb3b9591ee3813ad50" +checksum = "eab1c04a571841102f5345a8fc0f6bb3d31c315dec879b5c6e42e40ce7ffa34e" [[package]] name = "assert_matches" @@ -289,12 +289,15 @@ dependencies = [ [[package]] name = "combine" -version = "2.5.2" +version = "3.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1645a65a99c7c8d345761f4b75a6ffe5be3b3b27a93ee731fccc5050ba6be97c" +checksum = "da3da6baa321ec19e1cc41d31bf599f00c783d0517095cdaf0332e3fe8d20680" dependencies = [ "ascii", "byteorder 1.3.4", + "either", + "memchr", + "unreachable", ] [[package]] @@ -1475,6 +1478,7 @@ dependencies = [ "rand_chacha", "rand_core", "rand_hc", + "rand_pcg", ] [[package]] @@ -1505,6 +1509,15 @@ dependencies = [ "rand_core", ] +[[package]] +name = "rand_pcg" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "16abd0c1b639e9eb4d7c50c0b8100b0d0f849be2349829c740fe8e6eb4816429" +dependencies = [ + "rand_core", +] + [[package]] name = "rayon" version = "1.4.1" @@ -2347,9 +2360,9 @@ dependencies = [ [[package]] name = "solana_rbpf" -version = "0.2.0" +version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09e18fa1e1b6cac20a5f2571882b7580a65ae685b1413fc498f975d07d4c968f" +checksum = "8fad65297e2bd080468cb57a97e6a62e9a92928a45960496338e997e8270fa00" dependencies = [ "byteorder 1.3.4", "combine", @@ -2805,6 +2818,15 @@ version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "826e7639553986605ec5979c7dd957c7895e93eabed50ab2ffa7f6128a75097c" +[[package]] +name = "unreachable" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "382810877fe448991dfc7f0dd6e3ae5d58088fd0ea5e35189655f84e6814fa56" +dependencies = [ + "void", +] + [[package]] name = "untrusted" version = "0.7.1" @@ -2828,6 +2850,12 @@ version = "0.9.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b5a972e5669d67ba988ce3dc826706fb0a8b01471c088cb0b6110b805cc36aed" +[[package]] +name = "void" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6a02e4885ed3bc0f2de90ea6dd45ebcbb66dacffe03547fadbb0eeae2770887d" + [[package]] name = "walkdir" version = "2.3.1" diff --git a/programs/bpf/Cargo.toml b/programs/bpf/Cargo.toml index a2f548cf67..45fa36b067 100644 --- a/programs/bpf/Cargo.toml +++ b/programs/bpf/Cargo.toml @@ -27,7 +27,7 @@ solana-logger = { path = "../../logger", version = "1.5.0" } solana-measure = { path = "../../measure", version = "1.5.0" } solana-runtime = { path = "../../runtime", version = "1.5.0" } solana-sdk = { path = "../../sdk", version = "1.5.0" } -solana_rbpf = "=0.2.0" +solana_rbpf = "=0.2.1" [[bench]] name = "bpf_loader" diff --git a/programs/bpf/benches/bpf_loader.rs b/programs/bpf/benches/bpf_loader.rs index e8ec3e79c6..97bcbc9ea5 100644 --- a/programs/bpf/benches/bpf_loader.rs +++ b/programs/bpf/benches/bpf_loader.rs @@ -6,9 +6,12 @@ extern crate test; extern crate solana_bpf_loader_program; use byteorder::{ByteOrder, LittleEndian, WriteBytesExt}; -use solana_bpf_loader_program::ThisInstructionMeter; +use solana_bpf_loader_program::{ + create_vm, serialization::serialize_parameters, syscalls::register_syscalls, BPFError, + ThisInstructionMeter, +}; use solana_measure::measure::Measure; -use solana_rbpf::vm::{Executable, InstructionMeter}; +use solana_rbpf::vm::{Config, Executable, InstructionMeter}; use solana_runtime::{ bank::Bank, bank_client::BankClient, @@ -72,7 +75,9 @@ fn bench_program_create_executable(bencher: &mut Bencher) { let elf = load_elf("bench_alu").unwrap(); bencher.iter(|| { - let _ = Executable::::from_elf(&elf, None).unwrap(); + let _ = + Executable::::from_elf(&elf, None, Config::default()) + .unwrap(); }); } @@ -89,11 +94,14 @@ fn bench_program_alu(bencher: &mut Bencher) { let mut invoke_context = MockInvokeContext::default(); let elf = load_elf("bench_alu").unwrap(); - let executable = - Executable::::from_elf(&elf, None).unwrap(); + let mut executable = + Executable::::from_elf(&elf, None, Config::default()) + .unwrap(); + executable.set_syscall_registry(register_syscalls(&mut invoke_context).unwrap()); + executable.jit_compile().unwrap(); let compute_meter = invoke_context.get_compute_meter(); let mut instruction_meter = ThisInstructionMeter { compute_meter }; - let mut vm = solana_bpf_loader_program::create_vm( + let mut vm = create_vm( &loader_id, executable.as_ref(), &mut inner_iter, @@ -128,22 +136,17 @@ fn bench_program_alu(bencher: &mut Bencher) { println!("{{ \"type\": \"bench\", \"name\": \"bench_program_alu_interpreted_mips\", \"median\": {:?}, \"deviation\": 0 }}", mips); println!("JIT to native:"); - vm.jit_compile().unwrap(); - unsafe { - assert_eq!( - SUCCESS, - vm.execute_program_jit(&mut instruction_meter).unwrap() - ); - } + assert_eq!( + SUCCESS, + vm.execute_program_jit(&mut instruction_meter).unwrap() + ); assert_eq!(ARMSTRONG_LIMIT, LittleEndian::read_u64(&inner_iter)); assert_eq!( ARMSTRONG_EXPECTED, LittleEndian::read_u64(&inner_iter[mem::size_of::()..]) ); - bencher.iter(|| unsafe { - vm.execute_program_jit(&mut instruction_meter).unwrap(); - }); + bencher.iter(|| vm.execute_program_jit(&mut instruction_meter).unwrap()); let summary = bencher.bench(|_bencher| {}).unwrap(); println!(" {:?} instructions", instructions); println!(" {:?} ns/iter median", summary.median as u64); @@ -208,7 +211,7 @@ fn bench_instruction_count_tuner(_bencher: &mut Bencher) { let instruction_data = vec![0u8]; // Serialize account data - let serialized = solana_bpf_loader_program::serialization::serialize_parameters( + let mut serialized = serialize_parameters( &bpf_loader::id(), &solana_sdk::pubkey::new_rand(), &keyed_accounts, @@ -217,14 +220,16 @@ fn bench_instruction_count_tuner(_bencher: &mut Bencher) { .unwrap(); let elf = load_elf("tuner").unwrap(); - let executable = - Executable::::from_elf(&elf, None).unwrap(); + let mut executable = + Executable::::from_elf(&elf, None, Config::default()) + .unwrap(); + executable.set_syscall_registry(register_syscalls(&mut invoke_context).unwrap()); let compute_meter = invoke_context.get_compute_meter(); let mut instruction_meter = ThisInstructionMeter { compute_meter }; - let mut vm = solana_bpf_loader_program::create_vm( + let mut vm = create_vm( &loader_id, executable.as_ref(), - &serialized, + &mut serialized, &[], &mut invoke_context, ) diff --git a/programs/bpf/tests/programs.rs b/programs/bpf/tests/programs.rs index 27ebae82d3..6601e73624 100644 --- a/programs/bpf/tests/programs.rs +++ b/programs/bpf/tests/programs.rs @@ -6,9 +6,10 @@ extern crate solana_bpf_loader_program; use solana_bpf_loader_program::{ create_vm, serialization::{deserialize_parameters, serialize_parameters}, + syscalls::register_syscalls, ThisInstructionMeter, }; -use solana_rbpf::vm::Executable; +use solana_rbpf::vm::{Config, Executable, Tracer}; use solana_runtime::{ bank::Bank, bank_client::BankClient, @@ -85,23 +86,62 @@ fn run_program( let compute_meter = invoke_context.get_compute_meter(); let mut instruction_meter = ThisInstructionMeter { compute_meter }; - let executable = Executable::from_elf(&data, None).unwrap(); - let mut vm = create_vm( - &loader_id, - executable.as_ref(), - ¶meter_bytes, - parameter_accounts, - &mut invoke_context, - ) - .unwrap(); + let config = Config { + max_call_depth: 20, + stack_frame_size: 4096, + enable_instruction_meter: true, + enable_instruction_tracing: true, + }; + let mut executable = Executable::from_elf(&data, None, config).unwrap(); + executable.set_syscall_registry(register_syscalls(&mut invoke_context).unwrap()); + executable.jit_compile().unwrap(); - assert_eq!( - SUCCESS, - vm.execute_program_interpreted(&mut instruction_meter) - .unwrap() - ); - deserialize_parameters(&bpf_loader::id(), parameter_accounts, ¶meter_bytes).unwrap(); - Ok(vm.get_total_instruction_count()) + let mut instruction_count = 0; + let mut tracer = None; + for i in 0..2 { + let mut parameter_bytes = parameter_bytes.clone(); + let mut vm = create_vm( + &loader_id, + executable.as_ref(), + &mut parameter_bytes, + parameter_accounts, + &mut invoke_context, + ) + .unwrap(); + let result = if i == 0 { + vm.execute_program_interpreted(&mut instruction_meter) + } else { + vm.execute_program_jit(&mut instruction_meter) + }; + assert_eq!(SUCCESS, result.unwrap()); + deserialize_parameters(&bpf_loader::id(), parameter_accounts, ¶meter_bytes).unwrap(); + if i == 1 { + assert_eq!(instruction_count, vm.get_total_instruction_count()); + } + instruction_count = vm.get_total_instruction_count(); + if config.enable_instruction_tracing { + if i == 1 { + if !Tracer::compare(tracer.as_ref().unwrap(), vm.get_tracer()) { + let mut tracer_display = String::new(); + tracer + .as_ref() + .unwrap() + .write(&mut tracer_display, vm.get_program()) + .unwrap(); + println!("TRACE (interpreted): {}", tracer_display); + let mut tracer_display = String::new(); + vm.get_tracer() + .write(&mut tracer_display, vm.get_program()) + .unwrap(); + println!("TRACE (jit): {}", tracer_display); + assert!(false); + } + } + tracer = Some(vm.get_tracer().clone()); + } + } + + Ok(instruction_count) } fn process_transaction_and_record_inner( diff --git a/programs/bpf_loader/Cargo.toml b/programs/bpf_loader/Cargo.toml index a7f4654449..7420ad6d98 100644 --- a/programs/bpf_loader/Cargo.toml +++ b/programs/bpf_loader/Cargo.toml @@ -16,7 +16,7 @@ num-derive = "0.3" num-traits = "0.2" solana-runtime = { path = "../../runtime", version = "1.5.0" } solana-sdk = { path = "../../sdk", version = "1.5.0" } -solana_rbpf = "=0.2.0" +solana_rbpf = "=0.2.1" thiserror = "1.0" [dev-dependencies] diff --git a/programs/bpf_loader/src/lib.rs b/programs/bpf_loader/src/lib.rs index deea10cd7e..2104927782 100644 --- a/programs/bpf_loader/src/lib.rs +++ b/programs/bpf_loader/src/lib.rs @@ -45,6 +45,8 @@ pub enum BPFLoaderError { VirtualMachineCreationFailed = 0x0b9f_0001, #[error("virtual machine failed to run the program to completion")] VirtualMachineFailedToRunProgram = 0x0b9f_0002, + #[error("failed to compile program")] + JustInTimeCompilationFailed = 0x0b9f_0003, } impl DecodeError for BPFLoaderError { fn type_of() -> &'static str { @@ -89,12 +91,24 @@ fn map_ebpf_error( InstructionError::InvalidAccountData } +const IS_JIT_ENABLED: bool = false; + pub fn create_and_cache_executor( program: &KeyedAccount, invoke_context: &mut dyn InvokeContext, ) -> Result, InstructionError> { - let executable = Executable::from_elf(&program.try_account_ref()?.data, None) - .map_err(|e| map_ebpf_error(invoke_context, e))?; + let bpf_compute_budget = invoke_context.get_bpf_compute_budget(); + let mut executable = Executable::::from_elf( + &program.try_account_ref()?.data, + None, + Config { + max_call_depth: bpf_compute_budget.max_call_depth, + stack_frame_size: bpf_compute_budget.stack_frame_size, + enable_instruction_meter: true, + enable_instruction_tracing: false, + }, + ) + .map_err(|e| map_ebpf_error(invoke_context, e))?; let (_, elf_bytes) = executable .get_text_bytes() .map_err(|e| map_ebpf_error(invoke_context, e))?; @@ -103,6 +117,12 @@ pub fn create_and_cache_executor( !invoke_context.is_feature_active(&bpf_compute_budget_balancing::id()), ) .map_err(|e| map_ebpf_error(invoke_context, EbpfError::UserError(e)))?; + let syscall_registry = syscalls::register_syscalls(invoke_context) + .map_err(|e| map_ebpf_error(invoke_context, e))?; + executable.set_syscall_registry(syscall_registry); + if IS_JIT_ENABLED && executable.jit_compile().is_err() { + return Err(BPFLoaderError::JustInTimeCompilationFailed.into()); + } let executor = Arc::new(BPFExecutor { executable }); invoke_context.add_executor(program.unsigned_key(), executor.clone()); Ok(executor) @@ -115,24 +135,21 @@ const DEFAULT_HEAP_SIZE: usize = 32 * 1024; /// Create the BPF virtual machine pub fn create_vm<'a>( loader_id: &'a Pubkey, - executable: &'a dyn Executable, - parameter_bytes: &[u8], + executable: &'a dyn Executable, + parameter_bytes: &mut [u8], parameter_accounts: &'a [KeyedAccount<'a>], invoke_context: &'a mut dyn InvokeContext, ) -> Result, EbpfError> { let heap = vec![0_u8; DEFAULT_HEAP_SIZE]; - let heap_region = MemoryRegion::new_from_slice(&heap, MM_HEAP_START, true); - let bpf_compute_budget = invoke_context.get_bpf_compute_budget(); - let mut vm = EbpfVm::new( - executable, - Config { - max_call_depth: bpf_compute_budget.max_call_depth, - stack_frame_size: bpf_compute_budget.stack_frame_size, - }, - parameter_bytes, - &[heap_region], + let heap_region = MemoryRegion::new_from_slice(&heap, MM_HEAP_START, 0, true); + let mut vm = EbpfVm::new(executable, parameter_bytes, &[heap_region])?; + syscalls::bind_syscall_context_objects( + loader_id, + &mut vm, + parameter_accounts, + invoke_context, + heap, )?; - syscalls::register_syscalls(loader_id, &mut vm, parameter_accounts, invoke_context, heap)?; Ok(vm) } @@ -219,7 +236,7 @@ impl InstructionMeter for ThisInstructionMeter { /// BPF Loader's Executor implementation pub struct BPFExecutor { - executable: Box>, + executable: Box>, } // Well, implement Debug for solana_rbpf::vm::Executable in solana-rbpf... @@ -244,7 +261,7 @@ impl Executor for BPFExecutor { let program = next_keyed_account(&mut keyed_accounts_iter)?; let parameter_accounts = keyed_accounts_iter.as_slice(); - let parameter_bytes = serialize_parameters( + let mut parameter_bytes = serialize_parameters( program_id, program.unsigned_key(), parameter_accounts, @@ -255,7 +272,7 @@ impl Executor for BPFExecutor { let mut vm = match create_vm( program_id, self.executable.as_ref(), - parameter_bytes.as_slice(), + &mut parameter_bytes, ¶meter_accounts, invoke_context, ) { @@ -269,12 +286,8 @@ impl Executor for BPFExecutor { stable_log::program_invoke(&logger, program.unsigned_key(), invoke_depth); let mut instruction_meter = ThisInstructionMeter::new(compute_meter.clone()); let before = compute_meter.borrow().get_remaining(); - const IS_JIT_ENABLED: bool = false; let result = if IS_JIT_ENABLED { - if vm.jit_compile().is_err() { - return Err(BPFLoaderError::VirtualMachineCreationFailed.into()); - } - unsafe { vm.execute_program_jit(&mut instruction_meter) } + vm.execute_program_jit(&mut instruction_meter) } else { vm.execute_program_interpreted(&mut instruction_meter) }; @@ -357,14 +370,14 @@ mod tests { ]; let input = &mut [0x00]; - let executable = Executable::::from_text_bytes(program, None).unwrap(); - let mut vm = EbpfVm::::new( - executable.as_ref(), + let executable = Executable::::from_text_bytes( + program, + None, Config::default(), - input, - &[], ) .unwrap(); + let mut vm = + EbpfVm::::new(executable.as_ref(), input, &[]).unwrap(); let mut instruction_meter = TestInstructionMeter { remaining: 10 }; vm.execute_program_interpreted(&mut instruction_meter) .unwrap(); diff --git a/programs/bpf_loader/src/syscalls.rs b/programs/bpf_loader/src/syscalls.rs index 4993515c70..8745692cd3 100644 --- a/programs/bpf_loader/src/syscalls.rs +++ b/programs/bpf_loader/src/syscalls.rs @@ -2,10 +2,11 @@ use crate::{alloc, BPFError}; use alloc::Alloc; use curve25519_dalek::{ristretto::RistrettoPoint, scalar::Scalar}; use solana_rbpf::{ - ebpf::{hash_symbol_name, MM_HEAP_START}, + ebpf::MM_HEAP_START, error::EbpfError, memory_region::{AccessType, MemoryMapping}, - vm::{EbpfVm, Syscall, SyscallObject}, + question_mark, + vm::{EbpfVm, SyscallObject, SyscallRegistry}, }; use solana_runtime::message_processor::MessageProcessor; use solana_sdk::{ @@ -87,7 +88,48 @@ impl SyscallConsume for Rc> { /// Simple bump allocator, never frees use crate::allocator_bump::BPFAllocator; -pub fn register_syscalls<'a>( +pub fn register_syscalls( + invoke_context: &mut dyn InvokeContext, +) -> Result> { + let mut syscall_registry = SyscallRegistry::default(); + + syscall_registry.register_syscall_by_name(b"abort", SyscallAbort::call)?; + syscall_registry.register_syscall_by_name(b"sol_panic_", SyscallPanic::call)?; + syscall_registry.register_syscall_by_name(b"sol_log_", SyscallLog::call)?; + syscall_registry.register_syscall_by_name(b"sol_log_64_", SyscallLogU64::call)?; + + if invoke_context.is_feature_active(&sol_log_compute_units_syscall::id()) { + syscall_registry + .register_syscall_by_name(b"sol_log_compute_units_", SyscallLogBpfComputeUnits::call)?; + } + + if invoke_context.is_feature_active(&pubkey_log_syscall_enabled::id()) { + syscall_registry.register_syscall_by_name(b"sol_log_pubkey", SyscallLogPubkey::call)?; + } + + if invoke_context.is_feature_active(&sha256_syscall_enabled::id()) { + syscall_registry.register_syscall_by_name(b"sol_sha256", SyscallSha256::call)?; + } + + if invoke_context.is_feature_active(&ristretto_mul_syscall_enabled::id()) { + syscall_registry + .register_syscall_by_name(b"sol_ristretto_mul", SyscallRistrettoMul::call)?; + } + + syscall_registry.register_syscall_by_name( + b"sol_create_program_address", + SyscallCreateProgramAddress::call, + )?; + syscall_registry + .register_syscall_by_name(b"sol_invoke_signed_c", SyscallInvokeSignedC::call)?; + syscall_registry + .register_syscall_by_name(b"sol_invoke_signed_rust", SyscallInvokeSignedRust::call)?; + syscall_registry.register_syscall_by_name(b"sol_alloc_free_", SyscallAllocFree::call)?; + + Ok(syscall_registry) +} + +pub fn bind_syscall_context_objects<'a>( loader_id: &'a Pubkey, vm: &mut EbpfVm<'a, BPFError, crate::ThisInstructionMeter>, callers_keyed_accounts: &'a [KeyedAccount<'a>], @@ -98,194 +140,199 @@ pub fn register_syscalls<'a>( // Syscall functions common across languages - vm.register_syscall(hash_symbol_name(b"abort"), Syscall::Function(syscall_abort))?; - vm.register_syscall( - hash_symbol_name(b"sol_panic_"), - Syscall::Object(Box::new(SyscallPanic { loader_id })), - )?; - vm.register_syscall( - hash_symbol_name(b"sol_log_"), - Syscall::Object(Box::new(SyscallLog { + vm.bind_syscall_context_object(Box::new(SyscallAbort {}), None)?; + vm.bind_syscall_context_object(Box::new(SyscallPanic { loader_id }), None)?; + vm.bind_syscall_context_object( + Box::new(SyscallLog { cost: bpf_compute_budget.log_units, compute_meter: invoke_context.get_compute_meter(), logger: invoke_context.get_logger(), loader_id, - })), + }), + None, )?; - vm.register_syscall( - hash_symbol_name(b"sol_log_64_"), - Syscall::Object(Box::new(SyscallLogU64 { + vm.bind_syscall_context_object( + Box::new(SyscallLogU64 { cost: bpf_compute_budget.log_64_units, compute_meter: invoke_context.get_compute_meter(), logger: invoke_context.get_logger(), - })), + }), + None, )?; if invoke_context.is_feature_active(&sol_log_compute_units_syscall::id()) { - vm.register_syscall( - hash_symbol_name(b"sol_log_compute_units_"), - Syscall::Object(Box::new(SyscallLogBpfComputeUnits { + vm.bind_syscall_context_object( + Box::new(SyscallLogBpfComputeUnits { cost: 0, compute_meter: invoke_context.get_compute_meter(), logger: invoke_context.get_logger(), - })), + }), + None, )?; } if invoke_context.is_feature_active(&pubkey_log_syscall_enabled::id()) { - vm.register_syscall( - hash_symbol_name(b"sol_log_pubkey"), - Syscall::Object(Box::new(SyscallLogPubkey { + vm.bind_syscall_context_object( + Box::new(SyscallLogPubkey { cost: bpf_compute_budget.log_pubkey_units, compute_meter: invoke_context.get_compute_meter(), logger: invoke_context.get_logger(), loader_id, - })), + }), + None, )?; } if invoke_context.is_feature_active(&sha256_syscall_enabled::id()) { - vm.register_syscall( - hash_symbol_name(b"sol_sha256"), - Syscall::Object(Box::new(SyscallSha256 { + vm.bind_syscall_context_object( + Box::new(SyscallSha256 { sha256_base_cost: bpf_compute_budget.sha256_base_cost, sha256_byte_cost: bpf_compute_budget.sha256_byte_cost, compute_meter: invoke_context.get_compute_meter(), loader_id, - })), + }), + None, )?; } if invoke_context.is_feature_active(&ristretto_mul_syscall_enabled::id()) { - vm.register_syscall( - hash_symbol_name(b"sol_ristretto_mul"), - Syscall::Object(Box::new(SyscallRistrettoMul { + vm.bind_syscall_context_object( + Box::new(SyscallRistrettoMul { cost: 0, compute_meter: invoke_context.get_compute_meter(), loader_id, - })), + }), + None, )?; } - vm.register_syscall( - hash_symbol_name(b"sol_create_program_address"), - Syscall::Object(Box::new(SyscallCreateProgramAddress { + vm.bind_syscall_context_object( + Box::new(SyscallCreateProgramAddress { cost: bpf_compute_budget.create_program_address_units, compute_meter: invoke_context.get_compute_meter(), loader_id, - })), + }), + None, )?; // Cross-program invocation syscalls let invoke_context = Rc::new(RefCell::new(invoke_context)); - vm.register_syscall( - hash_symbol_name(b"sol_invoke_signed_c"), - Syscall::Object(Box::new(SyscallInvokeSignedC { + vm.bind_syscall_context_object( + Box::new(SyscallInvokeSignedC { callers_keyed_accounts, invoke_context: invoke_context.clone(), loader_id, - })), + }), + None, )?; - vm.register_syscall( - hash_symbol_name(b"sol_invoke_signed_rust"), - Syscall::Object(Box::new(SyscallInvokeSignedRust { + vm.bind_syscall_context_object( + Box::new(SyscallInvokeSignedRust { callers_keyed_accounts, invoke_context: invoke_context.clone(), loader_id, - })), + }), + None, )?; // Memory allocator - vm.register_syscall( - hash_symbol_name(b"sol_alloc_free_"), - Syscall::Object(Box::new(SyscallAllocFree { + vm.bind_syscall_context_object( + Box::new(SyscallAllocFree { aligned: *loader_id != bpf_loader_deprecated::id(), allocator: BPFAllocator::new(heap, MM_HEAP_START), - })), + }), + None, )?; Ok(()) } -#[macro_export] -macro_rules! translate { - ($memory_mapping:expr, $access_type:expr, $vm_addr:expr, $len:expr, $loader_id:expr) => { - $memory_mapping.map::($access_type, $vm_addr as u64, $len as u64) - }; +fn translate( + memory_mapping: &MemoryMapping, + access_type: AccessType, + vm_addr: u64, + len: u64, + _loader_id: &Pubkey, +) -> Result> { + memory_mapping.map::(access_type, vm_addr, len) } -#[macro_export] -macro_rules! translate_type_mut { - ($memory_mapping:expr, $access_type:expr, $vm_addr:expr, $t:ty, $loader_id:expr) => {{ - if $loader_id != &bpf_loader_deprecated::id() - && ($vm_addr as u64 as *mut $t).align_offset(align_of::<$t>()) != 0 - { - Err(SyscallError::UnalignedPointer.into()) - } else { - unsafe { - match translate!( - $memory_mapping, - $access_type, - $vm_addr, - size_of::<$t>(), - $loader_id - ) { - Ok(value) => Ok(&mut *(value as *mut $t)), - Err(e) => Err(e), - } - } - } - }}; -} -#[macro_export] -macro_rules! translate_type { - ($memory_mapping:expr, $access_type:expr, $vm_addr:expr, $t:ty, $loader_id:expr) => { - match translate_type_mut!($memory_mapping, $access_type, $vm_addr, $t, $loader_id) { - Ok(value) => Ok(&*value), - Err(e) => Err(e), - } - }; -} - -#[macro_export] -macro_rules! translate_slice_mut { - ($memory_mapping:expr, $access_type:expr, $vm_addr:expr, $t:ty, $len:expr, $loader_id:expr) => {{ - if $loader_id != &bpf_loader_deprecated::id() - && ($vm_addr as u64 as *mut $t).align_offset(align_of::<$t>()) != 0 - { - Err(SyscallError::UnalignedPointer.into()) - } else if $len == 0 { - Ok(unsafe { from_raw_parts_mut(0x1 as *mut $t, $len as usize) }) - } else { - match translate!( - $memory_mapping, - $access_type, - $vm_addr, - ($len as usize).saturating_mul(size_of::<$t>()), - $loader_id +fn translate_type_mut<'a, T>( + memory_mapping: &MemoryMapping, + access_type: AccessType, + vm_addr: u64, + loader_id: &Pubkey, +) -> Result<&'a mut T, EbpfError> { + if loader_id != &bpf_loader_deprecated::id() + && (vm_addr as u64 as *mut T).align_offset(align_of::()) != 0 + { + Err(SyscallError::UnalignedPointer.into()) + } else { + unsafe { + match translate( + memory_mapping, + access_type, + vm_addr, + size_of::() as u64, + loader_id, ) { - Ok(value) => Ok(unsafe { from_raw_parts_mut(value as *mut $t, $len as usize) }), + Ok(value) => Ok(&mut *(value as *mut T)), Err(e) => Err(e), } } - }}; + } } -#[macro_export] -macro_rules! translate_slice { - ($memory_mapping:expr, $access_type:expr, $vm_addr:expr, $t:ty, $len:expr, $loader_id:expr) => { - match translate_slice_mut!( - $memory_mapping, - $access_type, - $vm_addr, - $t, - $len, - $loader_id + +fn translate_type<'a, T>( + memory_mapping: &MemoryMapping, + access_type: AccessType, + vm_addr: u64, + loader_id: &Pubkey, +) -> Result<&'a T, EbpfError> { + match translate_type_mut::(memory_mapping, access_type, vm_addr, loader_id) { + Ok(value) => Ok(&*value), + Err(e) => Err(e), + } +} + +fn translate_slice_mut<'a, T>( + memory_mapping: &MemoryMapping, + access_type: AccessType, + vm_addr: u64, + len: u64, + loader_id: &Pubkey, +) -> Result<&'a mut [T], EbpfError> { + if loader_id != &bpf_loader_deprecated::id() + && (vm_addr as u64 as *mut T).align_offset(align_of::()) != 0 + { + Err(SyscallError::UnalignedPointer.into()) + } else if len == 0 { + Ok(unsafe { from_raw_parts_mut(0x1 as *mut T, len as usize) }) + } else { + match translate( + memory_mapping, + access_type, + vm_addr, + len * size_of::() as u64, + loader_id, ) { - Ok(value) => Ok(&*value), + Ok(value) => Ok(unsafe { from_raw_parts_mut(value as *mut T, len as usize) }), Err(e) => Err(e), } - }; + } +} + +fn translate_slice<'a, T>( + memory_mapping: &MemoryMapping, + access_type: AccessType, + vm_addr: u64, + len: u64, + loader_id: &Pubkey, +) -> Result<&'a [T], EbpfError> { + match translate_slice_mut::(memory_mapping, access_type, vm_addr, len, loader_id) { + Ok(value) => Ok(&*value), + Err(e) => Err(e), + } } /// Take a virtual pointer to a string (points to BPF VM memory space), translate it @@ -298,7 +345,7 @@ fn translate_string_and_do( loader_id: &Pubkey, work: &mut dyn FnMut(&str) -> Result>, ) -> Result> { - let buf = translate_slice!(memory_mapping, access_type, addr, u8, len, loader_id)?; + let buf = translate_slice::(memory_mapping, access_type, addr, len, loader_id)?; let i = match buf.iter().position(|byte| *byte == 0) { Some(i) => i, None => len as usize, @@ -313,15 +360,20 @@ fn translate_string_and_do( /// LLVM will insert calls to `abort()` if it detects an untenable situation, /// `abort()` is not intended to be called explicitly by the program. /// Causes the BPF program to be halted immediately -pub fn syscall_abort( - _arg1: u64, - _arg2: u64, - _arg3: u64, - _arg4: u64, - _arg5: u64, - _memory_mapping: &MemoryMapping, -) -> Result> { - Err(SyscallError::Abort.into()) +pub struct SyscallAbort {} +impl SyscallObject for SyscallAbort { + fn call( + &mut self, + _arg1: u64, + _arg2: u64, + _arg3: u64, + _arg4: u64, + _arg5: u64, + _memory_mapping: &MemoryMapping, + result: &mut Result>, + ) { + *result = Err(SyscallError::Abort.into()); + } } /// Panic syscall function, called when the BPF program calls 'sol_panic_()` @@ -339,15 +391,16 @@ impl<'a> SyscallObject for SyscallPanic<'a> { column: u64, _arg5: u64, memory_mapping: &MemoryMapping, - ) -> Result> { - translate_string_and_do( + result: &mut Result>, + ) { + *result = translate_string_and_do( memory_mapping, AccessType::Load, file, len, &self.loader_id, &mut |string: &str| Err(SyscallError::Panic(string.to_string(), line, column).into()), - ) + ); } } @@ -367,20 +420,24 @@ impl<'a> SyscallObject for SyscallLog<'a> { _arg4: u64, _arg5: u64, memory_mapping: &MemoryMapping, - ) -> Result> { - self.compute_meter.consume(self.cost)?; - translate_string_and_do( - memory_mapping, - AccessType::Load, - addr, - len, - &self.loader_id, - &mut |string: &str| { - stable_log::program_log(&self.logger, string); - Ok(0) - }, - )?; - Ok(0) + result: &mut Result>, + ) { + question_mark!(self.compute_meter.consume(self.cost), result); + question_mark!( + translate_string_and_do( + memory_mapping, + AccessType::Load, + addr, + len, + &self.loader_id, + &mut |string: &str| { + stable_log::program_log(&self.logger, string); + Ok(0) + }, + ), + result + ); + *result = Ok(0); } } @@ -399,8 +456,9 @@ impl SyscallObject for SyscallLogU64 { arg4: u64, arg5: u64, _memory_mapping: &MemoryMapping, - ) -> Result> { - self.compute_meter.consume(self.cost)?; + result: &mut Result>, + ) { + question_mark!(self.compute_meter.consume(self.cost), result); stable_log::program_log( &self.logger, &format!( @@ -408,7 +466,7 @@ impl SyscallObject for SyscallLogU64 { arg1, arg2, arg3, arg4, arg5 ), ); - Ok(0) + *result = Ok(0); } } @@ -427,19 +485,22 @@ impl SyscallObject for SyscallLogBpfComputeUnits { _arg4: u64, _arg5: u64, _memory_mapping: &MemoryMapping, - ) -> Result> { - self.compute_meter.consume(self.cost)?; - let logger = self - .logger - .try_borrow_mut() - .map_err(|_| SyscallError::InvokeContextBorrowFailed)?; + result: &mut Result>, + ) { + question_mark!(self.compute_meter.consume(self.cost), result); + let logger = question_mark!( + self.logger + .try_borrow_mut() + .map_err(|_| SyscallError::InvokeContextBorrowFailed), + result + ); if logger.log_enabled() { logger.log(&format!( "Program consumption: {} units remaining", self.compute_meter.borrow().get_remaining() )); } - Ok(0) + *result = Ok(0); } } @@ -459,17 +520,20 @@ impl<'a> SyscallObject for SyscallLogPubkey<'a> { _arg4: u64, _arg5: u64, memory_mapping: &MemoryMapping, - ) -> Result> { - self.compute_meter.consume(self.cost)?; - let pubkey = translate_type!( - memory_mapping, - AccessType::Load, - pubkey_addr, - Pubkey, - self.loader_id - )?; + result: &mut Result>, + ) { + question_mark!(self.compute_meter.consume(self.cost), result); + let pubkey = question_mark!( + translate_type::( + memory_mapping, + AccessType::Load, + pubkey_addr, + self.loader_id + ), + result + ); stable_log::program_log(&self.logger, &pubkey.to_string()); - Ok(0) + *result = Ok(0); } } @@ -492,7 +556,8 @@ impl SyscallObject for SyscallAllocFree { _arg4: u64, _arg5: u64, _memory_mapping: &MemoryMapping, - ) -> Result> { + result: &mut Result>, + ) { let align = if self.aligned { align_of::() } else { @@ -500,9 +565,12 @@ impl SyscallObject for SyscallAllocFree { }; let layout = match Layout::from_size_align(size as usize, align) { Ok(layout) => layout, - Err(_) => return Ok(0), + Err(_) => { + *result = Ok(0); + return; + } }; - if free_addr == 0 { + *result = if free_addr == 0 { match self.allocator.alloc(layout) { Ok(addr) => Ok(addr as u64), Err(_) => Ok(0), @@ -510,7 +578,7 @@ impl SyscallObject for SyscallAllocFree { } else { self.allocator.dealloc(free_addr, layout); Ok(0) - } + }; } } @@ -529,54 +597,66 @@ impl<'a> SyscallObject for SyscallCreateProgramAddress<'a> { address_addr: u64, _arg5: u64, memory_mapping: &MemoryMapping, - ) -> Result> { - self.compute_meter.consume(self.cost)?; + result: &mut Result>, + ) { + question_mark!(self.compute_meter.consume(self.cost), result); // TODO need ref? - let untranslated_seeds = translate_slice!( - memory_mapping, - AccessType::Load, - seeds_addr, - &[&u8], - seeds_len, - self.loader_id - )?; - let seeds = untranslated_seeds - .iter() - .map(|untranslated_seed| { - translate_slice!( - memory_mapping, - AccessType::Load, - untranslated_seed.as_ptr(), - u8, - untranslated_seed.len(), - self.loader_id - ) - }) - .collect::, EbpfError>>()?; - let program_id = translate_type!( - memory_mapping, - AccessType::Load, - program_id_addr, - Pubkey, - self.loader_id - )?; + let untranslated_seeds = question_mark!( + translate_slice::<&[&u8]>( + memory_mapping, + AccessType::Load, + seeds_addr, + seeds_len, + self.loader_id + ), + result + ); + let seeds = question_mark!( + untranslated_seeds + .iter() + .map(|untranslated_seed| { + translate_slice::( + memory_mapping, + AccessType::Load, + untranslated_seed.as_ptr() as *const _ as u64, + untranslated_seed.len() as u64, + self.loader_id, + ) + }) + .collect::, EbpfError>>(), + result + ); + let program_id = question_mark!( + translate_type::( + memory_mapping, + AccessType::Load, + program_id_addr, + self.loader_id + ), + result + ); let new_address = match Pubkey::create_program_address(&seeds, program_id) .map_err(SyscallError::BadSeeds) { Ok(address) => address, - Err(_) => return Ok(1), + Err(_) => { + *result = Ok(1); + return; + } }; - let address = translate_slice_mut!( - memory_mapping, - AccessType::Store, - address_addr, - u8, - 32, - self.loader_id - )?; + let address = question_mark!( + translate_slice_mut::( + memory_mapping, + AccessType::Store, + address_addr, + 32, + self.loader_id + ), + result + ); address.copy_from_slice(new_address.as_ref()); - Ok(0) + *result = Ok(0); } } @@ -596,42 +676,52 @@ impl<'a> SyscallObject for SyscallSha256<'a> { _arg4: u64, _arg5: u64, memory_mapping: &MemoryMapping, - ) -> Result> { - self.compute_meter.consume(self.sha256_base_cost)?; - let hash_result = translate_slice_mut!( - memory_mapping, - AccessType::Store, - result_addr, - u8, - HASH_BYTES, - self.loader_id - )?; + result: &mut Result>, + ) { + question_mark!(self.compute_meter.consume(self.sha256_base_cost), result); + let hash_result = question_mark!( + translate_slice_mut::( + memory_mapping, + AccessType::Store, + result_addr, + HASH_BYTES as u64, + self.loader_id + ), + result + ); let mut hasher = Hasher::default(); if vals_len > 0 { - let vals = translate_slice!( - memory_mapping, - AccessType::Load, - vals_addr, - &[u8], - vals_len, - self.loader_id - )?; - for val in vals.iter() { - let bytes = translate_slice!( + let vals = question_mark!( + translate_slice::<&[u8]>( memory_mapping, AccessType::Load, - val.as_ptr(), - u8, - val.len(), + vals_addr, + vals_len, self.loader_id - )?; - self.compute_meter - .consume(self.sha256_byte_cost * (val.len() as u64 / 2))?; + ), + result + ); + for val in vals.iter() { + let bytes = question_mark!( + translate_slice::( + memory_mapping, + AccessType::Load, + val.as_ptr() as u64, + val.len() as u64, + self.loader_id + ), + result + ); + question_mark!( + self.compute_meter + .consume(self.sha256_byte_cost * (val.len() as u64 / 2)), + result + ); hasher.hash(bytes); } } hash_result.copy_from_slice(&hasher.result().to_bytes()); - Ok(0) + *result = Ok(0); } } @@ -650,34 +740,40 @@ impl<'a> SyscallObject for SyscallRistrettoMul<'a> { _arg4: u64, _arg5: u64, memory_mapping: &MemoryMapping, - ) -> Result> { - self.compute_meter.consume(self.cost)?; + result: &mut Result>, + ) { + question_mark!(self.compute_meter.consume(self.cost), result); - let point = translate_type!( - memory_mapping, - AccessType::Load, - point_addr, - RistrettoPoint, - self.loader_id - )?; - let scalar = translate_type!( - memory_mapping, - AccessType::Load, - scalar_addr, - Scalar, - self.loader_id - )?; - let result = translate_type_mut!( - memory_mapping, - AccessType::Store, - result_addr, - RistrettoPoint, - self.loader_id - )?; + let point = question_mark!( + translate_type::( + memory_mapping, + AccessType::Load, + point_addr, + self.loader_id + ), + result + ); + let scalar = question_mark!( + translate_type::( + memory_mapping, + AccessType::Load, + scalar_addr, + self.loader_id + ), + result + ); + let output = question_mark!( + translate_type_mut::( + memory_mapping, + AccessType::Store, + result_addr, + self.loader_id + ), + result + ); + *output = point * scalar; - *result = point * scalar; - - Ok(0) + *result = Ok(0); } } @@ -705,14 +801,14 @@ trait SyscallInvokeSigned<'a> { &self, message: &Message, account_infos_addr: u64, - account_infos_len: usize, + account_infos_len: u64, memory_mapping: &MemoryMapping, ) -> Result, EbpfError>; fn translate_signers( &self, program_id: &Pubkey, signers_seeds_addr: u64, - signers_seeds_len: usize, + signers_seeds_len: u64, memory_mapping: &MemoryMapping, ) -> Result, EbpfError>; } @@ -737,29 +833,22 @@ impl<'a> SyscallInvokeSigned<'a> for SyscallInvokeSignedRust<'a> { addr: u64, memory_mapping: &MemoryMapping, ) -> Result> { - let ix = translate_type!( + let ix = + translate_type::(memory_mapping, AccessType::Load, addr, self.loader_id)?; + let accounts = translate_slice::( memory_mapping, AccessType::Load, - addr, - Instruction, - self.loader_id - )?; - let accounts = translate_slice!( - memory_mapping, - AccessType::Load, - ix.accounts.as_ptr(), - AccountMeta, - ix.accounts.len(), - self.loader_id + ix.accounts.as_ptr() as u64, + ix.accounts.len() as u64, + self.loader_id, )? .to_vec(); - let data = translate_slice!( + let data = translate_slice::( memory_mapping, AccessType::Load, - ix.data.as_ptr(), - u8, - ix.data.len(), - self.loader_id + ix.data.as_ptr() as u64, + ix.data.len() as u64, + self.loader_id, )? .to_vec(); Ok(Instruction { @@ -773,17 +862,16 @@ impl<'a> SyscallInvokeSigned<'a> for SyscallInvokeSignedRust<'a> { &self, message: &Message, account_infos_addr: u64, - account_infos_len: usize, + account_infos_len: u64, memory_mapping: &MemoryMapping, ) -> Result, EbpfError> { let account_infos = if account_infos_len > 0 { - translate_slice!( + translate_slice::( memory_mapping, AccessType::Load, account_infos_addr, - AccountInfo, account_infos_len, - self.loader_id + self.loader_id, )? } else { &[] @@ -793,71 +881,64 @@ impl<'a> SyscallInvokeSigned<'a> for SyscallInvokeSignedRust<'a> { let mut refs = Vec::with_capacity(message.account_keys.len()); 'root: for account_key in message.account_keys.iter() { for account_info in account_infos.iter() { - let key = translate_type!( + let key = translate_type::( memory_mapping, AccessType::Load, - account_info.key as *const _, - Pubkey, - self.loader_id + account_info.key as *const _ as u64, + self.loader_id, )?; if account_key == key { let lamports = { // Double translate lamports out of RefCell - let ptr = translate_type!( + let ptr = translate_type::( memory_mapping, AccessType::Load, - account_info.lamports.as_ptr(), - u64, - self.loader_id + account_info.lamports.as_ptr() as u64, + self.loader_id, )?; - translate_type_mut!( + translate_type_mut::( memory_mapping, AccessType::Store, *ptr, - u64, - self.loader_id + self.loader_id, )? }; - let owner = translate_type_mut!( + let owner = translate_type_mut::( memory_mapping, AccessType::Load, - account_info.owner as *const _, - Pubkey, - self.loader_id + account_info.owner as *const _ as u64, + self.loader_id, )?; let (data, ref_to_len_in_vm, serialized_len_ptr) = { // Double translate data out of RefCell - let data = *translate_type!( + let data = *translate_type::<&[u8]>( memory_mapping, AccessType::Load, - account_info.data.as_ptr(), - &[u8], - self.loader_id + account_info.data.as_ptr() as *const _ as u64, + self.loader_id, )?; - let translated = translate!( + let translated = translate( memory_mapping, AccessType::Load, - account_info.data.as_ptr(), + account_info.data.as_ptr() as *const _ as u64, 8, - self.loader_id + self.loader_id, )? as *mut u64; let ref_to_len_in_vm = unsafe { &mut *translated.offset(1) }; let ref_of_len_in_input_buffer = unsafe { data.as_ptr().offset(-8) }; - let serialized_len_ptr = translate_type_mut!( + let serialized_len_ptr = translate_type_mut::( memory_mapping, AccessType::Store, - ref_of_len_in_input_buffer, - u64, - self.loader_id + ref_of_len_in_input_buffer as *const _ as u64, + self.loader_id, )?; ( - translate_slice_mut!( + translate_slice_mut::( memory_mapping, AccessType::Store, - data.as_ptr(), - u8, - data.len(), - self.loader_id + data.as_ptr() as u64, + data.len() as u64, + self.loader_id, )?, ref_to_len_in_vm, serialized_len_ptr, @@ -891,38 +972,35 @@ impl<'a> SyscallInvokeSigned<'a> for SyscallInvokeSignedRust<'a> { &self, program_id: &Pubkey, signers_seeds_addr: u64, - signers_seeds_len: usize, + signers_seeds_len: u64, memory_mapping: &MemoryMapping, ) -> Result, EbpfError> { let mut signers = Vec::new(); if signers_seeds_len > 0 { - let signers_seeds = translate_slice!( + let signers_seeds = translate_slice::<&[&[u8]]>( memory_mapping, AccessType::Load, signers_seeds_addr, - &[&[u8]], signers_seeds_len, - self.loader_id + self.loader_id, )?; for signer_seeds in signers_seeds.iter() { - let untranslated_seeds = translate_slice!( + let untranslated_seeds = translate_slice::<&[u8]>( memory_mapping, AccessType::Load, - signer_seeds.as_ptr(), - &[u8], - signer_seeds.len(), - self.loader_id + signer_seeds.as_ptr() as *const _ as u64, + signer_seeds.len() as u64, + self.loader_id, )?; let seeds = untranslated_seeds .iter() .map(|untranslated_seed| { - translate_slice!( + translate_slice::( memory_mapping, AccessType::Load, - untranslated_seed.as_ptr(), - u8, - untranslated_seed.len(), - self.loader_id + untranslated_seed.as_ptr() as *const _ as u64, + untranslated_seed.len() as u64, + self.loader_id, ) }) .collect::, EbpfError>>()?; @@ -945,8 +1023,9 @@ impl<'a> SyscallObject for SyscallInvokeSignedRust<'a> { signers_seeds_addr: u64, signers_seeds_len: u64, memory_mapping: &MemoryMapping, - ) -> Result> { - call( + result: &mut Result>, + ) { + *result = call( self, instruction_addr, account_infos_addr, @@ -954,7 +1033,7 @@ impl<'a> SyscallObject for SyscallInvokeSignedRust<'a> { signers_seeds_addr, signers_seeds_len, memory_mapping, - ) + ); } } @@ -1024,46 +1103,41 @@ impl<'a> SyscallInvokeSigned<'a> for SyscallInvokeSignedC<'a> { addr: u64, memory_mapping: &MemoryMapping, ) -> Result> { - let ix_c = translate_type!( + let ix_c = translate_type::( memory_mapping, AccessType::Load, addr, - SolInstruction, - self.loader_id + self.loader_id, )?; - let program_id = translate_type!( + let program_id = translate_type::( memory_mapping, AccessType::Load, ix_c.program_id_addr, - Pubkey, - self.loader_id + self.loader_id, )?; - let meta_cs = translate_slice!( + let meta_cs = translate_slice::( memory_mapping, AccessType::Load, ix_c.accounts_addr, - SolAccountMeta, - ix_c.accounts_len, - self.loader_id + ix_c.accounts_len as u64, + self.loader_id, )?; - let data = translate_slice!( + let data = translate_slice::( memory_mapping, AccessType::Load, ix_c.data_addr, - u8, - ix_c.data_len, - self.loader_id + ix_c.data_len as u64, + self.loader_id, )? .to_vec(); let accounts = meta_cs .iter() .map(|meta_c| { - let pubkey = translate_type!( + let pubkey = translate_type::( memory_mapping, AccessType::Load, meta_c.pubkey_addr, - Pubkey, - self.loader_id + self.loader_id, )?; Ok(AccountMeta { pubkey: *pubkey, @@ -1084,61 +1158,55 @@ impl<'a> SyscallInvokeSigned<'a> for SyscallInvokeSignedC<'a> { &self, message: &Message, account_infos_addr: u64, - account_infos_len: usize, + account_infos_len: u64, memory_mapping: &MemoryMapping, ) -> Result, EbpfError> { - let account_infos = translate_slice!( + let account_infos = translate_slice::( memory_mapping, AccessType::Load, account_infos_addr, - SolAccountInfo, account_infos_len, - self.loader_id + self.loader_id, )?; let mut accounts = Vec::with_capacity(message.account_keys.len()); let mut refs = Vec::with_capacity(message.account_keys.len()); 'root: for account_key in message.account_keys.iter() { for account_info in account_infos.iter() { - let key = translate_type!( + let key = translate_type::( memory_mapping, AccessType::Load, account_info.key_addr, - Pubkey, - self.loader_id + self.loader_id, )?; if account_key == key { - let lamports = translate_type_mut!( + let lamports = translate_type_mut::( memory_mapping, AccessType::Store, account_info.lamports_addr, - u64, - self.loader_id + self.loader_id, )?; - let owner = translate_type_mut!( + let owner = translate_type_mut::( memory_mapping, AccessType::Load, account_info.owner_addr, - Pubkey, - self.loader_id + self.loader_id, )?; - let data = translate_slice_mut!( + let data = translate_slice_mut::( memory_mapping, AccessType::Store, account_info.data_addr, - u8, account_info.data_len, - self.loader_id + self.loader_id, )?; let ref_to_len_in_vm = unsafe { &mut *(&account_info.data_len as *const u64 as u64 as *mut u64) }; let ref_of_len_in_input_buffer = unsafe { (account_info.data_addr as *mut u8).offset(-8) }; - let serialized_len_ptr = translate_type_mut!( + let serialized_len_ptr = translate_type_mut::( memory_mapping, AccessType::Store, - ref_of_len_in_input_buffer, - u64, - self.loader_id + ref_of_len_in_input_buffer as *const _ as u64, + self.loader_id, )?; accounts.push(Rc::new(RefCell::new(Account { @@ -1168,39 +1236,36 @@ impl<'a> SyscallInvokeSigned<'a> for SyscallInvokeSignedC<'a> { &self, program_id: &Pubkey, signers_seeds_addr: u64, - signers_seeds_len: usize, + signers_seeds_len: u64, memory_mapping: &MemoryMapping, ) -> Result, EbpfError> { if signers_seeds_len > 0 { - let signers_seeds = translate_slice!( + let signers_seeds = translate_slice::( memory_mapping, AccessType::Load, signers_seeds_addr, - SolSignerSeedC, signers_seeds_len, - self.loader_id + self.loader_id, )?; Ok(signers_seeds .iter() .map(|signer_seeds| { - let seeds = translate_slice!( + let seeds = translate_slice::( memory_mapping, AccessType::Store, signer_seeds.addr, - SolSignerSeedC, signer_seeds.len, - self.loader_id + self.loader_id, )?; let seeds_bytes = seeds .iter() .map(|seed| { - translate_slice!( + translate_slice::( memory_mapping, AccessType::Load, seed.addr, - u8, seed.len, - self.loader_id + self.loader_id, ) }) .collect::, EbpfError>>()?; @@ -1222,8 +1287,9 @@ impl<'a> SyscallObject for SyscallInvokeSignedC<'a> { signers_seeds_addr: u64, signers_seeds_len: u64, memory_mapping: &MemoryMapping, - ) -> Result> { - call( + result: &mut Result>, + ) { + *result = call( self, instruction_addr, account_infos_addr, @@ -1231,7 +1297,7 @@ impl<'a> SyscallObject for SyscallInvokeSignedC<'a> { signers_seeds_addr, signers_seeds_len, memory_mapping, - ) + ); } } @@ -1297,7 +1363,7 @@ fn call<'a>( let signers = syscall.translate_signers( caller_program_id, signers_seeds_addr, - signers_seeds_len as usize, + signers_seeds_len, memory_mapping, )?; verify_instruction(syscall, &instruction, &signers)?; @@ -1308,7 +1374,7 @@ fn call<'a>( let (accounts, account_refs) = syscall.translate_accounts( &message, account_infos_addr, - account_infos_len as usize, + account_infos_len, memory_mapping, )?; @@ -1393,7 +1459,7 @@ mod tests { let data = vec![0u8; LENGTH as usize]; let addr = data.as_ptr() as u64; let memory_mapping = MemoryMapping::new_from_regions(vec![MemoryRegion::new_from_slice( - &data, START, false, + &data, START, 0, false, )]); let cases = vec![ @@ -1415,8 +1481,8 @@ mod tests { for (ok, start, length, value) in cases { if ok { assert_eq!( - translate!( - memory_mapping, + translate( + &memory_mapping, AccessType::Load, start, length, @@ -1426,8 +1492,8 @@ mod tests { value ) } else { - assert!(translate!( - memory_mapping, + assert!(translate( + &memory_mapping, AccessType::Load, start, length, @@ -1447,16 +1513,12 @@ mod tests { host_addr: addr, vm_addr: 100, len: std::mem::size_of::() as u64, + vm_gap_shift: 63, is_writable: false, }]); - let translated_pubkey = translate_type!( - memory_mapping, - AccessType::Load, - 100, - Pubkey, - &bpf_loader::id() - ) - .unwrap(); + let translated_pubkey = + translate_type::(&memory_mapping, AccessType::Load, 100, &bpf_loader::id()) + .unwrap(); assert_eq!(pubkey, *translated_pubkey); // Instruction @@ -1470,23 +1532,18 @@ mod tests { host_addr: addr, vm_addr: 96, len: std::mem::size_of::() as u64, + vm_gap_shift: 63, is_writable: false, }]); - let translated_instruction = translate_type!( - memory_mapping, - AccessType::Load, - 96, - Instruction, - &bpf_loader::id() - ) - .unwrap(); + let translated_instruction = + translate_type::(&memory_mapping, AccessType::Load, 96, &bpf_loader::id()) + .unwrap(); assert_eq!(instruction, *translated_instruction); memory_mapping.resize_region::(0, 1).unwrap(); - assert!(translate_type!( - memory_mapping, + assert!(translate_type::( + &memory_mapping, AccessType::Load, 100, - Instruction, &bpf_loader::id() ) .is_err()); @@ -1503,15 +1560,15 @@ mod tests { host_addr: addr, vm_addr: 100, len: good_data.len() as u64, + vm_gap_shift: 63, is_writable: false, }]); - let translated_data = translate_slice!( - memory_mapping, + let translated_data = translate_slice::( + &memory_mapping, AccessType::Load, - data.as_ptr(), - u8, + data.as_ptr() as u64, 0, - &bpf_loader::id() + &bpf_loader::id(), ) .unwrap(); assert_eq!(data, translated_data); @@ -1524,36 +1581,34 @@ mod tests { host_addr: addr, vm_addr: 100, len: data.len() as u64, + vm_gap_shift: 63, is_writable: false, }]); - let translated_data = translate_slice!( - memory_mapping, + let translated_data = translate_slice::( + &memory_mapping, AccessType::Load, 100, - u8, - data.len(), - &bpf_loader::id() + data.len() as u64, + &bpf_loader::id(), ) .unwrap(); assert_eq!(data, translated_data); data[0] = 10; assert_eq!(data, translated_data); - assert!(translate_slice!( - memory_mapping, + assert!(translate_slice::( + &memory_mapping, AccessType::Load, - data.as_ptr(), - u8, + data.as_ptr() as u64, u64::MAX, &bpf_loader::id() ) .is_err()); - assert!(translate_slice!( - memory_mapping, + assert!(translate_slice::( + &memory_mapping, AccessType::Load, 100 - 1, - u8, - data.len(), + data.len() as u64, &bpf_loader::id() ) .is_err()); @@ -1565,15 +1620,15 @@ mod tests { host_addr: addr, vm_addr: 100, len: (data.len() * std::mem::size_of::()) as u64, + vm_gap_shift: 63, is_writable: false, }]); - let translated_data = translate_slice!( - memory_mapping, + let translated_data = translate_slice::( + &memory_mapping, AccessType::Load, 100, - Pubkey, - data.len(), - &bpf_loader::id() + data.len() as u64, + &bpf_loader::id(), ) .unwrap(); assert_eq!(data, translated_data); @@ -1589,6 +1644,7 @@ mod tests { host_addr: addr, vm_addr: 100, len: string.len() as u64, + vm_gap_shift: 63, is_writable: false, }]); assert_eq!( @@ -1612,7 +1668,18 @@ mod tests { #[should_panic(expected = "UserError(SyscallError(Abort))")] fn test_syscall_abort() { let memory_mapping = MemoryMapping::new_from_regions(vec![MemoryRegion::default()]); - syscall_abort(0, 0, 0, 0, 0, &memory_mapping).unwrap(); + let mut result: Result> = Ok(0); + SyscallAbort::call( + &mut SyscallAbort {}, + 0, + 0, + 0, + 0, + 0, + &memory_mapping, + &mut result, + ); + result.unwrap(); } #[test] @@ -1624,14 +1691,23 @@ mod tests { host_addr: addr, vm_addr: 100, len: string.len() as u64, + vm_gap_shift: 63, is_writable: false, }]); let mut syscall_panic = SyscallPanic { loader_id: &bpf_loader::id(), }; - syscall_panic - .call(100, string.len() as u64, 42, 84, 0, &memory_mapping) - .unwrap(); + let mut result: Result> = Ok(0); + syscall_panic.call( + 100, + string.len() as u64, + 42, + 84, + 0, + &memory_mapping, + &mut result, + ); + result.unwrap(); } #[test] @@ -1654,45 +1730,61 @@ mod tests { host_addr: addr, vm_addr: 100, len: string.len() as u64, + vm_gap_shift: 63, is_writable: false, }]); - syscall_sol_log - .call(100, string.len() as u64, 0, 0, 0, &memory_mapping) - .unwrap(); + let mut result: Result> = Ok(0); + syscall_sol_log.call( + 100, + string.len() as u64, + 0, + 0, + 0, + &memory_mapping, + &mut result, + ); + result.unwrap(); assert_eq!(log.borrow().len(), 1); assert_eq!(log.borrow()[0], "Program log: Gaggablaghblagh!"); - assert_access_violation!( - syscall_sol_log.call( - 101, // AccessViolation - string.len() as u64, - 0, - 0, - 0, - &memory_mapping - ), - 101, - string.len() as u64 + let mut result: Result> = Ok(0); + syscall_sol_log.call( + 101, // AccessViolation + string.len() as u64, + 0, + 0, + 0, + &memory_mapping, + &mut result, ); - assert_access_violation!( - syscall_sol_log.call( - 100, - string.len() as u64 * 2, // AccessViolation - 0, - 0, - 0, - &memory_mapping - ), + assert_access_violation!(result, 101, string.len() as u64); + let mut result: Result> = Ok(0); + syscall_sol_log.call( 100, - string.len() as u64 * 2 + string.len() as u64 * 2, // AccessViolation + 0, + 0, + 0, + &memory_mapping, + &mut result, + ); + assert_access_violation!(result, 100, string.len() as u64 * 2); + let mut result: Result> = Ok(0); + syscall_sol_log.call( + 100, + string.len() as u64, + 0, + 0, + 0, + &memory_mapping, + &mut result, ); - assert_eq!( Err(EbpfError::UserError(BPFError::SyscallError( SyscallError::InstructionError(InstructionError::ComputationalBudgetExceeded) ))), - syscall_sol_log.call(100, string.len() as u64, 0, 0, 0, &memory_mapping) + result ); } @@ -1712,9 +1804,9 @@ mod tests { }; let memory_mapping = MemoryMapping::new_from_regions(vec![]); - syscall_sol_log_u64 - .call(1, 2, 3, 4, 5, &memory_mapping) - .unwrap(); + let mut result: Result> = Ok(0); + syscall_sol_log_u64.call(1, 2, 3, 4, 5, &memory_mapping, &mut result); + result.unwrap(); assert_eq!(log.borrow().len(), 1); assert_eq!(log.borrow()[0], "Program log: 0x1, 0x2, 0x3, 0x4, 0x5"); @@ -1740,36 +1832,36 @@ mod tests { host_addr: addr, vm_addr: 100, len: 32, + vm_gap_shift: 63, is_writable: false, }]); - syscall_sol_pubkey - .call(100, 0, 0, 0, 0, &memory_mapping) - .unwrap(); + let mut result: Result> = Ok(0); + syscall_sol_pubkey.call(100, 0, 0, 0, 0, &memory_mapping, &mut result); + result.unwrap(); assert_eq!(log.borrow().len(), 1); assert_eq!( log.borrow()[0], "Program log: MoqiU1vryuCGQSxFKA1SZ316JdLEFFhoAu6cKUNk7dN" ); - - assert_access_violation!( - syscall_sol_pubkey.call( - 101, // AccessViolation - 32, - 0, - 0, - 0, - &memory_mapping, - ), - 101, - 32 + let mut result: Result> = Ok(0); + syscall_sol_pubkey.call( + 101, // AccessViolation + 32, + 0, + 0, + 0, + &memory_mapping, + &mut result, ); - + assert_access_violation!(result, 101, 32); + let mut result: Result> = Ok(0); + syscall_sol_pubkey.call(100, 32, 0, 0, 0, &memory_mapping, &mut result); assert_eq!( Err(EbpfError::UserError(BPFError::SyscallError( SyscallError::InstructionError(InstructionError::ComputationalBudgetExceeded) ))), - syscall_sol_pubkey.call(100, 32, 0, 0, 0, &memory_mapping) + result ); } @@ -1782,18 +1874,22 @@ mod tests { MemoryMapping::new_from_regions(vec![MemoryRegion::new_from_slice( &heap, MM_HEAP_START, + 0, true, )]); let mut syscall = SyscallAllocFree { aligned: true, allocator: BPFAllocator::new(heap, MM_HEAP_START), }; - assert_ne!(syscall.call(100, 0, 0, 0, 0, &memory_mapping).unwrap(), 0); - assert_eq!(syscall.call(100, 0, 0, 0, 0, &memory_mapping).unwrap(), 0); - assert_eq!( - syscall.call(u64::MAX, 0, 0, 0, 0, &memory_mapping).unwrap(), - 0 - ); + let mut result: Result> = Ok(0); + syscall.call(100, 0, 0, 0, 0, &memory_mapping, &mut result); + assert_ne!(result.unwrap(), 0); + let mut result: Result> = Ok(0); + syscall.call(100, 0, 0, 0, 0, &memory_mapping, &mut result); + assert_eq!(result.unwrap(), 0); + let mut result: Result> = Ok(0); + syscall.call(u64::MAX, 0, 0, 0, 0, &memory_mapping, &mut result); + assert_eq!(result.unwrap(), 0); } // many small unaligned allocs { @@ -1802,6 +1898,7 @@ mod tests { MemoryMapping::new_from_regions(vec![MemoryRegion::new_from_slice( &heap, MM_HEAP_START, + 0, true, )]); let mut syscall = SyscallAllocFree { @@ -1809,9 +1906,13 @@ mod tests { allocator: BPFAllocator::new(heap, MM_HEAP_START), }; for _ in 0..100 { - assert_ne!(syscall.call(1, 0, 0, 0, 0, &memory_mapping).unwrap(), 0); + let mut result: Result> = Ok(0); + syscall.call(1, 0, 0, 0, 0, &memory_mapping, &mut result); + assert_ne!(result.unwrap(), 0); } - assert_eq!(syscall.call(100, 0, 0, 0, 0, &memory_mapping).unwrap(), 0); + let mut result: Result> = Ok(0); + syscall.call(100, 0, 0, 0, 0, &memory_mapping, &mut result); + assert_eq!(result.unwrap(), 0); } // many small aligned allocs { @@ -1820,6 +1921,7 @@ mod tests { MemoryMapping::new_from_regions(vec![MemoryRegion::new_from_slice( &heap, MM_HEAP_START, + 0, true, )]); let mut syscall = SyscallAllocFree { @@ -1827,9 +1929,13 @@ mod tests { allocator: BPFAllocator::new(heap, MM_HEAP_START), }; for _ in 0..12 { - assert_ne!(syscall.call(1, 0, 0, 0, 0, &memory_mapping).unwrap(), 0); + let mut result: Result> = Ok(0); + syscall.call(1, 0, 0, 0, 0, &memory_mapping, &mut result); + assert_ne!(result.unwrap(), 0); } - assert_eq!(syscall.call(100, 0, 0, 0, 0, &memory_mapping).unwrap(), 0); + let mut result: Result> = Ok(0); + syscall.call(100, 0, 0, 0, 0, &memory_mapping, &mut result); + assert_eq!(result.unwrap(), 0); } // aligned allocs @@ -1839,15 +1945,24 @@ mod tests { MemoryMapping::new_from_regions(vec![MemoryRegion::new_from_slice( &heap, MM_HEAP_START, + 0, true, )]); let mut syscall = SyscallAllocFree { aligned: true, allocator: BPFAllocator::new(heap, MM_HEAP_START), }; - let address = syscall - .call(size_of::() as u64, 0, 0, 0, 0, &memory_mapping) - .unwrap(); + let mut result: Result> = Ok(0); + syscall.call( + size_of::() as u64, + 0, + 0, + 0, + 0, + &memory_mapping, + &mut result, + ); + let address = result.unwrap(); assert_ne!(address, 0); assert_eq!((address as *const u8).align_offset(align_of::()), 0); } @@ -1885,24 +2000,28 @@ mod tests { host_addr: bytes1.as_ptr() as *const _ as u64, vm_addr: 4096, len: bytes1.len() as u64, + vm_gap_shift: 63, is_writable: false, }, MemoryRegion { host_addr: bytes2.as_ptr() as *const _ as u64, vm_addr: 8192, len: bytes2.len() as u64, + vm_gap_shift: 63, is_writable: false, }, MemoryRegion { host_addr: bytes_to_hash.as_ptr() as *const _ as u64, vm_addr: 96, len: 32, + vm_gap_shift: 63, is_writable: false, }, MemoryRegion { host_addr: hash_result.as_ptr() as *const _ as u64, vm_addr: rw_va, len: HASH_BYTES as u64, + vm_gap_shift: 63, is_writable: true, }, ]); @@ -1917,55 +2036,52 @@ mod tests { loader_id: &bpf_loader_deprecated::id(), }; - syscall - .call(ro_va, ro_len, rw_va, 0, 0, &memory_mapping) - .unwrap(); + let mut result: Result> = Ok(0); + syscall.call(ro_va, ro_len, rw_va, 0, 0, &memory_mapping, &mut result); + result.unwrap(); let hash_local = hashv(&[bytes1.as_ref(), bytes2.as_ref()]).to_bytes(); assert_eq!(hash_result, hash_local); - - assert_access_violation!( - syscall.call( - ro_va - 1, // AccessViolation - ro_len, - rw_va, - 0, - 0, - &memory_mapping - ), - ro_va - 1, - ro_len + let mut result: Result> = Ok(0); + syscall.call( + ro_va - 1, // AccessViolation + ro_len, + rw_va, + 0, + 0, + &memory_mapping, + &mut result, ); - assert_access_violation!( - syscall.call( - ro_va, - ro_len + 1, // AccessViolation - rw_va, - 0, - 0, - &memory_mapping - ), + assert_access_violation!(result, ro_va - 1, ro_len); + let mut result: Result> = Ok(0); + syscall.call( ro_va, - ro_len + 1 + ro_len + 1, // AccessViolation + rw_va, + 0, + 0, + &memory_mapping, + &mut result, ); - assert_access_violation!( - syscall.call( - ro_va, - ro_len, - rw_va - 1, // AccessViolation - 0, - 0, - &memory_mapping - ), - rw_va - 1, - HASH_BYTES as u64 + assert_access_violation!(result, ro_va, ro_len + 1); + let mut result: Result> = Ok(0); + syscall.call( + ro_va, + ro_len, + rw_va - 1, // AccessViolation + 0, + 0, + &memory_mapping, + &mut result, ); + assert_access_violation!(result, rw_va - 1, HASH_BYTES as u64); + syscall.call(ro_va, ro_len, rw_va, 0, 0, &memory_mapping, &mut result); assert_eq!( Err(EbpfError::UserError(BPFError::SyscallError( SyscallError::InstructionError(InstructionError::ComputationalBudgetExceeded) ))), - syscall.call(ro_va, ro_len, rw_va, 0, 0, &memory_mapping) + result ); } } diff --git a/sdk/bpf/scripts/bpf-trace.py b/sdk/bpf/scripts/bpf-trace.py deleted file mode 100755 index e64ff01197..0000000000 --- a/sdk/bpf/scripts/bpf-trace.py +++ /dev/null @@ -1,138 +0,0 @@ -#!/usr/bin/env python - -# -# Prints a BPF program call trace with instruction counts for each call -# -# This script requires a dump file containing the instruction dump of the ELF -# and a trace file that contains the trace output of the BPF VM -# -# You can create the dump file by passing the --dump flag to `cargo build-bpf`, -# or directly: -# $ llvm-objdump -print-imm-hex --source --disassemble -# -# You can create the trace file by running the program and setting RUST_LOG: -# Set RUST_LOG -# $ export RUST_LOG=solana_rbpf=trace -# Capture output via `> trace.txt 2>&1` -# - -import re -import sys - -# regular expressions to search for -rxs_symbols = { - 'start' : re.compile(r'Disassembly of section \.text.*\n'), - 'symbol': re.compile(r'^(?!LBB)([<\S].+)\n'), -} -rxs_ixs = { - 'ixs': re.compile(r' *(\d+) *.*\n'), -} -rxs_call = { - 'entry': re.compile(r'BPF: +0 .+pc *(\d+) *.*\n'), - 'call' : re.compile(r'BPF: +(\d+) .+pc *(\d+) *call.*\n'), - 'exit' : re.compile(r'BPF: +(\d+) .+exit\n'), -} -rxs_called = { - 'pc': re.compile(r'BPF: +\d+ .+pc +(\d+).*\n'), -} - -# parse a line -def parse_line(rxs, line): - for key, rx in rxs.items(): - match = rx.search(line) - if match: - return key, match - return None, None - -# main -if __name__ == '__main__': - - if len(sys.argv) < 3: - print('Error: Must specify a dump and trace file') - sys.exit(' Usage: ' + sys.argv[0] + ' dump_file trace_file') - dumppath = sys.argv[1] - tracepath = sys.argv[2] - - # parse the dump file to create a map - # of instruction numbers to symbols - symbols = {} - with open(dumppath, 'r') as file_object: - line = file_object.readline() - while line: - key, match = parse_line(rxs_symbols, line) - if key == 'start': - line = file_object.readline() - while line: - key, match = parse_line(rxs_symbols, line) - if key == 'symbol': - symbol = match.group(1) - line = file_object.readline() - key, match = parse_line(rxs_ixs, line) - if key == 'ixs': - ixs = int(match.group(1)) - symbols[ixs] = symbol - line = file_object.readline() - line = file_object.readline() - if len(symbols) == 0: - sys.exit("Error: No instruction dump in: " + dumppath) - - # parse the trace file to build a call list - calls = [] # all the calls made - with open(tracepath, 'r') as file_object: - exits = [] # instruction counts at each call exit - call_nums = [] # used to match up exits to calls - frame = 1 - max_frame = 0 - num_calls = 0 - line = file_object.readline() - while line: - # print line - key, match = parse_line(rxs_call, line) - if key == 'call': - ixs_count = int(match.group(1)) - calling_pc = int(match.group(2)) - line = file_object.readline() - key, match = parse_line(rxs_called, line) - while key != 'pc': - line = file_object.readline() - key, match = parse_line(rxs_called, line) - called_pc = int(match.group(1)) - if calling_pc + 1 == called_pc: - calls.append((ixs_count, frame, 'Solana system call')) - exits.append(ixs_count) - num_calls += 1 - else: - calls.append((ixs_count, frame, symbols[called_pc])) - call_nums.append(num_calls) - exits.append(0) - num_calls += 1 - frame += 1 - max_frame = max(frame, max_frame) - else: - if key == 'entry': - pc = int(match.group(1)) - calls.append((0, 0, symbols[pc])) - call_nums.append(num_calls) - exits.append(0) - num_calls += 1 - elif key == 'exit': - ixs_count = int(match.group(1)) - num = call_nums.pop() - exits[num] = ixs_count - frame -= 1 - line = file_object.readline() - if len(calls) == 0: - sys.exit("Error: No valid trace in : " + tracepath) - - # print the call trace with instruction counts for each call - print "Max frame depth: ", max_frame - 1 - print "Call trace:" - print "Ins num (Ins count): Symbol called" - for call, exit in zip(calls, exits): - if exit == 0: - count = " No return" - else: - count = "%9d" % (exit - call[0]) - print("%9d (%s): %s %s" % (call[0], count, ' | ' * call[1], call[2])) - if frame != 0: - print "Error: Program did not exit gracefully"