WARNING! Access to this system is limited to authorised users only.
Unauthorised users may be subject to prosecution.
Unauthorised access to this system is a criminal offence under Australian law (Federal Crimes Act 1914 Part VIA)
It is a criminal offence to:
(1) Obtain access to data without authority. -Penalty 2 years imprisonment.
(2) Damage, delete, alter or insert data without authority. -Penalty 10 years imprisonment.
User activity is monitored and recorded. Anyone using this system expressly consents to such monitoring and recording.

To protect your data, the CISO officer has suggested users to enable 2FA as soon as possible.
Currently 2.7% of users enabled 2FA.

Commit 08a74443 authored by qinsoon's avatar qinsoon
Browse files

exception handling should work (also on linux)

cannot run test_throw in test_rpython along with other pytests
(especially tests from c script). Will look into this later
parent eb300764
......@@ -29,7 +29,7 @@ pub struct Frame {
impl fmt::Display for Frame {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
writeln!(f, "Frame for FuncVer {} {{", self.func_ver_id).unwrap();
writeln!(f, "\nFrame for FuncVer {} {{", self.func_ver_id).unwrap();
writeln!(f, " allocated slots:").unwrap();
for slot in self.allocated.values() {
writeln!(f, " {}", slot).unwrap();
......
......@@ -40,7 +40,7 @@ use std::fmt;
// last_frame_callee_saved: a pointer passed from assembly, values of 6 callee_saved
// registers are layed out as rbx, rbp, r12-r15 (from low address to high address)
// and return address is put after 6 callee saved regsiters
pub extern fn throw_exception_internal(exception_obj: Address, last_frame_callee_saved: Address) {
pub extern fn throw_exception_internal(exception_obj: Address, last_frame_callee_saved: Address) -> ! {
trace!("throwing exception: {}", exception_obj);
trace!("callee saved registers of last frame is saved at {}", last_frame_callee_saved);
......@@ -50,14 +50,15 @@ pub extern fn throw_exception_internal(exception_obj: Address, last_frame_callee
// set exception object
cur_thread.exception_obj = exception_obj;
let cf_lock = cur_thread.vm.compiled_funcs().read().unwrap();
let cf_lock = cur_thread.vm.compiled_funcs().read().unwrap();
let func_lock = cur_thread.vm.funcs().read().unwrap();
let rust_frame_return_addr = unsafe {last_frame_callee_saved.plus(POINTER_SIZE * x86_64::CALLEE_SAVED_GPRs.len()).load::<Address>()};
trace!("return address : 0x{:x} - throw instruction", rust_frame_return_addr);
// the return address is within throwing frame
let throw_frame_callsite = rust_frame_return_addr;
let (throw_func, throw_fv) = find_func_for_address(&cf_lock, throw_frame_callsite);
let (throw_func, throw_fv) = find_func_for_address(&cf_lock, &func_lock, throw_frame_callsite);
trace!("throwing fucntion: {}", throw_func);
// skip to previous frame
......@@ -88,12 +89,9 @@ pub extern fn throw_exception_internal(exception_obj: Address, last_frame_callee
trace!("Stack Unwinding starts");
loop {
trace!("frame cursor: {}", cursor);
// get return address (the slot above RBP slot)
// let return_addr = unsafe {rbp.plus(POINTER_SIZE).load::<Address>()};
// release the locks, and keep a clone of the frame
// because we may improperly leave this function
// FIXME: consider using Rust () -> ! to tell Rust compiler that we may not finish the func
let frame = {
let rwlock_cf = match cf_lock.get(&cursor.func_ver_id) {
Some(ret) => ret,
......@@ -119,7 +117,7 @@ pub extern fn throw_exception_internal(exception_obj: Address, last_frame_callee
if reg_id == x86_64::RBP.id() {
} else {
warn!("failed to find an entry for it in current frame");
info!("failed to find an entry for {} in current frame", reg_id);
}
}
}
......@@ -171,7 +169,7 @@ pub extern fn throw_exception_internal(exception_obj: Address, last_frame_callee
// keep unwinding
callsite = cursor.return_addr;
cursor.to_previous_frame(&cf_lock);
cursor.to_previous_frame(&cf_lock, &func_lock);
trace!("cursor unwinds to previous frame: {}", cursor);
}
}
......@@ -182,7 +180,7 @@ fn inspect_nearby_address(base: Address, n: isize) {
unsafe {
let addr = base.offset(i * POINTER_SIZE as isize);
let val = addr.load::<Word>();
trace!("addr: 0x{:x} | val: 0x{:x}", addr, val);
trace!("addr: 0x{:x} | val: 0x{:x} {}", addr, val, {if addr == base {"<- base"} else {""}});
}
i -= 1;
}
......@@ -198,7 +196,7 @@ struct FrameCursor {
impl fmt::Display for FrameCursor {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
writeln!(f, "FrameCursor{{").unwrap();
writeln!(f, "\nFrameCursor{{").unwrap();
writeln!(f, " rbp=0x{:x}, return_addr=0x{:x}, func_id={}, func_version_id={}", self.rbp, self.return_addr, self.func_id, self.func_ver_id).unwrap();
writeln!(f, " callee_saved:").unwrap();
for (reg, addr) in self.callee_saved_locs.iter() {
......@@ -209,7 +207,7 @@ impl fmt::Display for FrameCursor {
}
impl FrameCursor {
fn to_previous_frame(&mut self, cf: &RwLockReadGuard<HashMap<MuID, RwLock<CompiledFunction>>>) {
fn to_previous_frame(&mut self, cf: &RwLockReadGuard<HashMap<MuID, RwLock<CompiledFunction>>>, funcs: &RwLockReadGuard<HashMap<MuID, RwLock<MuFunction>>>) {
// check if return_addr is valid
// FIXME: should use a sentinel value here
if self.return_addr.is_zero() {
......@@ -218,7 +216,7 @@ impl FrameCursor {
let previous_rbp = unsafe {self.rbp.load::<Address>()};
let previous_return_addr = unsafe {previous_rbp.plus(POINTER_SIZE).load::<Address>()};
let (previous_func, previous_fv_id) = find_func_for_address(cf, self.return_addr);
let (previous_func, previous_fv_id) = find_func_for_address(cf, funcs, self.return_addr);
self.rbp = previous_rbp;
self.return_addr = previous_return_addr;
......@@ -227,14 +225,22 @@ impl FrameCursor {
}
}
fn find_func_for_address (cf: &RwLockReadGuard<HashMap<MuID, RwLock<CompiledFunction>>>, pc_addr: Address) -> (MuID, MuID) {
fn find_func_for_address (cf: &RwLockReadGuard<HashMap<MuID, RwLock<CompiledFunction>>>, funcs: &RwLockReadGuard<HashMap<MuID, RwLock<MuFunction>>>, pc_addr: Address) -> (MuID, MuID) {
use std::ops::Deref;
trace!("trying to find FuncVersion for address 0x{:x}", pc_addr);
for (_, func) in cf.iter() {
let func = func.read().unwrap();
let f = match funcs.get(&func.func_id) {
Some(f) => f,
None => panic!("failed to find func #{}", func.func_id)
};
let f_lock = f.read().unwrap();
let start = func.start.to_address();
let end = func.end.to_address();
trace!("CompiledFunction: func_id={}, fv_id={}, start=0x{:x}, end=0x{:x}", func.func_id, func.func_ver_id, start, end);
trace!("CompiledFunction: func={}, fv_id={}, start=0x{:x}, end=0x{:x}", f_lock.deref(), func.func_ver_id, start, end);
// pc won't be the start of a function, but could be the end
if pc_addr > start && pc_addr <= end {
......
......@@ -84,7 +84,13 @@ begin_func muentry_throw_exception
# %rsp points to %rbx, pass this as 2nd argument
movq %rsp, %rsi
#if defined (__linux__)
jmp CNAME(throw_exception_internal@PLT)
#elif defined (__APPLE__)
jmp CNAME(throw_exception_internal)
#else
#error "Only Linux and OSX are supported. "
#endif
# won't return
# _exception_restore(dest: Address, callee_saved: *const Word, rsp: Address) -> !
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment