forked from qmonnet/rbpf
-
Notifications
You must be signed in to change notification settings - Fork 175
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
2 changed files
with
258 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,257 @@ | ||
#![allow(clippy::arithmetic_side_effects)] | ||
#![cfg(all(feature = "jit", not(target_os = "windows"), target_arch = "x86_64"))] | ||
// Copyright 2020 Solana Maintainers <[email protected]> | ||
// | ||
// Licensed under the Apache License, Version 2.0 <http://www.apache.org/licenses/LICENSE-2.0> or | ||
// the MIT license <http://opensource.org/licenses/MIT>, at your option. This file may not be | ||
// copied, modified, or distributed except according to those terms. | ||
|
||
extern crate byteorder; | ||
extern crate libc; | ||
extern crate solana_rbpf; | ||
extern crate test_utils; | ||
extern crate thiserror; | ||
|
||
use rand::{rngs::SmallRng, RngCore, SeedableRng}; | ||
use solana_rbpf::{ | ||
assembler::assemble, | ||
ebpf, | ||
memory_region::MemoryRegion, | ||
program::{BuiltinFunction, BuiltinProgram, FunctionRegistry}, | ||
static_analysis::Analysis, | ||
verifier::RequisiteVerifier, | ||
vm::{Config, ContextObject, TestContextObject}, | ||
}; | ||
use std::sync::Arc; | ||
use test_utils::create_vm; | ||
|
||
macro_rules! test_interpreter_and_jit { | ||
(register, $function_registry:expr, $location:expr => $syscall_function:expr) => { | ||
$function_registry | ||
.register_function_hashed($location.as_bytes(), $syscall_function) | ||
.unwrap(); | ||
}; | ||
($executable:expr, $mem:tt, $context_object:expr $(,)?) => { | ||
let expected_instruction_count = $context_object.get_remaining(); | ||
#[allow(unused_mut)] | ||
let mut context_object = $context_object; | ||
$executable.verify::<RequisiteVerifier>().unwrap(); | ||
let ( | ||
instruction_count_interpreter, | ||
interpreter_final_pc, | ||
_tracer_interpreter, | ||
interpreter_result, | ||
) = { | ||
let mut mem = $mem; | ||
let mem_region = MemoryRegion::new_writable(&mut mem, ebpf::MM_INPUT_START); | ||
let mut context_object = context_object.clone(); | ||
create_vm!( | ||
vm, | ||
&$executable, | ||
&mut context_object, | ||
stack, | ||
heap, | ||
vec![mem_region], | ||
None | ||
); | ||
let (instruction_count_interpreter, result) = vm.execute_program(&$executable, true); | ||
( | ||
instruction_count_interpreter, | ||
vm.registers[11], | ||
vm.context_object_pointer.clone(), | ||
result.unwrap(), | ||
) | ||
}; | ||
#[cfg(all(not(windows), target_arch = "x86_64"))] | ||
{ | ||
#[allow(unused_mut)] | ||
$executable.jit_compile().unwrap(); | ||
let mut mem = $mem; | ||
let mem_region = MemoryRegion::new_writable(&mut mem, ebpf::MM_INPUT_START); | ||
create_vm!( | ||
vm, | ||
&$executable, | ||
&mut context_object, | ||
stack, | ||
heap, | ||
vec![mem_region], | ||
None | ||
); | ||
let (instruction_count_jit, result) = vm.execute_program(&$executable, false); | ||
let tracer_jit = &vm.context_object_pointer; | ||
if !TestContextObject::compare_trace_log(&_tracer_interpreter, tracer_jit) { | ||
let analysis = Analysis::from_executable(&$executable).unwrap(); | ||
let stdout = std::io::stdout(); | ||
analysis | ||
.disassemble_trace_log(&mut stdout.lock(), &_tracer_interpreter.trace_log) | ||
.unwrap(); | ||
analysis | ||
.disassemble_trace_log(&mut stdout.lock(), &tracer_jit.trace_log) | ||
.unwrap(); | ||
panic!(); | ||
} | ||
assert_eq!( | ||
result.unwrap(), | ||
interpreter_result, | ||
"Unexpected result for JIT" | ||
); | ||
assert_eq!( | ||
instruction_count_interpreter, instruction_count_jit, | ||
"Interpreter and JIT instruction meter diverged", | ||
); | ||
assert_eq!( | ||
interpreter_final_pc, vm.registers[11], | ||
"Interpreter and JIT instruction final PC diverged", | ||
); | ||
} | ||
if $executable.get_config().enable_instruction_meter { | ||
assert_eq!( | ||
instruction_count_interpreter, expected_instruction_count, | ||
"Instruction meter did not consume expected amount" | ||
); | ||
} | ||
}; | ||
} | ||
|
||
macro_rules! test_interpreter_and_jit_asm { | ||
($source:expr, $config:expr, $mem:tt, ($($location:expr => $syscall_function:expr),* $(,)?), $context_object:expr $(,)?) => { | ||
#[allow(unused_mut)] | ||
{ | ||
let mut config = $config; | ||
config.enable_instruction_tracing = true; | ||
let mut function_registry = FunctionRegistry::<BuiltinFunction<TestContextObject>>::default(); | ||
$(test_interpreter_and_jit!(register, function_registry, $location => $syscall_function);)* | ||
let loader = Arc::new(BuiltinProgram::new_loader(config, function_registry)); | ||
let mut executable = assemble($source, loader).unwrap(); | ||
test_interpreter_and_jit!(executable, $mem, $context_object); | ||
} | ||
}; | ||
($source:expr, $mem:tt, ($($location:expr => $syscall_function:expr),* $(,)?), $context_object:expr $(,)?) => { | ||
#[allow(unused_mut)] | ||
{ | ||
test_interpreter_and_jit_asm!($source, Config::default(), $mem, ($($location => $syscall_function),*), $context_object); | ||
} | ||
}; | ||
} | ||
|
||
// BPF_ALU : Arithmetic and Logic | ||
#[test] | ||
fn fuzz_alu() { | ||
let seed = 0xC2DB2F8F282284A0; | ||
let mut prng = SmallRng::seed_from_u64(seed); | ||
|
||
for src in 0..10 { | ||
for dst in 0..10 { | ||
for _ in 0..10 { | ||
test_ins(format!("mov64 r{src}, r{dst}"), &mut prng); | ||
test_ins(format!("add64 r{src}, r{dst}"), &mut prng); | ||
test_ins(format!("sub64 r{src}, r{dst}"), &mut prng); | ||
test_ins(format!("xor64 r{src}, r{dst}"), &mut prng); | ||
test_ins(format!("and64 r{src}, r{dst}"), &mut prng); | ||
test_ins(format!("lmul64 r{src}, r{dst}"), &mut prng); | ||
test_ins(format!("uhmul64 r{src}, r{dst}"), &mut prng); | ||
test_ins(format!("shmul64 r{src}, r{dst}"), &mut prng); | ||
test_ins(format!("udiv64 r{src}, r{dst}"), &mut prng); | ||
test_ins(format!("urem64 r{src}, r{dst}"), &mut prng); | ||
test_ins(format!("sdiv64 r{src}, r{dst}"), &mut prng); | ||
|
||
test_ins(format!("lsh64 r{src}, r{dst}"), &mut prng); | ||
test_ins(format!("rsh64 r{src}, r{dst}"), &mut prng); | ||
test_ins(format!("arsh64 r{src}, r{dst}"), &mut prng); | ||
|
||
test_ins(format!("mov32 r{src}, r{dst}"), &mut prng); | ||
test_ins(format!("add32 r{src}, r{dst}"), &mut prng); | ||
test_ins(format!("sub32 r{src}, r{dst}"), &mut prng); | ||
test_ins(format!("xor32 r{src}, r{dst}"), &mut prng); | ||
test_ins(format!("and32 r{src}, r{dst}"), &mut prng); | ||
test_ins(format!("lmul32 r{src}, r{dst}"), &mut prng); | ||
// test_ins(format!("uhmul32 r{src}, r{dst}"), &mut prng); | ||
// test_ins(format!("shmul32 r{src}, r{dst}"), &mut prng); | ||
test_ins(format!("udiv32 r{src}, r{dst}"), &mut prng); | ||
test_ins(format!("urem32 r{src}, r{dst}"), &mut prng); | ||
test_ins(format!("sdiv32 r{src}, r{dst}"), &mut prng); | ||
|
||
test_ins(format!("lsh32 r{src}, r{dst}"), &mut prng); | ||
test_ins(format!("rsh32 r{src}, r{dst}"), &mut prng); | ||
test_ins(format!("arsh32 r{src}, r{dst}"), &mut prng); | ||
} | ||
} | ||
|
||
for _ in 0..10 { | ||
let mut imm = prng.next_u32() as i32; | ||
|
||
test_ins(format!("mov64 r{src}, {imm}"), &mut prng); | ||
test_ins(format!("add64 r{src}, {imm}"), &mut prng); | ||
test_ins(format!("sub64 r{src}, {imm}"), &mut prng); | ||
test_ins(format!("xor64 r{src}, {imm}"), &mut prng); | ||
test_ins(format!("and64 r{src}, {imm}"), &mut prng); | ||
test_ins(format!("lmul64 r{src}, {imm}"), &mut prng); | ||
test_ins(format!("uhmul64 r{src}, {imm}"), &mut prng); | ||
test_ins(format!("shmul64 r{src}, {imm}"), &mut prng); | ||
test_ins(format!("udiv64 r{src}, {imm}"), &mut prng); | ||
test_ins(format!("urem64 r{src}, {imm}"), &mut prng); | ||
test_ins(format!("sdiv64 r{src}, {imm}"), &mut prng); | ||
test_ins(format!("srem64 r{src}, {imm}"), &mut prng); | ||
|
||
test_ins(format!("mov32 r{src}, {imm}"), &mut prng); | ||
test_ins(format!("add32 r{src}, {imm}"), &mut prng); | ||
test_ins(format!("sub32 r{src}, {imm}"), &mut prng); | ||
test_ins(format!("xor32 r{src}, {imm}"), &mut prng); | ||
test_ins(format!("and32 r{src}, {imm}"), &mut prng); | ||
test_ins(format!("lmul32 r{src}, {imm}"), &mut prng); | ||
test_ins(format!("udiv32 r{src}, {imm}"), &mut prng); | ||
test_ins(format!("urem32 r{src}, {imm}"), &mut prng); | ||
test_ins(format!("sdiv32 r{src}, {imm}"), &mut prng); | ||
test_ins(format!("srem32 r{src}, {imm}"), &mut prng); | ||
|
||
imm &= 63; | ||
|
||
test_ins(format!("lsh64 r{src}, {imm}"), &mut prng); | ||
test_ins(format!("rsh64 r{src}, {imm}"), &mut prng); | ||
test_ins(format!("arsh64 r{src}, {imm}"), &mut prng); | ||
test_ins(format!("hor64 r{src}, {imm}"), &mut prng); | ||
|
||
imm &= 31; | ||
|
||
test_ins(format!("lsh32 r{src}, {imm}"), &mut prng); | ||
test_ins(format!("rsh32 r{src}, {imm}"), &mut prng); | ||
test_ins(format!("arsh32 r{src}, {imm}"), &mut prng); | ||
|
||
test_ins(format!("be64 r{src}"), &mut prng); | ||
test_ins(format!("be32 r{src}"), &mut prng); | ||
test_ins(format!("be16 r{src}"), &mut prng); | ||
} | ||
} | ||
} | ||
|
||
fn test_ins(ins: String, prng: &mut SmallRng) { | ||
let mut input = [0u8; 80]; | ||
|
||
prng.fill_bytes(&mut input); | ||
|
||
let asm = format!( | ||
" | ||
ldxdw r9, [r1+72] | ||
ldxdw r8, [r1+64] | ||
ldxdw r7, [r1+56] | ||
ldxdw r6, [r1+48] | ||
ldxdw r5, [r1+40] | ||
ldxdw r4, [r1+32] | ||
ldxdw r3, [r1+24] | ||
ldxdw r2, [r1+16] | ||
ldxdw r0, [r1+0] | ||
ldxdw r1, [r1+8] | ||
{ins} | ||
xor64 r0, r1 | ||
xor64 r0, r2 | ||
xor64 r0, r3 | ||
xor64 r0, r4 | ||
xor64 r0, r5 | ||
xor64 r0, r6 | ||
xor64 r0, r7 | ||
xor64 r0, r8 | ||
xor64 r0, r9 | ||
exit" | ||
); | ||
test_interpreter_and_jit_asm!(asm.as_str(), input, (), TestContextObject::new(21)); | ||
} |