diff --git a/src/context/context.rs b/src/context/context.rs index 269b4ee4095953e4fa4302edac360205d76cfe67..0a0f1869b9c6ad635e9d2ba16a2284ff31550993 100644 --- a/src/context/context.rs +++ b/src/context/context.rs @@ -142,8 +142,8 @@ pub struct Context { pub kfx: Option<Box<[u8]>>, /// Kernel stack pub kstack: Option<Box<[u8]>>, - /// Kernel signal backup - pub ksig: Option<(arch::Context, Option<Box<[u8]>>, Option<Box<[u8]>>)>, + /// Kernel signal backup: Registers, Kernel FX, Kernel Stack, Signal number + pub ksig: Option<(arch::Context, Option<Box<[u8]>>, Option<Box<[u8]>>, u8)>, /// Restore ksig context on next switch pub ksig_restore: bool, /// Executable image diff --git a/src/context/signal.rs b/src/context/signal.rs index a19376af3a41879f5f80111159f6ae9780cac04b..f7db1ae3fc31774ce81d3bc968d42022e1fe7a65 100644 --- a/src/context/signal.rs +++ b/src/context/signal.rs @@ -6,6 +6,11 @@ use crate::start::usermode; use crate::syscall; use crate::syscall::flag::{SIG_DFL, SIG_IGN, SIGCHLD, SIGCONT, SIGSTOP, SIGTSTP, SIGTTIN, SIGTTOU}; +pub fn is_user_handled(handler: Option<extern "C" fn(usize)>) -> bool { + let handler = handler.map(|ptr| ptr as usize).unwrap_or(0); + handler != SIG_DFL && handler != SIG_IGN +} + pub extern "C" fn signal_handler(sig: usize) { let (action, restorer) = { let contexts = contexts(); diff --git a/src/context/switch.rs b/src/context/switch.rs index cf55220fc802dbbcbda6456318df42a4fcf20efa..2a5f6c51aed09eb27f63562faf68cfbc4c47dc73 100644 --- a/src/context/switch.rs +++ b/src/context/switch.rs @@ -151,7 +151,7 @@ pub unsafe fn switch() -> bool { let arch = (&mut *to_ptr).arch.clone(); let kfx = (&mut *to_ptr).kfx.clone(); let kstack = (&mut *to_ptr).kstack.clone(); - (&mut *to_ptr).ksig = Some((arch, kfx, kstack)); + (&mut *to_ptr).ksig = Some((arch, kfx, kstack, sig)); (&mut *to_ptr).arch.signal_stack(signal_handler, sig); } diff --git a/src/ptrace.rs b/src/ptrace.rs index f82749680289e0e0aa38e82c3b3425a64848be17..538a2fc8617ce0c66b9c578c678bdb2ee2e0cc97 100644 --- a/src/ptrace.rs +++ b/src/ptrace.rs @@ -9,7 +9,7 @@ use crate::{ } }, common::unique::Unique, - context::{self, Context, ContextId, Status}, + context::{self, signal, Context, ContextId, Status}, event, scheme::proc, sync::WaitCondition @@ -328,18 +328,44 @@ pub unsafe fn rebase_regs_ptr_mut( /// restored and otherwise undo all your changes. See `update(...)` in /// context/switch.rs. pub unsafe fn regs_for(context: &Context) -> Option<&InterruptStack> { - Some(&*match context.ksig { - Some((_, _, ref kstack)) => rebase_regs_ptr(context.regs, kstack.as_ref())?, - None => context.regs?.1.as_ptr() - }) + let signal_backup_regs = match context.ksig { + None => None, + Some((_, _, ref kstack, signum)) => { + let is_user_handled = { + let actions = context.actions.lock(); + signal::is_user_handled(actions[signum as usize].0.sa_handler) + }; + if is_user_handled { + None + } else { + Some(rebase_regs_ptr(context.regs, kstack.as_ref())?) + } + } + }; + signal_backup_regs + .or_else(|| context.regs.map(|regs| regs.1.as_ptr() as *const _)) + .map(|ptr| &*ptr) } /// Mutable version of `regs_for` pub unsafe fn regs_for_mut(context: &mut Context) -> Option<&mut InterruptStack> { - Some(&mut *match context.ksig { - Some((_, _, ref mut kstack)) => rebase_regs_ptr_mut(context.regs, kstack.as_mut())?, - None => context.regs?.1.as_ptr() - }) + let signal_backup_regs = match context.ksig { + None => None, + Some((_, _, ref mut kstack, signum)) => { + let is_user_handled = { + let actions = context.actions.lock(); + signal::is_user_handled(actions[signum as usize].0.sa_handler) + }; + if is_user_handled { + None + } else { + Some(rebase_regs_ptr_mut(context.regs, kstack.as_mut())?) + } + } + }; + signal_backup_regs + .or_else(|| context.regs.map(|regs| regs.1.as_ptr())) + .map(|ptr| &mut *ptr) } // __ __