osprey 0.4.4

Gluon bindings for Falcon
use falcon;
use falcon::loader::Loader;
use gluon::vm::api::{Userdata, VmType};
use gluon::vm::thread::{Traverseable};
use gluon;
use std::path::Path;
use std::sync::Arc;

use architecture;
use il;
use memory;

falcon_type_wrapper!(Arc<falcon::loader::Elf>, LoaderElf);

fn elf_architecture(elf: &LoaderElf) -> architecture::ArchitectureArchitecture {
    architecture::ArchitectureArchitecture {
        x: Arc::new(elf.x.architecture().box_clone())
    }
}

fn elf_base_address(elf: &LoaderElf) -> u64 {
    elf.x.base_address()
}

fn elf_function_entries(elf: &LoaderElf) -> Vec<LoaderFunctionEntry> {
    elf.x
        .function_entries()
        .unwrap()
        .into_iter()
        .map(|fe| LoaderFunctionEntry { x: fe })
        .collect::<Vec<LoaderFunctionEntry>>()
}

fn elf_from_file(filename: String) -> LoaderElf {
    let path = Path::new(&filename);
    LoaderElf {
        x: Arc::new(falcon::loader::Elf::from_file(&path).unwrap())
    }
}

fn elf_function(elf: &LoaderElf, address: u64) -> il::IlFunction {
    il::IlFunction { x: elf.x.function(address).unwrap() }
}

fn elf_memory(elf: &LoaderElf) -> memory::BackingMemory {
    memory::BackingMemory { x: elf.x.memory().unwrap() }
}

fn elf_program(elf: &LoaderElf) -> il::IlProgram {
    il::IlProgram { x: elf.x.program().unwrap() }
}

fn elf_program_recursive(elf: &LoaderElf) -> il::IlProgram {
    il::IlProgram { x: elf.x.program_recursive().unwrap() }
}


falcon_type_wrapper!(Arc<falcon::loader::ElfLinker>, LoaderElfLinker);

fn elf_linker_architecture(elf_linker: &LoaderElfLinker)
    -> architecture::ArchitectureArchitecture {

    architecture::ArchitectureArchitecture {
        x: Arc::new(elf_linker.x.architecture().box_clone())
    }
}

fn elf_linker_function(elf_linker: &LoaderElfLinker, address: u64)
    -> Option<il::IlFunction> {

    elf_linker.x.function(address).ok().map(|f| il::IlFunction {x: f})
}

fn elf_linker_function_entries(elf_linker: &LoaderElfLinker)
    -> Vec<LoaderFunctionEntry> {

    elf_linker.x
        .function_entries()
        .unwrap()
        .into_iter()
        .map(|fe| LoaderFunctionEntry { x: fe })
        .collect::<Vec<LoaderFunctionEntry>>()
}

fn elf_linker_memory(elf_linker: &LoaderElfLinker) -> memory::BackingMemory {
    memory::BackingMemory { x: elf_linker.x.memory().unwrap() }
}

fn elf_linker_new(
    filename: String,
    do_relocations: bool,
    just_interpreter: bool
) -> LoaderElfLinker {
    LoaderElfLinker {
        x: Arc::new(falcon::loader::ElfLinker::new(
            filename.into(),
            do_relocations,
            just_interpreter,
            None
        ).unwrap())
    }
}

fn elf_linker_program(elf_linker: &LoaderElfLinker) -> il::IlProgram {
    il::IlProgram { x: elf_linker.x.program().unwrap() }
}

fn elf_linker_program_entry(elf_linker: &LoaderElfLinker) -> u64 {
    elf_linker.x.program_entry()
}

fn elf_linker_program_recursive(elf_linker: &LoaderElfLinker) -> il::IlProgram {
    il::IlProgram { x: elf_linker.x.program_recursive().unwrap() }
}


falcon_type_wrapper!(Arc<falcon::loader::Pe>, LoaderPe);

fn pe_architecture(pe: &LoaderPe) -> architecture::ArchitectureArchitecture {
    architecture::ArchitectureArchitecture {
        x: Arc::new(pe.x.architecture().box_clone())
    }
}

fn pe_from_file(filename: String) -> LoaderPe {
    let path = Path::new(&filename);
    LoaderPe {
        x: Arc::new(falcon::loader::Pe::from_file(&path).unwrap())
    }
}

fn pe_function(pe: &LoaderPe, address: u64) -> il::IlFunction {
    il::IlFunction { x: pe.x.function(address).unwrap() }
}

fn pe_function_entries(pe: &LoaderPe) -> Vec<LoaderFunctionEntry> {
    pe.x
      .function_entries()
      .unwrap()
      .iter()
      .map(|fe| LoaderFunctionEntry { x: fe.clone() })
      .collect::<Vec<LoaderFunctionEntry>>()
}

fn pe_memory(pe: &LoaderPe) -> memory::BackingMemory {
    memory::BackingMemory { x: pe.x.memory().unwrap() }
}

fn pe_program(pe: &LoaderPe) -> il::IlProgram {
    il::IlProgram { x: pe.x.program().unwrap() }
}

fn pe_program_recursive(pe: &LoaderPe) -> il::IlProgram {
    il::IlProgram { x: pe.x.program_recursive().unwrap() }
}

falcon_type_wrapper!(Arc<falcon::loader::Loader>, LoaderLoader);

fn loader_from_file(filename: String) -> Option<LoaderLoader> {
    let path = Path::new(&filename);

    let loader = falcon::loader::Elf::from_file(&path)
        .ok()
        .map(|elf| Arc::new(elf));

    if let Some(loader) = loader {
        return Some(LoaderLoader {x: loader});
    }

    let loader = falcon::loader::Pe::from_file(&path)
            .ok()
            .map(|pe| Arc::new(pe))?;

    Some(LoaderLoader { x: loader })
}

fn loader_architecture(loader: &LoaderLoader) -> architecture::ArchitectureArchitecture {
    architecture::ArchitectureArchitecture {
        x: Arc::new(loader.x.architecture().box_clone())
    }
}

fn loader_function(loader: &LoaderLoader, address: u64) -> il::IlFunction {
    il::IlFunction { x: loader.x.function(address).unwrap() }
}

fn loader_function_entries(loader: &LoaderLoader) -> Vec<LoaderFunctionEntry> {
    loader.x
        .function_entries()
        .unwrap()
        .iter()
        .map(|fe| LoaderFunctionEntry { x: fe.clone() })
        .collect::<Vec<LoaderFunctionEntry>>()
}

fn loader_memory(loader: &LoaderLoader) -> memory::BackingMemory {
    memory::BackingMemory { x: loader.x.memory().unwrap() }
}

fn loader_program(loader: &LoaderLoader) -> il::IlProgram {
    il::IlProgram { x: loader.x.program().unwrap() }
}

fn loader_program_recursive(loader: &LoaderLoader) -> il::IlProgram {
    il::IlProgram { x: loader.x.program_recursive().unwrap() }
}

falcon_type_wrapper!(falcon::loader::FunctionEntry, LoaderFunctionEntry);

fn function_entry_name(function_entry: &LoaderFunctionEntry) -> Option<String> {
    function_entry.x.name().map(|s| s.to_string())
}

fn function_entry_address(function_entry: &LoaderFunctionEntry) -> u64 {
    function_entry.x.address()
}

fn function_entry_str(function_entry: &LoaderFunctionEntry) -> String {
    format!("{}", function_entry.x)
}


pub fn bindings(vm: gluon::RootedThread) -> gluon::RootedThread {

    vm.register_type::<LoaderElf>("LoaderElf", &[]).unwrap();
    vm.register_type::<LoaderElfLinker>("LoaderElfLinker", &[]).unwrap();
    vm.register_type::<LoaderFunctionEntry>("LoaderFunctionEntry", &[]).unwrap();
    vm.register_type::<LoaderLoader>("LoaderLoader", &[]).unwrap();
    vm.register_type::<LoaderPe>("LoaderPe", &[]).unwrap();

    fn falcon_loader_prim_loader(vm: &gluon::Thread)
        -> gluon::vm::Result<gluon::vm::ExternModule> {
        
        gluon::vm::ExternModule::new(vm, record! {
            elf_architecture => primitive!(1, elf_architecture),
            elf_base_address => primitive!(1, elf_base_address),
            elf_from_file => primitive!(1, elf_from_file),
            elf_function_entries => primitive!(1, elf_function_entries),
            elf_function => primitive!(2, elf_function),
            elf_memory => primitive!(1, elf_memory),
            elf_program => primitive!(1, elf_program),
            elf_program_recursive => primitive!(1, elf_program_recursive),
            elf_linker_architecture => primitive!(1, elf_linker_architecture),
            elf_linker_function => primitive!(2, elf_linker_function),
            elf_linker_function_entries => primitive!(1, elf_linker_function_entries),
            elf_linker_memory => primitive!(1, elf_linker_memory),
            elf_linker_new => primitive!(3, elf_linker_new),
            elf_linker_program => primitive!(1, elf_linker_program),
            elf_linker_program_entry => primitive!(1, elf_linker_program_entry),
            elf_linker_program_recursive => primitive!(1, elf_linker_program_recursive),
            function_entry_name => primitive!(1, function_entry_name),
            function_entry_address => primitive!(1, function_entry_address),
            function_entry_str => primitive!(1, function_entry_str),
            loader_architecture => primitive!(1, loader_architecture),
            loader_from_file => primitive!(1, loader_from_file),
            loader_function => primitive!(2, loader_function),
            loader_function_entries => primitive!(1, loader_function_entries),
            loader_memory => primitive!(1, loader_memory),
            loader_program => primitive!(1, loader_program),
            loader_program_recursive => primitive!(1, loader_program_recursive),
            pe_architecture => primitive!(1, pe_architecture),
            pe_from_file => primitive!(1, pe_from_file),
            pe_function_entries => primitive!(1, pe_function_entries),
            pe_function => primitive!(2, pe_function),
            pe_memory => primitive!(1, pe_memory),
            pe_program => primitive!(1, pe_program),
            pe_program_recursive => primitive!(1, pe_program_recursive),
        })
    }
    
    gluon::import::add_extern_module(
        &vm, "falcon_loader_prim", falcon_loader_prim_loader);

    vm
}