@@ -37,7 +37,6 @@ CC_FLAGS := \
 | 
			
		||||
LLC_FLAGS := \
 | 
			
		||||
  -march=bpf \
 | 
			
		||||
  -filetype=obj \
 | 
			
		||||
  -function-sections \
 | 
			
		||||
 | 
			
		||||
OBJ_DUMP_FLAGS := \
 | 
			
		||||
  -color \
 | 
			
		||||
 
 | 
			
		||||
@@ -34,36 +34,15 @@ typedef unsigned long int uint64_t;
 | 
			
		||||
typedef enum { false = 0, true } bool;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Built-in helper functions
 | 
			
		||||
 * @{
 | 
			
		||||
 * The BPF VM makes a limited number of helper functions available to BPF
 | 
			
		||||
 * programs.  They are resolved at run-time and identified by a function index.
 | 
			
		||||
 * Calling any of these functions results in `Call` instruction out of the
 | 
			
		||||
 * user's BPF program.
 | 
			
		||||
 *
 | 
			
		||||
 * The helper functions all follow the same signature:
 | 
			
		||||
 *
 | 
			
		||||
 * int helper(uint64_t, uint64_t, uint64_t, uint64_t, uint64_t)
 | 
			
		||||
 *
 | 
			
		||||
 * The meaning of each argument and return value is dependent on the particular
 | 
			
		||||
 * helper function being called.
 | 
			
		||||
 * Helper function that prints a string to stdout
 | 
			
		||||
 */
 | 
			
		||||
extern void sol_log(const char*);
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Helper function that prints to stdout
 | 
			
		||||
 *
 | 
			
		||||
 * Prints the hexadecimal representation of each parameter
 | 
			
		||||
 * Helper function that prints a 64 bit values represented in hexadecimal
 | 
			
		||||
 * to stdout
 | 
			
		||||
 */
 | 
			
		||||
#define BPF_TRACE_PRINTK_IDX 6
 | 
			
		||||
static int (*sol_print)(
 | 
			
		||||
  uint64_t,
 | 
			
		||||
  uint64_t,
 | 
			
		||||
  uint64_t,
 | 
			
		||||
  uint64_t,
 | 
			
		||||
  uint64_t
 | 
			
		||||
) = (void *)BPF_TRACE_PRINTK_IDX;
 | 
			
		||||
 | 
			
		||||
/**@}*/
 | 
			
		||||
extern void sol_log_64(uint64_t, uint64_t, uint64_t, uint64_t, uint64_t);
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Prefix for all BPF functions
 | 
			
		||||
@@ -147,7 +126,7 @@ SOL_FN_PREFIX int sol_memcmp(const void *s1, const void *s2, int n) {
 | 
			
		||||
 */
 | 
			
		||||
#define sol_panic() _sol_panic(__LINE__)
 | 
			
		||||
SOL_FN_PREFIX void _sol_panic(uint64_t line) {
 | 
			
		||||
  sol_print(0xFF, 0xFF, 0xFF, 0xFF, line);
 | 
			
		||||
  sol_log_64(0xFF, 0xFF, 0xFF, 0xFF, line);
 | 
			
		||||
  uint8_t *pv = (uint8_t *)1;
 | 
			
		||||
  *pv = 1;
 | 
			
		||||
}
 | 
			
		||||
@@ -241,9 +220,9 @@ SOL_FN_PREFIX bool sol_deserialize(
 | 
			
		||||
 *
 | 
			
		||||
 * @param key The public key to print
 | 
			
		||||
 */
 | 
			
		||||
SOL_FN_PREFIX void sol_print_key(const SolPubkey *key) {
 | 
			
		||||
SOL_FN_PREFIX void sol_log_key(const SolPubkey *key) {
 | 
			
		||||
  for (int j = 0; j < sizeof(*key); j++) {
 | 
			
		||||
    sol_print(0, 0, 0, j, key->x[j]);
 | 
			
		||||
    sol_log_64(0, 0, 0, j, key->x[j]);
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -252,9 +231,9 @@ SOL_FN_PREFIX void sol_print_key(const SolPubkey *key) {
 | 
			
		||||
 *
 | 
			
		||||
 * @param array The array to print
 | 
			
		||||
 */
 | 
			
		||||
SOL_FN_PREFIX void sol_print_array(const uint8_t *array, int len) {
 | 
			
		||||
SOL_FN_PREFIX void sol_log_array(const uint8_t *array, int len) {
 | 
			
		||||
  for (int j = 0; j < len; j++) {
 | 
			
		||||
    sol_print(0, 0, 0, j, array[j]);
 | 
			
		||||
    sol_log_64(0, 0, 0, j, array[j]);
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -266,20 +245,20 @@ SOL_FN_PREFIX void sol_print_array(const uint8_t *array, int len) {
 | 
			
		||||
 * @param data A pointer to the instruction data to print
 | 
			
		||||
 * @param data_len The length in bytes of the instruction data
 | 
			
		||||
 */
 | 
			
		||||
SOL_FN_PREFIX void sol_print_params(
 | 
			
		||||
SOL_FN_PREFIX void sol_log_params(
 | 
			
		||||
  uint64_t num_ka,
 | 
			
		||||
  const SolKeyedAccounts *ka,
 | 
			
		||||
  const uint8_t *data,
 | 
			
		||||
  uint64_t data_len
 | 
			
		||||
) {
 | 
			
		||||
  sol_print(0, 0, 0, 0, num_ka);
 | 
			
		||||
  sol_log_64(0, 0, 0, 0, num_ka);
 | 
			
		||||
  for (int i = 0; i < num_ka; i++) {
 | 
			
		||||
    sol_print_key(ka[i].key);
 | 
			
		||||
    sol_print(0, 0, 0, 0, *ka[i].tokens);
 | 
			
		||||
    sol_print_array(ka[i].userdata, ka[i].userdata_len);
 | 
			
		||||
    sol_print_key(ka[i].program_id);
 | 
			
		||||
    sol_log_key(ka[i].key);
 | 
			
		||||
    sol_log_64(0, 0, 0, 0, *ka[i].tokens);
 | 
			
		||||
    sol_log_array(ka[i].userdata, ka[i].userdata_len);
 | 
			
		||||
    sol_log_key(ka[i].program_id);
 | 
			
		||||
  }
 | 
			
		||||
  sol_print_array(data, data_len);
 | 
			
		||||
  sol_log_array(data, data_len);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**@}*/
 | 
			
		||||
@@ -299,7 +278,7 @@ SOL_FN_PREFIX void sol_print_params(
 | 
			
		||||
 *   if (!sol_deserialize(buf, ka, SOL_ARRAY_SIZE(ka), NULL, &data, &data_len)) {
 | 
			
		||||
 *     return false;
 | 
			
		||||
 *   }
 | 
			
		||||
 *   print_params(1, ka, data, data_len);
 | 
			
		||||
 *   sol_log_params(1, ka, data, data_len);
 | 
			
		||||
 *   return true;
 | 
			
		||||
 * }
 | 
			
		||||
 */
 | 
			
		||||
 
 | 
			
		||||
@@ -24,9 +24,9 @@ extern bool entrypoint(const uint8_t *input) {
 | 
			
		||||
  if (*ka[0].tokens >= tokens) {
 | 
			
		||||
    *ka[0].tokens -= tokens;
 | 
			
		||||
    *ka[2].tokens += tokens;
 | 
			
		||||
    // sol_print(0, 0, *ka[0].tokens, *ka[2].tokens, tokens);
 | 
			
		||||
    // sol_log_64(0, 0, *ka[0].tokens, *ka[2].tokens, tokens);
 | 
			
		||||
  } else {
 | 
			
		||||
    // sol_print(0, 0, 0xFF, *ka[0].tokens, tokens);
 | 
			
		||||
    // sol_log_64(0, 0, 0xFF, *ka[0].tokens, tokens);
 | 
			
		||||
  }
 | 
			
		||||
  return true;
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -16,10 +16,12 @@ extern bool entrypoint(const uint8_t *input) {
 | 
			
		||||
  const uint8_t *data;
 | 
			
		||||
  uint64_t data_len;
 | 
			
		||||
  
 | 
			
		||||
  sol_log("noop");
 | 
			
		||||
 | 
			
		||||
  if (!sol_deserialize(input, ka, NUM_KA, NULL, &data, &data_len)) {
 | 
			
		||||
    return false;
 | 
			
		||||
  }
 | 
			
		||||
  sol_print_params(NUM_KA, ka, data, data_len);
 | 
			
		||||
  sol_log_params(NUM_KA, ka, data, data_len);
 | 
			
		||||
 | 
			
		||||
  sol_assert(sizeof(int8_t) == 1);
 | 
			
		||||
  sol_assert(sizeof(uint8_t) == 1);
 | 
			
		||||
 
 | 
			
		||||
@@ -13,7 +13,7 @@ elf = "0.0.10"
 | 
			
		||||
env_logger = "0.5.12"
 | 
			
		||||
libc = "0.2.43"
 | 
			
		||||
log = "0.4.2"
 | 
			
		||||
solana_rbpf = "0.1.2"
 | 
			
		||||
solana_rbpf = "0.1.3"
 | 
			
		||||
serde = "1.0.27"
 | 
			
		||||
serde_derive = "1.0.27"
 | 
			
		||||
solana-sdk = { path = "../../../sdk", version = "0.10.1" }
 | 
			
		||||
 
 | 
			
		||||
@@ -5,20 +5,24 @@ extern crate byteorder;
 | 
			
		||||
extern crate env_logger;
 | 
			
		||||
#[macro_use]
 | 
			
		||||
extern crate log;
 | 
			
		||||
extern crate libc;
 | 
			
		||||
extern crate solana_rbpf;
 | 
			
		||||
extern crate solana_sdk;
 | 
			
		||||
 | 
			
		||||
use bincode::deserialize;
 | 
			
		||||
use byteorder::{ByteOrder, LittleEndian, WriteBytesExt};
 | 
			
		||||
use solana_rbpf::{helpers, EbpfVmRaw};
 | 
			
		||||
use libc::c_char;
 | 
			
		||||
use solana_rbpf::EbpfVmRaw;
 | 
			
		||||
use solana_sdk::account::KeyedAccount;
 | 
			
		||||
use solana_sdk::loader_instruction::LoaderInstruction;
 | 
			
		||||
use solana_sdk::pubkey::Pubkey;
 | 
			
		||||
use std::ffi::CStr;
 | 
			
		||||
use std::io::prelude::*;
 | 
			
		||||
use std::io::Error;
 | 
			
		||||
use std::io::{Error, ErrorKind};
 | 
			
		||||
use std::mem;
 | 
			
		||||
use std::sync::{Once, ONCE_INIT};
 | 
			
		||||
 | 
			
		||||
// TODO use rbpf's disassemble
 | 
			
		||||
#[allow(dead_code)]
 | 
			
		||||
fn dump_program(key: &Pubkey, prog: &[u8]) {
 | 
			
		||||
    let mut eight_bytes: Vec<u8> = Vec::new();
 | 
			
		||||
@@ -33,32 +37,64 @@ fn dump_program(key: &Pubkey, prog: &[u8]) {
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
pub fn helper_printf(arg1: u64, arg2: u64, arg3: u64, arg4: u64, arg5: u64) -> u64 {
 | 
			
		||||
#[allow(unused_variables)]
 | 
			
		||||
pub fn helper_sol_log_verify(
 | 
			
		||||
    addr: u64,
 | 
			
		||||
    unused2: u64,
 | 
			
		||||
    unused3: u64,
 | 
			
		||||
    unused4: u64,
 | 
			
		||||
    unused5: u64,
 | 
			
		||||
    ro_regions: &[&[u8]],
 | 
			
		||||
    unused7: &[&[u8]],
 | 
			
		||||
) -> Result<(()), Error> {
 | 
			
		||||
    for region in ro_regions.iter() {
 | 
			
		||||
        if region.as_ptr() as u64 <= addr
 | 
			
		||||
            && addr as u64 <= region.as_ptr() as u64 + region.len() as u64
 | 
			
		||||
        {
 | 
			
		||||
            let c_buf: *const c_char = addr as *const c_char;
 | 
			
		||||
            let max_size = (region.as_ptr() as u64 + region.len() as u64) - addr;
 | 
			
		||||
            unsafe {
 | 
			
		||||
                for i in 0..max_size {
 | 
			
		||||
                    if std::ptr::read(c_buf.offset(i as isize)) == 0 {
 | 
			
		||||
                        return Ok(());
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
            return Err(Error::new(ErrorKind::Other, "Error, Unterminated string"));
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    Err(Error::new(
 | 
			
		||||
        ErrorKind::Other,
 | 
			
		||||
        "Error: Load segfault, bad string pointer",
 | 
			
		||||
    ))
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[allow(unused_variables)]
 | 
			
		||||
pub fn helper_sol_log(addr: u64, unused2: u64, unused3: u64, unused4: u64, unused5: u64) -> u64 {
 | 
			
		||||
    let c_buf: *const c_char = addr as *const c_char;
 | 
			
		||||
    let c_str: &CStr = unsafe { CStr::from_ptr(c_buf) };
 | 
			
		||||
    match c_str.to_str() {
 | 
			
		||||
        Ok(slice) => info!("sol_log: {:?}", slice),
 | 
			
		||||
        Err(e) => warn!("Error: Cannot print invalid string"),
 | 
			
		||||
    };
 | 
			
		||||
    0
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
pub fn helper_sol_log_u64(arg1: u64, arg2: u64, arg3: u64, arg4: u64, arg5: u64) -> u64 {
 | 
			
		||||
    info!(
 | 
			
		||||
        "bpf_trace_printf: {:#x}, {:#x}, {:#x}, {:#x}, {:#x}",
 | 
			
		||||
        "sol_log_u64: {:#x}, {:#x}, {:#x}, {:#x}, {:#x}",
 | 
			
		||||
        arg1, arg2, arg3, arg4, arg5
 | 
			
		||||
    );
 | 
			
		||||
    let size_arg = |x| {
 | 
			
		||||
        if x == 0 {
 | 
			
		||||
            1
 | 
			
		||||
        } else {
 | 
			
		||||
            (x as f64).log(16.0).floor() as u64 + 1
 | 
			
		||||
        }
 | 
			
		||||
    };
 | 
			
		||||
    "bpf_trace_printf: 0x, 0x, 0x, 0x, 0x\n".len() as u64
 | 
			
		||||
        + size_arg(arg1)
 | 
			
		||||
        + size_arg(arg2)
 | 
			
		||||
        + size_arg(arg3)
 | 
			
		||||
        + size_arg(arg4)
 | 
			
		||||
        + size_arg(arg5)
 | 
			
		||||
    0
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
fn create_vm(prog: &[u8]) -> Result<EbpfVmRaw, Error> {
 | 
			
		||||
    let mut vm = EbpfVmRaw::new(None)?;
 | 
			
		||||
    vm.set_verifier(bpf_verifier::check)?;
 | 
			
		||||
    vm.set_max_instruction_count(36000)?; // 36000 is a wag, need to tune
 | 
			
		||||
    vm.set_program(&prog)?;
 | 
			
		||||
    vm.register_helper(helpers::BPF_TRACE_PRINTK_IDX, helper_printf)?;
 | 
			
		||||
    vm.set_elf(&prog)?;
 | 
			
		||||
    vm.register_helper_ex("sol_log", Some(helper_sol_log_verify), helper_sol_log)?;
 | 
			
		||||
    vm.register_helper_ex("sol_log_64", None, helper_sol_log_u64)?;
 | 
			
		||||
    Ok(vm)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -163,6 +199,8 @@ pub extern "C" fn process(keyed_accounts: &mut [KeyedAccount], tx_data: &[u8]) -
 | 
			
		||||
#[cfg(test)]
 | 
			
		||||
mod tests {
 | 
			
		||||
    use super::*;
 | 
			
		||||
    use solana_rbpf::helpers;
 | 
			
		||||
 | 
			
		||||
    #[test]
 | 
			
		||||
    #[should_panic(expected = "Error: Execution exceeded maximum number of instructions")]
 | 
			
		||||
    fn test_non_terminating_program() {
 | 
			
		||||
@@ -180,7 +218,13 @@ mod tests {
 | 
			
		||||
            0x95, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // exit
 | 
			
		||||
        ];
 | 
			
		||||
        let input = &mut [0x00];
 | 
			
		||||
        let mut vm = create_vm(prog).unwrap();
 | 
			
		||||
 | 
			
		||||
        let mut vm = EbpfVmRaw::new(None).unwrap();
 | 
			
		||||
        vm.set_verifier(bpf_verifier::check).unwrap();
 | 
			
		||||
        vm.set_max_instruction_count(36000).unwrap(); // 36000 is a wag, need to tune
 | 
			
		||||
        vm.set_program(prog).unwrap();
 | 
			
		||||
        vm.register_helper(helpers::BPF_TRACE_PRINTK_IDX, helpers::bpf_trace_printf)
 | 
			
		||||
            .unwrap();
 | 
			
		||||
        vm.execute_program(input).unwrap();
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -1,5 +1,6 @@
 | 
			
		||||
extern crate bincode;
 | 
			
		||||
extern crate elf;
 | 
			
		||||
extern crate serde_derive;
 | 
			
		||||
extern crate solana;
 | 
			
		||||
extern crate solana_sdk;
 | 
			
		||||
 | 
			
		||||
@@ -13,13 +14,15 @@ use solana::mint::Mint;
 | 
			
		||||
use solana::native_loader;
 | 
			
		||||
use solana::signature::{Keypair, KeypairUtil};
 | 
			
		||||
use solana::system_transaction::SystemTransaction;
 | 
			
		||||
#[cfg(feature = "bpf_c")]
 | 
			
		||||
use solana::tictactoe_program::Command;
 | 
			
		||||
use solana::transaction::Transaction;
 | 
			
		||||
use solana_sdk::pubkey::Pubkey;
 | 
			
		||||
#[cfg(feature = "bpf_c")]
 | 
			
		||||
use std::env;
 | 
			
		||||
#[cfg(feature = "bpf_c")]
 | 
			
		||||
use std::fs::File;
 | 
			
		||||
#[cfg(feature = "bpf_c")]
 | 
			
		||||
use std::io::Read;
 | 
			
		||||
#[cfg(feature = "bpf_c")]
 | 
			
		||||
use std::path::PathBuf;
 | 
			
		||||
 | 
			
		||||
/// BPF program file extension
 | 
			
		||||
@@ -119,7 +122,7 @@ struct Program {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl Program {
 | 
			
		||||
    pub fn new(loader: &Loader, userdata: Vec<u8>) -> Self {
 | 
			
		||||
    pub fn new(loader: &Loader, userdata: &Vec<u8>) -> Self {
 | 
			
		||||
        let program = Keypair::new();
 | 
			
		||||
 | 
			
		||||
        // allocate, populate, finalize and spawn program
 | 
			
		||||
@@ -183,7 +186,7 @@ fn test_program_native_noop() {
 | 
			
		||||
    let loader = Loader::new_native();
 | 
			
		||||
    let name = String::from("noop");
 | 
			
		||||
    let userdata = name.as_bytes().to_vec();
 | 
			
		||||
    let program = Program::new(&loader, userdata);
 | 
			
		||||
    let program = Program::new(&loader, &userdata);
 | 
			
		||||
 | 
			
		||||
    // Call user program
 | 
			
		||||
    let tx = Transaction::new(
 | 
			
		||||
@@ -213,7 +216,7 @@ fn test_program_lua_move_funds() {
 | 
			
		||||
            accounts[2].tokens = accounts[2].tokens + tokens
 | 
			
		||||
        "#.as_bytes()
 | 
			
		||||
    .to_vec();
 | 
			
		||||
    let program = Program::new(&loader, userdata);
 | 
			
		||||
    let program = Program::new(&loader, &userdata);
 | 
			
		||||
    let from = Keypair::new();
 | 
			
		||||
    let to = Keypair::new().pubkey();
 | 
			
		||||
 | 
			
		||||
@@ -272,16 +275,12 @@ fn test_program_lua_move_funds() {
 | 
			
		||||
fn test_program_builtin_bpf_noop() {
 | 
			
		||||
    logger::setup();
 | 
			
		||||
 | 
			
		||||
    let mut file = File::open(create_bpf_path("noop")).expect("file open failed");
 | 
			
		||||
    let mut elf = Vec::new();
 | 
			
		||||
    file.read_to_end(&mut elf).unwrap();
 | 
			
		||||
 | 
			
		||||
    let loader = Loader::new_bpf();
 | 
			
		||||
    let program = Program::new(
 | 
			
		||||
        &loader,
 | 
			
		||||
        elf::File::open_path(&create_bpf_path("noop"))
 | 
			
		||||
            .unwrap()
 | 
			
		||||
            .get_section(PLATFORM_SECTION_C)
 | 
			
		||||
            .unwrap()
 | 
			
		||||
            .data
 | 
			
		||||
            .clone(),
 | 
			
		||||
    );
 | 
			
		||||
    let program = Program::new(&loader, &elf);
 | 
			
		||||
 | 
			
		||||
    // Call user program
 | 
			
		||||
    let tx = Transaction::new(
 | 
			
		||||
@@ -304,16 +303,12 @@ fn test_program_builtin_bpf_noop() {
 | 
			
		||||
fn test_program_bpf_noop_c() {
 | 
			
		||||
    logger::setup();
 | 
			
		||||
 | 
			
		||||
    let mut file = File::open(create_bpf_path("noop")).expect("file open failed");
 | 
			
		||||
    let mut elf = Vec::new();
 | 
			
		||||
    file.read_to_end(&mut elf).unwrap();
 | 
			
		||||
 | 
			
		||||
    let loader = Loader::new_dynamic("solana_bpf_loader");
 | 
			
		||||
    let program = Program::new(
 | 
			
		||||
        &loader,
 | 
			
		||||
        elf::File::open_path(&create_bpf_path("noop"))
 | 
			
		||||
            .unwrap()
 | 
			
		||||
            .get_section(PLATFORM_SECTION_C)
 | 
			
		||||
            .unwrap()
 | 
			
		||||
            .data
 | 
			
		||||
            .clone(),
 | 
			
		||||
    );
 | 
			
		||||
    let program = Program::new(&loader, &elf);
 | 
			
		||||
 | 
			
		||||
    // Call user program
 | 
			
		||||
    let tx = Transaction::new(
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user