]> rtime.felk.cvut.cz Git - l4.git/blobdiff - l4/pkg/valgrind/src/valgrind-3.6.0-svn/coregrind/m_signals.c
update
[l4.git] / l4 / pkg / valgrind / src / valgrind-3.6.0-svn / coregrind / m_signals.c
index dd29fc43ba69115ed9535ce07ffab1b78edb7bdd..a40b9be690dc38b0034e18c9e8d495c381784c0b 100644 (file)
    VG_(sigtimedwait_zero).  This is trivial on Linux, since it's just a
    syscall.  But on Darwin and AIX, we have to cobble together the
    functionality in a tedious, longwinded and probably error-prone way.
+
+   Finally, if a gdb is debugging the process under valgrind,
+   the signal can be ignored if gdb tells this. So, before resuming the
+   scheduler/delivering the signal, a call to VG_(gdbserver_report_signal)
+   is done. If this returns True, the signal is delivered.
  */
 
 #include "pub_core_basics.h"
 #include "pub_core_vki.h"
 #include "pub_core_vkiscnums.h"
 #include "pub_core_debuglog.h"
+#include "pub_core_libcsetjmp.h"    // to keep _threadstate.h happy
 #include "pub_core_threadstate.h"
 #include "pub_core_xarray.h"
 #include "pub_core_clientstate.h"
 #include "pub_core_aspacemgr.h"
 #include "pub_core_debugger.h"      // For VG_(start_debugger)
 #include "pub_core_errormgr.h"
+#include "pub_core_gdbserver.h"
 #include "pub_core_libcbase.h"
 #include "pub_core_libcassert.h"
 #include "pub_core_libcprint.h"
@@ -378,6 +385,7 @@ typedef struct SigQueue {
         (srP)->misc.ARM.r14 = (uc)->uc_mcontext.arm_lr; \
         (srP)->misc.ARM.r12 = (uc)->uc_mcontext.arm_ip; \
         (srP)->misc.ARM.r11 = (uc)->uc_mcontext.arm_fp; \
+        (srP)->misc.ARM.r7  = (uc)->uc_mcontext.arm_r7; \
       }
 
 #elif defined(VGP_ppc32_aix5)
@@ -533,6 +541,23 @@ typedef struct SigQueue {
 #  define VG_UCONTEXT_LINK_REG(uc)        0 /* Dude, where's my LR? */
 
 
+#elif defined(VGP_s390x_linux)
+
+#  define VG_UCONTEXT_INSTR_PTR(uc)       ((uc)->uc_mcontext.regs.psw.addr)
+#  define VG_UCONTEXT_STACK_PTR(uc)       ((uc)->uc_mcontext.regs.gprs[15])
+#  define VG_UCONTEXT_FRAME_PTR(uc)       ((uc)->uc_mcontext.regs.gprs[11])
+#  define VG_UCONTEXT_SYSCALL_SYSRES(uc)                        \
+      VG_(mk_SysRes_s390x_linux)((uc)->uc_mcontext.regs.gprs[2])
+#  define VG_UCONTEXT_LINK_REG(uc) ((uc)->uc_mcontext.regs.gprs[14])
+
+#  define VG_UCONTEXT_TO_UnwindStartRegs(srP, uc)        \
+      { (srP)->r_pc = (ULong)((uc)->uc_mcontext.regs.psw.addr);    \
+        (srP)->r_sp = (ULong)((uc)->uc_mcontext.regs.gprs[15]);    \
+        (srP)->misc.S390X.r_fp = (uc)->uc_mcontext.regs.gprs[11];  \
+        (srP)->misc.S390X.r_lr = (uc)->uc_mcontext.regs.gprs[14];  \
+      }
+
+
 #else 
 #  error Unknown platform
 #endif
@@ -651,11 +676,14 @@ typedef
 
 static SKSS skss;
 
-static Bool is_sig_ign(Int sigNo)
+/* returns True if signal is to be ignored. 
+   To check this, possibly call gdbserver with tid. */
+static Bool is_sig_ign(Int sigNo, ThreadId tid)
 {
    vg_assert(sigNo >= 1 && sigNo <= _VKI_NSIG);
 
-   return scss.scss_per_sig[sigNo].scss_handler == VKI_SIG_IGN;
+   return scss.scss_per_sig[sigNo].scss_handler == VKI_SIG_IGN
+      || !VG_(gdbserver_report_signal) (sigNo, tid);
 }
 
 /* ---------------------------------------------------------------------
@@ -871,6 +899,13 @@ extern void my_sigreturn(void);
    "my_sigreturn:\n" \
    ".long 0\n"
 
+#elif defined(VGP_s390x_linux)
+#  define _MY_SIGRETURN(name) \
+   ".text\n" \
+   "my_sigreturn:\n" \
+   " svc " #name "\n" \
+   ".previous\n"
+
 #else
 #  error Unknown platform
 #endif
@@ -1421,8 +1456,10 @@ void VG_(kill_self)(Int sigNo)
    VG_(sigprocmask)(VKI_SIG_UNBLOCK, &mask, &origmask);
 
    r = VG_(kill)(VG_(getpid)(), sigNo);
+#  if defined(VGO_linux)
    /* This sometimes fails with EPERM on Darwin.  I don't know why. */
-   /* vg_assert(r == 0); */
+   vg_assert(r == 0);
+#  endif
 
    VG_(convert_sigaction_fromK_to_toK)( &origsa, &origsa2 );
    VG_(sigaction)(sigNo, &origsa2, NULL);
@@ -1790,7 +1827,7 @@ static void resume_scheduler(ThreadId tid)
    if (tst->sched_jmpbuf_valid) {
       /* Can't continue; must longjmp back to the scheduler and thus
          enter the sighandler immediately. */
-      __builtin_longjmp(tst->sched_jmpbuf, True);
+      VG_MINIMAL_LONGJMP(tst->sched_jmpbuf);
    }
 }
 
@@ -1812,6 +1849,9 @@ static void synth_fault_common(ThreadId tid, Addr addr, Int si_code)
    info.si_code = si_code;
    info.VKI_SIGINFO_si_addr = (void*)addr;
 
+   /* even if gdbserver indicates to ignore the signal, we will deliver it */
+   VG_(gdbserver_report_signal) (VKI_SIGSEGV, tid);
+
    /* If they're trying to block the signal, force it to be delivered */
    if (VG_(sigismember)(&VG_(threads)[tid].sig_mask, VKI_SIGSEGV))
       VG_(set_default_handler)(VKI_SIGSEGV);
@@ -1851,8 +1891,12 @@ void VG_(synth_sigill)(ThreadId tid, Addr addr)
    info.si_code  = VKI_ILL_ILLOPC; /* jrs: no idea what this should be */
    info.VKI_SIGINFO_si_addr = (void*)addr;
 
-   resume_scheduler(tid);
-   deliver_signal(tid, &info, NULL);
+   if (VG_(gdbserver_report_signal) (VKI_SIGILL, tid)) {
+      resume_scheduler(tid);
+      deliver_signal(tid, &info, NULL);
+   }
+   else
+      resume_scheduler(tid);
 }
 
 // Synthesise a SIGBUS.
@@ -1872,8 +1916,12 @@ void VG_(synth_sigbus)(ThreadId tid)
       in .si_addr.  Oh well. */
    /* info.VKI_SIGINFO_si_addr = (void*)addr; */
 
-   resume_scheduler(tid);
-   deliver_signal(tid, &info, NULL);
+   if (VG_(gdbserver_report_signal) (VKI_SIGBUS, tid)) {
+      resume_scheduler(tid);
+      deliver_signal(tid, &info, NULL);
+   }
+   else
+      resume_scheduler(tid);
 }
 
 // Synthesise a SIGTRAP.
@@ -1907,8 +1955,13 @@ void VG_(synth_sigtrap)(ThreadId tid)
    uc.uc_mcontext->__es.__err = 0;
 #  endif
 
-   resume_scheduler(tid);
-   deliver_signal(tid, &info, &uc);
+   /* fixs390: do we need to do anything here for s390 ? */
+   if (VG_(gdbserver_report_signal) (VKI_SIGTRAP, tid)) {
+      resume_scheduler(tid);
+      deliver_signal(tid, &info, &uc);
+   }
+   else
+      resume_scheduler(tid);
 }
 
 /* Make a signal pending for a thread, for later delivery.
@@ -2088,7 +2141,7 @@ void async_signalhandler ( Int sigNo,
 
    /* (2) */
    /* Set up the thread's state to deliver a signal */
-   if (!is_sig_ign(info->si_signo))
+   if (!is_sig_ign(info->si_signo, tid))
       deliver_signal(tid, info, uc);
 
    /* It's crucial that (1) and (2) happen in the order (1) then (2)
@@ -2259,6 +2312,19 @@ void sync_signalhandler_from_user ( ThreadId tid,
    }
 }
 
+/* Returns the reported fault address for an exact address */
+static Addr fault_mask(Addr in)
+{
+   /*  We have to use VG_PGROUNDDN because faults on s390x only deliver
+       the page address but not the address within a page.
+    */
+#  if defined(VGA_s390x)
+   return VG_PGROUNDDN(in);
+#  else
+   return in;
+#endif
+}
+
 /* Returns True if the sync signal was due to the stack requiring extension
    and the extension was successful.
 */
@@ -2296,7 +2362,7 @@ static Bool extend_stack_if_appropriate(ThreadId tid, vki_siginfo_t* info)
        && seg_next
        && seg_next->kind == SkAnonC
        && seg->end+1 == seg_next->start
-       && fault >= (esp - VG_STACK_REDZONE_SZB)) {
+       && fault >= fault_mask(esp - VG_STACK_REDZONE_SZB)) {
       /* If the fault address is above esp but below the current known
          stack segment base, and it was a fault because there was
          nothing mapped there (as opposed to a permissions fault),
@@ -2350,10 +2416,15 @@ void sync_signalhandler_from_kernel ( ThreadId tid,
       }
 
       if (VG_(in_generated_code)) {
-         /* Can't continue; must longjmp back to the scheduler and thus
-            enter the sighandler immediately. */
-         deliver_signal(tid, info, uc);
-         resume_scheduler(tid);
+         if (VG_(gdbserver_report_signal) (sigNo, tid)
+             || VG_(sigismember)(&tst->sig_mask, sigNo)) {
+            /* Can't continue; must longjmp back to the scheduler and thus
+               enter the sighandler immediately. */
+            deliver_signal(tid, info, uc);
+            resume_scheduler(tid);
+         }
+         else
+            resume_scheduler(tid);
       }
 
       /* If resume_scheduler returns or its our fault, it means we
@@ -2553,7 +2624,7 @@ void VG_(poll_signals)(ThreadId tid)
       /* OK, something to do; deliver it */
       if (VG_(clo_trace_signals))
          VG_(dmsg)("Polling found signal %d for tid %d\n", sip->si_signo, tid);
-      if (!is_sig_ign(sip->si_signo))
+      if (!is_sig_ign(sip->si_signo, tid))
         deliver_signal(tid, sip, NULL);
       else if (VG_(clo_trace_signals))
          VG_(dmsg)("   signal %d ignored\n", sip->si_signo);