Allow procmgr to recognize unhandled exceptions.
This commit is contained in:
@@ -1,15 +1,19 @@
|
||||
use syscall::Exception;
|
||||
use x86::irq::PageFaultError;
|
||||
|
||||
use crate::{
|
||||
interrupt_error, interrupt_stack, ksignal, memory::GenericPfFlags, paging::VirtualAddress,
|
||||
panic::stack_trace, ptrace, syscall::flag::*,
|
||||
arch::x86_shared::interrupt, context::signal::excp_handler, interrupt_error, interrupt_stack,
|
||||
memory::GenericPfFlags, paging::VirtualAddress, panic::stack_trace, ptrace, syscall::flag::*,
|
||||
};
|
||||
|
||||
interrupt_stack!(divide_by_zero, |stack| {
|
||||
println!("Divide by zero");
|
||||
stack.dump();
|
||||
stack_trace();
|
||||
ksignal(SIGFPE);
|
||||
excp_handler(Exception {
|
||||
kind: 0,
|
||||
..Default::default()
|
||||
});
|
||||
});
|
||||
|
||||
interrupt_stack!(debug, @paranoid, |stack| {
|
||||
@@ -31,7 +35,10 @@ interrupt_stack!(debug, @paranoid, |stack| {
|
||||
if !handled {
|
||||
println!("Debug trap");
|
||||
stack.dump();
|
||||
ksignal(SIGTRAP);
|
||||
excp_handler(Exception {
|
||||
kind: 1,
|
||||
..Default::default()
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
@@ -64,7 +71,10 @@ interrupt_stack!(breakpoint, |stack| {
|
||||
if ptrace::breakpoint_callback(PTRACE_STOP_BREAKPOINT, None).is_none() {
|
||||
println!("Breakpoint trap");
|
||||
stack.dump();
|
||||
ksignal(SIGTRAP);
|
||||
excp_handler(Exception {
|
||||
kind: 3,
|
||||
..Default::default()
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
@@ -72,63 +82,94 @@ interrupt_stack!(overflow, |stack| {
|
||||
println!("Overflow trap");
|
||||
stack.dump();
|
||||
stack_trace();
|
||||
ksignal(SIGFPE);
|
||||
excp_handler(Exception {
|
||||
kind: 4,
|
||||
..Default::default()
|
||||
});
|
||||
});
|
||||
|
||||
interrupt_stack!(bound_range, |stack| {
|
||||
println!("Bound range exceeded fault");
|
||||
stack.dump();
|
||||
stack_trace();
|
||||
ksignal(SIGSEGV);
|
||||
excp_handler(Exception {
|
||||
kind: 5,
|
||||
..Default::default()
|
||||
});
|
||||
});
|
||||
|
||||
interrupt_stack!(invalid_opcode, |stack| {
|
||||
println!("Invalid opcode fault");
|
||||
stack.dump();
|
||||
stack_trace();
|
||||
ksignal(SIGILL);
|
||||
excp_handler(Exception {
|
||||
kind: 6,
|
||||
..Default::default()
|
||||
});
|
||||
});
|
||||
|
||||
interrupt_stack!(device_not_available, |stack| {
|
||||
println!("Device not available fault");
|
||||
stack.dump();
|
||||
stack_trace();
|
||||
ksignal(SIGILL);
|
||||
excp_handler(Exception {
|
||||
kind: 7,
|
||||
..Default::default()
|
||||
});
|
||||
});
|
||||
|
||||
interrupt_error!(double_fault, |stack, _code| {
|
||||
println!("Double fault");
|
||||
stack.dump();
|
||||
stack_trace();
|
||||
ksignal(SIGSEGV);
|
||||
loop {
|
||||
interrupt::disable();
|
||||
interrupt::halt();
|
||||
}
|
||||
});
|
||||
|
||||
interrupt_error!(invalid_tss, |stack, _code| {
|
||||
interrupt_error!(invalid_tss, |stack, code| {
|
||||
println!("Invalid TSS fault");
|
||||
stack.dump();
|
||||
stack_trace();
|
||||
ksignal(SIGSEGV);
|
||||
excp_handler(Exception {
|
||||
kind: 10,
|
||||
code,
|
||||
..Default::default()
|
||||
});
|
||||
});
|
||||
|
||||
interrupt_error!(segment_not_present, |stack, _code| {
|
||||
interrupt_error!(segment_not_present, |stack, code| {
|
||||
println!("Segment not present fault");
|
||||
stack.dump();
|
||||
stack_trace();
|
||||
ksignal(SIGSEGV);
|
||||
excp_handler(Exception {
|
||||
kind: 11,
|
||||
code,
|
||||
..Default::default()
|
||||
});
|
||||
});
|
||||
|
||||
interrupt_error!(stack_segment, |stack, _code| {
|
||||
interrupt_error!(stack_segment, |stack, code| {
|
||||
println!("Stack segment fault");
|
||||
stack.dump();
|
||||
stack_trace();
|
||||
ksignal(SIGSEGV);
|
||||
excp_handler(Exception {
|
||||
kind: 12,
|
||||
code,
|
||||
..Default::default()
|
||||
});
|
||||
});
|
||||
|
||||
interrupt_error!(protection, |stack, code| {
|
||||
println!("Protection fault code={:#0x}", code);
|
||||
stack.dump();
|
||||
stack_trace();
|
||||
ksignal(SIGSEGV);
|
||||
excp_handler(Exception {
|
||||
kind: 13,
|
||||
code,
|
||||
..Default::default()
|
||||
});
|
||||
});
|
||||
|
||||
interrupt_error!(page, |stack, code| {
|
||||
@@ -161,7 +202,11 @@ interrupt_error!(page, |stack, code| {
|
||||
println!("Page fault: {:>016X} {:#?}", cr2.data(), arch_flags);
|
||||
stack.dump();
|
||||
stack_trace();
|
||||
ksignal(SIGSEGV);
|
||||
excp_handler(Exception {
|
||||
kind: 14,
|
||||
code,
|
||||
address: cr2.data(),
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
@@ -169,21 +214,31 @@ interrupt_stack!(fpu_fault, |stack| {
|
||||
println!("FPU floating point fault");
|
||||
stack.dump();
|
||||
stack_trace();
|
||||
ksignal(SIGFPE);
|
||||
excp_handler(Exception {
|
||||
kind: 16,
|
||||
..Default::default()
|
||||
});
|
||||
});
|
||||
|
||||
interrupt_error!(alignment_check, |stack, _code| {
|
||||
interrupt_error!(alignment_check, |stack, code| {
|
||||
println!("Alignment check fault");
|
||||
stack.dump();
|
||||
stack_trace();
|
||||
ksignal(SIGBUS);
|
||||
excp_handler(Exception {
|
||||
kind: 17,
|
||||
code,
|
||||
..Default::default()
|
||||
});
|
||||
});
|
||||
|
||||
interrupt_stack!(machine_check, @paranoid, |stack| {
|
||||
println!("Machine check fault");
|
||||
stack.dump();
|
||||
stack_trace();
|
||||
ksignal(SIGBUS);
|
||||
loop {
|
||||
interrupt::disable();
|
||||
interrupt::halt();
|
||||
}
|
||||
});
|
||||
|
||||
interrupt_stack!(simd, |stack| {
|
||||
@@ -193,19 +248,28 @@ interrupt_stack!(simd, |stack| {
|
||||
core::arch::asm!("stmxcsr [{}]", in(reg) core::ptr::addr_of_mut!(mxcsr));
|
||||
println!("MXCSR {:#0x}", mxcsr);
|
||||
stack_trace();
|
||||
ksignal(SIGFPE);
|
||||
excp_handler(Exception {
|
||||
kind: 19,
|
||||
..Default::default()
|
||||
});
|
||||
});
|
||||
|
||||
interrupt_stack!(virtualization, |stack| {
|
||||
println!("Virtualization fault");
|
||||
stack.dump();
|
||||
stack_trace();
|
||||
ksignal(SIGBUS);
|
||||
loop {
|
||||
interrupt::disable();
|
||||
interrupt::halt();
|
||||
}
|
||||
});
|
||||
|
||||
interrupt_error!(security, |stack, _code| {
|
||||
println!("Security exception");
|
||||
stack.dump();
|
||||
stack_trace();
|
||||
ksignal(SIGBUS);
|
||||
loop {
|
||||
interrupt::disable();
|
||||
interrupt::halt();
|
||||
}
|
||||
});
|
||||
|
||||
@@ -44,7 +44,9 @@ pub enum Status {
|
||||
HardBlocked {
|
||||
reason: HardBlockedReason,
|
||||
},
|
||||
Dead,
|
||||
Dead {
|
||||
excp: Option<syscall::Exception>,
|
||||
},
|
||||
}
|
||||
|
||||
impl Status {
|
||||
|
||||
+24
-7
@@ -75,15 +75,32 @@ pub fn signal_handler() {
|
||||
Ordering::Release,
|
||||
);
|
||||
}
|
||||
pub fn excp_handler(_signal: usize) {
|
||||
pub fn excp_handler(excp: syscall::Exception) {
|
||||
let current = context::current();
|
||||
let context = current.write();
|
||||
|
||||
let Some(_eh) = context.sig.as_ref().and_then(|s| s.excp_handler) else {
|
||||
let mut context = current.write();
|
||||
|
||||
let Some(eh) = context.sig.as_ref().and_then(|s| s.excp_handler) else {
|
||||
// TODO: Let procmgr print this?
|
||||
log::info!(
|
||||
"UNHANDLED EXCEPTION, CPU {}, PID {current:p}, NAME {}",
|
||||
crate::cpu_id(),
|
||||
context.name
|
||||
);
|
||||
drop(context);
|
||||
drop(current);
|
||||
crate::syscall::exit_this_context();
|
||||
// TODO: Allow exceptions to be caught by tracer etc, without necessarily exiting the
|
||||
// context (closing files, dropping AddrSpace, etc)
|
||||
crate::syscall::process::exit_this_context(Some(excp));
|
||||
};
|
||||
|
||||
// TODO: call exception handler, similar to the signal handler case
|
||||
// TODO
|
||||
/*
|
||||
let Some(regs) = context.regs_mut() else {
|
||||
// TODO: unhandled exception in this case too?
|
||||
return;
|
||||
};
|
||||
let old_ip = regs.instr_pointer();
|
||||
let old_archdep_reg = regs.ar
|
||||
let (tctl, pctl, sigst) = context.sigcontrol().expect("already checked");
|
||||
tctl.saved_ip.set(excp.rsp);
|
||||
tctl.saved_archdep_reg*/
|
||||
}
|
||||
|
||||
-12
@@ -270,18 +270,6 @@ fn run_userspace() -> ! {
|
||||
}
|
||||
}
|
||||
|
||||
/// Allow exception handlers to send signal to arch-independent kernel
|
||||
pub fn ksignal(signal: usize) {
|
||||
let current = context::current();
|
||||
|
||||
info!("SIGNAL {signal}, CPU {}, PID {current:p}", cpu_id(),);
|
||||
{
|
||||
let context = current.read();
|
||||
info!("NAME {}", context.name);
|
||||
}
|
||||
crate::context::signal::excp_handler(signal);
|
||||
}
|
||||
|
||||
// TODO: Use this macro on aarch64 too.
|
||||
|
||||
macro_rules! linker_offsets(
|
||||
|
||||
+13
-4
@@ -1065,7 +1065,7 @@ impl ContextHandle {
|
||||
let mut guard = context.write();
|
||||
|
||||
match guard.status {
|
||||
Status::Dead => return Err(Error::new(EOWNERDEAD)),
|
||||
Status::Dead { .. } => return Err(Error::new(EOWNERDEAD)),
|
||||
Status::HardBlocked {
|
||||
reason: HardBlockedReason::AwaitingMmap { .. },
|
||||
} => todo!(),
|
||||
@@ -1118,7 +1118,7 @@ impl ContextHandle {
|
||||
}
|
||||
}
|
||||
}
|
||||
crate::syscall::exit_this_context();
|
||||
crate::syscall::exit_this_context(None);
|
||||
} else {
|
||||
let mut ctxt = context.write();
|
||||
//log::trace!("FORCEKILL NONSELF={} {}, SELF={}", ctxt.debug_id, ctxt.pid, context::current().read().debug_id);
|
||||
@@ -1250,8 +1250,17 @@ impl ContextHandle {
|
||||
let status = {
|
||||
let context = context.read();
|
||||
match context.status {
|
||||
Status::Dead => ContextStatus::Dead,
|
||||
Status::Runnable if context.being_sigkilled => ContextStatus::Dead,
|
||||
Status::Dead { excp: None } => ContextStatus::Dead,
|
||||
Status::Runnable if context.being_sigkilled => ContextStatus::ForceKilled,
|
||||
Status::Dead { excp: Some(excp) } => {
|
||||
let (status, payload) =
|
||||
buf.split_at(size_of::<usize>()).ok_or(Error::new(EINVAL))?;
|
||||
status.copy_from_slice(
|
||||
&(ContextStatus::UnhandledExcp as usize).to_ne_bytes(),
|
||||
)?;
|
||||
let len = payload.copy_common_bytes_from_slice(&excp)?;
|
||||
return Ok(size_of::<usize>() + len);
|
||||
}
|
||||
Status::Runnable => ContextStatus::Runnable,
|
||||
Status::Blocked => ContextStatus::Blocked,
|
||||
Status::HardBlocked {
|
||||
|
||||
@@ -53,7 +53,7 @@ pub fn resource() -> Result<Vec<u8>> {
|
||||
stat_string.push('B');
|
||||
}
|
||||
}
|
||||
context::Status::Dead => {
|
||||
context::Status::Dead { .. } => {
|
||||
stat_string.push('Z');
|
||||
}
|
||||
}
|
||||
|
||||
@@ -208,7 +208,7 @@ impl SyscallDebugInfo {
|
||||
}
|
||||
#[cfg(feature = "syscall_debug")]
|
||||
pub fn debug_start([a, b, c, d, e, f]: [usize; 6]) {
|
||||
let do_debug = if crate::context::current().read().name.contains("bash") {
|
||||
let do_debug = if false && crate::context::current().read().name.contains("bash") {
|
||||
if a == SYS_CLOCK_GETTIME || a == SYS_YIELD || a == SYS_FUTEX {
|
||||
false
|
||||
} else if (a == SYS_WRITE || a == SYS_FSYNC) && (b == 1 || b == 2) {
|
||||
|
||||
+1
-1
@@ -216,7 +216,7 @@ pub fn syscall(a: usize, b: usize, c: usize, d: usize, e: usize, f: usize) -> us
|
||||
percpu.inside_syscall.set(false);
|
||||
|
||||
if percpu.switch_internals.being_sigkilled.get() {
|
||||
exit_this_context();
|
||||
exit_this_context(None);
|
||||
}
|
||||
|
||||
// errormux turns Result<usize> into -errno
|
||||
|
||||
@@ -23,7 +23,7 @@ use crate::{
|
||||
|
||||
use super::usercopy::UserSliceWo;
|
||||
|
||||
pub fn exit_this_context() -> ! {
|
||||
pub fn exit_this_context(excp: Option<syscall::Exception>) -> ! {
|
||||
let close_files;
|
||||
let addrspace_opt;
|
||||
|
||||
@@ -49,7 +49,7 @@ pub fn exit_this_context() -> ! {
|
||||
// TODO: Should status == Status::HardBlocked be handled differently?
|
||||
let owner = {
|
||||
let mut guard = context_lock.write();
|
||||
guard.status = context::Status::Dead;
|
||||
guard.status = context::Status::Dead { excp };
|
||||
guard.owner_proc_id
|
||||
};
|
||||
if let Some(owner) = owner {
|
||||
|
||||
Reference in New Issue
Block a user