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"
(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)
# 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
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);
}
/* ---------------------------------------------------------------------
"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
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);
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);
}
}
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);
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.
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.
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.
/* (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)
}
}
+/* 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.
*/
&& 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),
}
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
/* 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);