mod.rs 6.72 KB
Newer Older
Isaac Oscar Gariano's avatar
Isaac Oscar Gariano committed
1 2 3 4 5 6 7 8 9 10 11 12 13 14
// Copyright 2017 The Australian National University
// 
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// 
//     http://www.apache.org/licenses/LICENSE-2.0
// 
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

15
use utils;
16
use ast::ir::*;
17
use vm::VM;
18 19
use compiler::backend::Word;
use compiler::backend::RegGroup;
qinsoon's avatar
qinsoon committed
20
use utils::Address;
21

22 23
use libc::*;
use std;
24
use std::fmt;
25
use std::ffi::CString;
26 27
use std::ffi::CStr;
use std::sync::Arc;
28
use rodal;
29

30
pub mod mm;
qinsoon's avatar
qinsoon committed
31
pub mod thread;
qinsoon's avatar
qinsoon committed
32
pub mod math;
qinsoon's avatar
qinsoon committed
33
pub mod entrypoints;
qinsoon's avatar
qinsoon committed
34

35 36
pub mod exception;

37

38 39 40
// TODO: this actually returns the name and address of the nearest symbol (of any type)
// that starts before function_addr (instead we want the nearest function symbol)
pub fn get_function_info(function_addr: Address) -> (CName, Address) {
41 42
    // dladdr will initialise this for us
    let mut info = unsafe{std::mem::uninitialized::<Dl_info>()};
43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62

    unsafe {dladdr(function_addr.to_ptr_mut::<c_void>(), &mut info)};

    let error = unsafe {dlerror()};
    if !error.is_null() {
        let cstr = unsafe {CStr::from_ptr(error)};
        error!("cannot find function address: {}", function_addr);
        error!("{}", cstr.to_str().unwrap());

        panic!("failed to resolve function address");
    }
    if !info.dli_sname.is_null() {
        (unsafe {CStr::from_ptr(info.dli_sname)}.to_str().unwrap().to_string(), Address::from_ptr(info.dli_saddr))
    } else {
        ("UNKOWN".to_string(), Address::from_ptr(info.dli_saddr))
    }

}


63 64
pub fn resolve_symbol(symbol: String) -> Address {
    use std::ptr;
65

66
    let c_symbol = CString::new(name_check(symbol.clone())).unwrap();
67 68
    
    let rtld_default = unsafe {dlopen(ptr::null(), 0)};
69
    let ret = unsafe {dlsym(rtld_default, c_symbol.as_ptr())};
70 71 72 73

    let error = unsafe {dlerror()};
    if !error.is_null() {
        let cstr = unsafe {CStr::from_ptr(error)};
74 75
        error!("cannot find symbol: {}", symbol);
        error!("{}", cstr.to_str().unwrap());
76 77

        panic!("failed to resolve symbol");
78 79 80 81 82
    }
    
    Address::from_ptr(ret)
}

83
rodal_enum!(ValueLocation{(Register: group, id), (Constant: group, word), (Relocatable: group, name)});
qinsoon's avatar
qinsoon committed
84
#[derive(PartialEq, Eq, Hash, Clone, Debug)]
85
pub enum ValueLocation {
86 87 88
    Register(RegGroup, MuID),
    Constant(RegGroup, Word),
    Relocatable(RegGroup, MuName),
89
    
90 91
    Direct(RegGroup, Address),    // Not dumped
    Indirect(RegGroup, Address),  // Not dumped
qinsoon's avatar
qinsoon committed
92 93
}

94 95 96 97 98 99 100 101 102 103 104 105
impl fmt::Display for ValueLocation {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match self {
            &ValueLocation::Register(_, id) => write!(f, "VL_Reg: {}", id),
            &ValueLocation::Constant(_, val) => write!(f, "VL_Const: {}", val),
            &ValueLocation::Relocatable(_, ref name) => write!(f, "VL_Reloc: {}", name),
            &ValueLocation::Direct(_, addr) => write!(f, "VL_Direct: 0x{:x}", addr),
            &ValueLocation::Indirect(_, addr) => write!(f, "VL_Indirect: 0x{:x}", addr)
        }
    }
}

106 107 108 109 110
impl ValueLocation {
    pub fn load_value(&self) -> (RegGroup, Word) {
        match self {
            &ValueLocation::Register(_, _)
            | &ValueLocation::Direct(_, _)
111 112 113 114 115
            | &ValueLocation::Indirect(_, _) => unimplemented!(),
            
            &ValueLocation::Constant(group, word) => {
                (group, word)
            }
116 117 118
            &ValueLocation::Relocatable(_, _) => panic!("expect a runtime value")
        }
    }
qinsoon's avatar
qinsoon committed
119
    
120
    #[allow(unused_variables)]
qinsoon's avatar
qinsoon committed
121
    pub fn from_constant(c: Constant) -> ValueLocation {
122 123 124 125 126 127 128
        match c {
            Constant::Int(int_val) => ValueLocation::Constant(RegGroup::GPR, utils::mem::u64_to_raw(int_val)),
            Constant::Float(f32_val) => ValueLocation::Constant(RegGroup::FPR, utils::mem::f32_to_raw(f32_val)),
            Constant::Double(f64_val) => ValueLocation::Constant(RegGroup::FPR, utils::mem::f64_to_raw(f64_val)),
            
            _ => unimplemented!()
        }
qinsoon's avatar
qinsoon committed
129
    }
qinsoon's avatar
qinsoon committed
130 131 132 133 134 135 136 137 138 139
    
    pub fn to_address(&self) -> Address {
        match self {
            &ValueLocation::Register(_, _)
            | &ValueLocation::Constant(_, _) => panic!("a register/constant cannot be turned into address"),
            &ValueLocation::Direct(_, addr) => addr, 
            &ValueLocation::Indirect(_, addr) => unsafe {addr.load::<Address>()},
            &ValueLocation::Relocatable(_, ref symbol) => resolve_symbol(symbol.clone())
        }
    }
140 141 142 143 144 145 146

    pub fn to_relocatable(&self) -> MuName {
        match self {
            &ValueLocation::Relocatable(_, ref name) => name.clone(),
            _ => panic!("expecting Relocatable location, found {}", self)
        }
    }
147 148
}

149 150
pub const PRIMORDIAL_ENTRY : &'static str = "src/runtime/main.c";

151 152
#[no_mangle]
pub extern fn mu_trace_level_log() {
qinsoon's avatar
qinsoon committed
153
    VM::start_logging_trace();
154 155 156
}

#[no_mangle]
157 158
pub extern fn mu_main(edata: *const(), dumped_vm : *mut Arc<VM>, argc: c_int, argv: *const *const c_char) {
    VM::start_logging_env();
159
    debug!("mu_main() started...");
160 161 162

    unsafe{rodal::load_asm_bounds(rodal::Address::from_ptr(dumped_vm), rodal::Address::from_ptr(edata))};
    let vm = VM::resume_vm(dumped_vm);
163 164 165 166 167 168 169 170 171
    
    let primordial = vm.primordial.read().unwrap();
    if primordial.is_none() {
        panic!("no primordial thread/stack/function. Client should provide an entry point");
    } else {
        let primordial = primordial.as_ref().unwrap();
        
        // create mu stack
        let stack = vm.new_stack(primordial.func_id);
qinsoon's avatar
qinsoon committed
172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187

        // if the primordial named some const arguments, we use the const args
        // otherwise we push 'argc' and 'argv' to new stack
        let args : Vec<ValueLocation> = if primordial.has_const_args {
            primordial.args.iter().map(|arg| ValueLocation::from_constant(arg.clone())).collect()
        } else {
            let mut args = vec![];

            // 1st arg: argc
            args.push(ValueLocation::from_constant(Constant::Int(argc as u64)));

            // 2nd arg: argv
            args.push(ValueLocation::from_constant(Constant::Int(argv as u64)));

            args
        };
188 189 190
        
        // FIXME: currently assumes no user defined thread local
        // will need to fix this after we can serialize heap object
191
        let thread = thread::MuThread::new_thread_normal(stack, unsafe{Address::zero()}, args, vm.clone());
192 193 194
        
        thread.join().unwrap();
    }
195
}
196 197 198 199

#[no_mangle]
#[allow(unreachable_code)]
pub extern fn muentry_print_hex(x: u64) {
200
    println!("PRINTHEX: 0x{:x}", x);
201
}