Browse Source

Kernel: Send SIGSEGV on seg-fault

Now programs can catch the SIGSEGV signal when they segfault.

This commit also introduced the send_urgent_signal_to_self method,
which is needed to send signals to a thread when handling exceptions
caused by the same thread.
Drew Stratford 5 years ago
parent
commit
c136fd3fe2
3 changed files with 31 additions and 0 deletions
  1. 5 0
      Kernel/Arch/i386/CPU.cpp
  2. 24 0
      Kernel/Thread.cpp
  3. 2 0
      Kernel/Thread.h

+ 5 - 0
Kernel/Arch/i386/CPU.cpp

@@ -262,6 +262,11 @@ void exception_14_handler(RegisterDump& regs)
     auto response = MM.handle_page_fault(PageFault(regs.exception_code, VirtualAddress(fault_address)));
     auto response = MM.handle_page_fault(PageFault(regs.exception_code, VirtualAddress(fault_address)));
 
 
     if (response == PageFaultResponse::ShouldCrash) {
     if (response == PageFaultResponse::ShouldCrash) {
+	    if(current->has_signal_handler(SIGSEGV)){
+	        current->send_urgent_signal_to_self(SIGSEGV);
+	       	return;
+	    }
+
         kprintf("\033[31;1m%s(%u:%u) Unrecoverable page fault, %s address %p\033[0m\n",
         kprintf("\033[31;1m%s(%u:%u) Unrecoverable page fault, %s address %p\033[0m\n",
             current->process().name().characters(),
             current->process().name().characters(),
             current->pid(),
             current->pid(),

+ 24 - 0
Kernel/Thread.cpp

@@ -246,6 +246,23 @@ void Thread::send_signal(u8 signal, Process* sender)
     m_pending_signals |= 1 << (signal - 1);
     m_pending_signals |= 1 << (signal - 1);
 }
 }
 
 
+// Certain exceptions, such as SIGSEGV and SIGILL, put a
+// thread into a state where the signal handler must be
+// invoked immediately, otherwise it will continue to fault.
+// This function should be used in an exception handler to
+// ensure that when the thread resumes, it's executing in
+// the appropriate signal handler.
+void Thread::send_urgent_signal_to_self(u8 signal)
+{
+    // FIXME: because of a bug in dispatch_signal we can't
+    // setup a signal while we are the current thread. Because of
+    // this we use a work-around where we send the signal and then
+    // block, allowing the scheduler to properly dispatch the signal
+    // before the thread is next run.
+    send_signal(signal, &process());
+    (void)block<SemiPermanentBlocker>(SemiPermanentBlocker::Reason::Signal);
+}
+
 bool Thread::has_unmasked_pending_signals() const
 bool Thread::has_unmasked_pending_signals() const
 {
 {
     return m_pending_signals & ~m_signal_mask;
     return m_pending_signals & ~m_signal_mask;
@@ -330,6 +347,13 @@ bool Thread::should_ignore_signal(u8 signal) const
     return false;
     return false;
 }
 }
 
 
+bool Thread::has_signal_handler(u8 signal) const
+{
+    ASSERT(signal < 32);
+    auto& action = m_signal_action_data[signal];
+    return !action.handler_or_sigaction.is_null();
+}
+
 ShouldUnblockThread Thread::dispatch_signal(u8 signal)
 ShouldUnblockThread Thread::dispatch_signal(u8 signal)
 {
 {
     ASSERT_INTERRUPTS_DISABLED();
     ASSERT_INTERRUPTS_DISABLED();

+ 2 - 0
Kernel/Thread.h

@@ -273,6 +273,7 @@ public:
     void set_selector(u16 s) { m_far_ptr.selector = s; }
     void set_selector(u16 s) { m_far_ptr.selector = s; }
     void set_state(State);
     void set_state(State);
 
 
+    void send_urgent_signal_to_self(u8 signal);
     void send_signal(u8 signal, Process* sender);
     void send_signal(u8 signal, Process* sender);
     void consider_unblock(time_t now_sec, long now_usec);
     void consider_unblock(time_t now_sec, long now_usec);
 
 
@@ -283,6 +284,7 @@ public:
     bool has_unmasked_pending_signals() const;
     bool has_unmasked_pending_signals() const;
     void terminate_due_to_signal(u8 signal);
     void terminate_due_to_signal(u8 signal);
     bool should_ignore_signal(u8 signal) const;
     bool should_ignore_signal(u8 signal) const;
+    bool has_signal_handler(u8 signal) const;
 
 
     FPUState& fpu_state() { return *m_fpu_state; }
     FPUState& fpu_state() { return *m_fpu_state; }
     bool has_used_fpu() const { return m_has_used_fpu; }
     bool has_used_fpu() const { return m_has_used_fpu; }