Allow procmgr to recognize unhandled exceptions.

This commit is contained in:
4lDO2
2025-04-15 15:18:42 +02:00
parent 020b8ad415
commit 2e6122bc7e
9 changed files with 134 additions and 54 deletions
+89 -25
View File
@@ -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();
}
});
+3 -1
View File
@@ -44,7 +44,9 @@ pub enum Status {
HardBlocked {
reason: HardBlockedReason,
},
Dead,
Dead {
excp: Option<syscall::Exception>,
},
}
impl Status {
+24 -7
View File
@@ -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
View File
@@ -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
View File
@@ -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 {
+1 -1
View File
@@ -53,7 +53,7 @@ pub fn resource() -> Result<Vec<u8>> {
stat_string.push('B');
}
}
context::Status::Dead => {
context::Status::Dead { .. } => {
stat_string.push('Z');
}
}
+1 -1
View File
@@ -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
View File
@@ -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
+2 -2
View File
@@ -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 {