mod.rs 6.81 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

    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))
    }

}

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

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

    let error = unsafe {dlerror()};
    if !error.is_null() {
        let cstr = unsafe {CStr::from_ptr(error)};
73
        panic!("failed to resolve symbol: {} ({})", symbol, cstr.to_str().unwrap());
74 75 76 77 78
    }
    
    Address::from_ptr(ret)
}

79
rodal_enum!(ValueLocation{(Register: group, id), (Constant: group, word), (Relocatable: group, name)});
qinsoon's avatar
qinsoon committed
80
#[derive(PartialEq, Eq, Hash, Clone, Debug)]
81
pub enum ValueLocation {
82 83
    Register(RegGroup, MuID),
    Constant(RegGroup, Word),
84 85
    Relocatable(RegGroup, MuName), // TODO: This only works for mu entities (add a flag to indicate if its native or have a different variant?)

86 87
    Direct(RegGroup, Address),    // Not dumped
    Indirect(RegGroup, Address),  // Not dumped
qinsoon's avatar
qinsoon committed
88 89
}

90 91 92 93 94 95 96 97 98 99 100 101
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)
        }
    }
}

102 103 104 105 106
impl ValueLocation {
    pub fn load_value(&self) -> (RegGroup, Word) {
        match self {
            &ValueLocation::Register(_, _)
            | &ValueLocation::Direct(_, _)
107 108 109 110 111
            | &ValueLocation::Indirect(_, _) => unimplemented!(),
            
            &ValueLocation::Constant(group, word) => {
                (group, word)
            }
112 113 114
            &ValueLocation::Relocatable(_, _) => panic!("expect a runtime value")
        }
    }
qinsoon's avatar
qinsoon committed
115
    
116
    #[allow(unused_variables)]
qinsoon's avatar
qinsoon committed
117
    pub fn from_constant(c: Constant) -> ValueLocation {
118 119 120 121 122 123 124
        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
125
    }
qinsoon's avatar
qinsoon committed
126 127 128 129 130 131 132 133 134 135
    
    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())
        }
    }
136 137 138 139 140 141 142

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

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

147 148
#[no_mangle]
pub extern fn mu_trace_level_log() {
qinsoon's avatar
qinsoon committed
149
    VM::start_logging_trace();
150 151
}

152 153 154
#[no_mangle]
pub static mut LAST_TIME: c_ulong = 0;

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

    unsafe{rodal::load_asm_bounds(rodal::Address::from_ptr(dumped_vm), rodal::Address::from_ptr(edata))};
    let vm = VM::resume_vm(dumped_vm);
162

163 164 165 166 167 168 169 170
    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
171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186

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

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