Forwards decls.
------------------------------------------------------------------ */
-static void sync_signalhandler ( Int sigNo, vki_siginfo_t *info, struct vki_ucontext * );
-static void async_signalhandler ( Int sigNo, vki_siginfo_t *info, struct vki_ucontext * );
-static void sigvgkill_handler ( Int sigNo, vki_siginfo_t *info, struct vki_ucontext * );
+static void sync_signalhandler ( Int sigNo, vki_siginfo_t *info,
+ struct vki_ucontext * );
+static void async_signalhandler ( Int sigNo, vki_siginfo_t *info,
+ struct vki_ucontext * );
+static void sigvgkill_handler ( Int sigNo, vki_siginfo_t *info,
+ struct vki_ucontext * );
static const Char *signame(Int sigNo);
/* ------ Macros for pulling stuff out of ucontexts ------ */
+/* Q: what does UCONTEXT_SYSCALL_SYSRES do? A: let's suppose the
+ machine context (uc) reflects the situation that a syscall had just
+ completed, quite literally -- that is, that the program counter was
+ now at the instruction following the syscall. (or we're slightly
+ downstream, but we're sure no relevant register has yet changed
+ value.) Then UCONTEXT_SYSCALL_SYSRES returns a SysRes reflecting
+ the result of the syscall; it does this by fishing relevant bits of
+ the machine state out of the uc. Of course if the program counter
+ was somewhere else entirely then the result is likely to be
+ meaningless, so the caller of UCONTEXT_SYSCALL_SYSRES has to be
+ very careful to pay attention to the results only when it is sure
+ that the said constraint on the program counter is indeed valid. */
#if defined(VGP_x86_linux)
# define VG_UCONTEXT_INSTR_PTR(uc) ((uc)->uc_mcontext.eip)
# define VG_UCONTEXT_STACK_PTR(uc) ((uc)->uc_mcontext.esp)
case VKI_SIGCONT:
/* Let the kernel handle SIGCONT unless the client is actually
catching it. */
- case VKI_SIGCHLD:
- case VKI_SIGWINCH:
- case VKI_SIGURG:
- /* For signals which are have a default action of Ignore,
- only set a handler if the client has set a signal handler.
- Otherwise the kernel will interrupt a syscall which
- wouldn't have otherwise been interrupted. */
+ case VKI_SIGCHLD:
+ case VKI_SIGWINCH:
+ case VKI_SIGURG:
+ /* For signals which are have a default action of Ignore,
+ only set a handler if the client has set a signal handler.
+ Otherwise the kernel will interrupt a syscall which
+ wouldn't have otherwise been interrupted. */
if (scss.scss_per_sig[sig].scss_handler == VKI_SIG_DFL)
skss_handler = VKI_SIG_DFL;
else if (scss.scss_per_sig[sig].scss_handler == VKI_SIG_IGN)
extern void my_sigreturn(void);
#if defined(VGP_x86_linux)
-# define _MYSIG(name) \
+# define _MY_SIGRETURN(name) \
".text\n" \
"my_sigreturn:\n" \
" movl $" #name ", %eax\n" \
" int $0x80\n" \
".previous\n"
#elif defined(VGP_amd64_linux)
-# define _MYSIG(name) \
+# define _MY_SIGRETURN(name) \
".text\n" \
"my_sigreturn:\n" \
" movq $" #name ", %rax\n" \
" syscall\n" \
".previous\n"
#elif defined(VGP_ppc32_linux)
-# define _MYSIG(name) \
+# define _MY_SIGRETURN(name) \
".text\n" \
"my_sigreturn:\n" \
" li 0, " #name "\n" \
" sc\n" \
".previous\n"
#elif defined(VGP_ppc64_linux)
-# define _MYSIG(name) \
+# define _MY_SIGRETURN(name) \
".align 2\n" \
".globl my_sigreturn\n" \
".section \".opd\",\"aw\"\n" \
" li 0, " #name "\n" \
" sc\n"
#elif defined(VGP_ppc32_aix5)
-# define _MYSIG(name) \
+# define _MY_SIGRETURN(name) \
".globl my_sigreturn\n" \
"my_sigreturn:\n" \
".long 0\n"
#elif defined(VGP_ppc64_aix5)
-# define _MYSIG(name) \
+# define _MY_SIGRETURN(name) \
".globl my_sigreturn\n" \
"my_sigreturn:\n" \
".long 0\n"
# error Unknown platform
#endif
-#define MYSIG(name) _MYSIG(name)
+#define MY_SIGRETURN(name) _MY_SIGRETURN(name)
asm(
- MYSIG(__NR_rt_sigreturn)
+ MY_SIGRETURN(__NR_rt_sigreturn)
);
{
ThreadState *tst = VG_(get_ThreadState)(tid);
- return (m_SP - (Addr)tst->altstack.ss_sp < tst->altstack.ss_size);
+ return (m_SP - (Addr)tst->altstack.ss_sp < (Addr)tst->altstack.ss_size);
}
static Int sas_ss_flags ( ThreadId tid, Addr m_SP )
if (VG_(clo_trace_signals))
VG_(message)(Vg_DebugExtraMsg,
"sys_sigaltstack: tid %d, "
- "ss %p, oss %p (current SP %p)",
- tid, (void*)ss, (void*)oss, (void*)m_SP );
+ "ss %p{%p,sz=%llu,flags=0x%llx}, oss %p (current SP %p)",
+ tid, (void*)ss,
+ ss ? ss->ss_sp : 0,
+ (ULong)(ss ? ss->ss_size : 0),
+ (ULong)(ss ? ss->ss_flags : 0),
+ (void*)oss, (void*)m_SP );
if (oss != NULL) {
oss->ss_sp = VG_(threads)[tid].altstack.ss_sp;
oss->ss_size = VG_(threads)[tid].altstack.ss_size;
- oss->ss_flags = VG_(threads)[tid].altstack.ss_flags | sas_ss_flags(tid, m_SP);
+ oss->ss_flags = VG_(threads)[tid].altstack.ss_flags
+ | sas_ss_flags(tid, m_SP);
}
if (ss != NULL) {
}
static
-const Char *format_sigset ( const vki_sigset_t* set )
+HChar* format_sigset ( const vki_sigset_t* set )
{
- static Char buf[128];
+ static HChar buf[128];
int w;
VG_(strcpy)(buf, "");
{
if (VG_(clo_trace_signals))
VG_(message)(Vg_DebugExtraMsg,
- "do_setmask: tid = %d how = %d (%s), set = %p %s",
+ "do_setmask: tid = %d how = %d (%s), newset = %p (%s)",
tid, how,
how==VKI_SIG_BLOCK ? "SIG_BLOCK" : (
how==VKI_SIG_UNBLOCK ? "SIG_UNBLOCK" : (
how==VKI_SIG_SETMASK ? "SIG_SETMASK" : "???")),
- newset, format_sigset(newset));
+ newset, newset ? format_sigset(newset) : "NULL" );
/* Just do this thread. */
vg_assert(VG_(is_valid_tid)(tid));
/* Set up a stack frame (VgSigContext) for the client's signal
handler. */
static
-void push_signal_frame ( ThreadId tid, const vki_siginfo_t *siginfo, const struct vki_ucontext *uc )
+void push_signal_frame ( ThreadId tid, const vki_siginfo_t *siginfo,
+ const struct vki_ucontext *uc )
{
Addr esp_top_of_frame;
ThreadState* tst;
= (Addr)(tst->altstack.ss_sp) + tst->altstack.ss_size;
if (VG_(clo_trace_signals))
VG_(message)(Vg_DebugMsg,
- "delivering signal %d (%s) to thread %d: on ALT STACK (%p-%p; %ld bytes)",
+ "delivering signal %d (%s) to thread %d: "
+ "on ALT STACK (%p-%p; %ld bytes)",
sigNo, signame(sigNo), tid,
tst->altstack.ss_sp,
(UChar *)tst->altstack.ss_sp + tst->altstack.ss_size,
static const Char *signame(Int sigNo)
{
- static Char buf[10];
+ static Char buf[20];
switch(sigNo) {
case VKI_SIGHUP: return "SIGHUP";
vg_assert(!core || (core && terminate));
if (VG_(clo_trace_signals))
- VG_(message)(Vg_DebugMsg, "delivering %d (code %d) to default handler; action: %s%s",
- sigNo, info->si_code, terminate ? "terminate" : "ignore", core ? "+core" : "");
+ VG_(message)(Vg_DebugMsg,
+ "delivering %d (code %d) to default handler; action: %s%s",
+ sigNo, info->si_code, terminate ? "terminate" : "ignore",
+ core ? "+core" : "");
if (!terminate)
return; /* nothing to do */
This updates the thread state, but it does not set it to be
Runnable.
*/
-static void deliver_signal ( ThreadId tid, const vki_siginfo_t *info, const struct vki_ucontext *uc )
+static void deliver_signal ( ThreadId tid, const vki_siginfo_t *info,
+ const struct vki_ucontext *uc )
{
Int sigNo = info->si_signo;
SCSS_Per_Signal *handler = &scss.scss_per_sig[sigNo];
vg_assert(VG_(threads)[tid].status == VgTs_Runnable);
+ VG_(memset)(&info, 0, sizeof(info));
info.si_signo = VKI_SIGSEGV;
info.si_code = si_code;
info.VKI_SIGINFO_si_addr = (void*)addr;
vg_assert(VG_(threads)[tid].status == VgTs_Runnable);
+ VG_(memset)(&info, 0, sizeof(info));
info.si_signo = VKI_SIGILL;
info.si_code = VKI_ILL_ILLOPC; /* jrs: no idea what this should be */
info.VKI_SIGINFO_si_addr = (void*)addr;
vg_assert(VG_(threads)[tid].status == VgTs_Runnable);
+ VG_(memset)(&info, 0, sizeof(info));
+ VG_(memset)(&uc, 0, sizeof(uc));
info.si_signo = VKI_SIGTRAP;
info.si_code = VKI_TRAP_BRKPT; /* tjh: only ever called for a brkpt ins */
#if defined(VGA_x86) || defined(VGA_amd64)
since that's the only time this set of signals is unblocked.
*/
static
-void async_signalhandler ( Int sigNo, vki_siginfo_t *info, struct vki_ucontext *uc )
+void async_signalhandler ( Int sigNo,
+ vki_siginfo_t *info, struct vki_ucontext *uc )
{
- ThreadId tid = VG_(lwpid_to_vgtid)(VG_(gettid)());
- ThreadState *tst = VG_(get_ThreadState)(tid);
+ ThreadId tid = VG_(lwpid_to_vgtid)(VG_(gettid)());
+ ThreadState* tst = VG_(get_ThreadState)(tid);
-#ifdef VGO_linux
+ /* The thread isn't currently running, make it so before going on */
+ vg_assert(tst->status == VgTs_WaitSys);
+ VG_(acquire_BigLock)(tid, "async_signalhandler");
+
+# if defined(VGO_linux)
/* The linux kernel uses the top 16 bits of si_code for it's own
use and only exports the bottom 16 bits to user space - at least
that is the theory, but it turns out that there are some kernels
mask them off) sign extends them when exporting to user space so
we do the same thing here. */
info->si_code = (Short)info->si_code;
-#endif
+# endif
if (VG_(clo_trace_signals))
VG_(message)(Vg_DebugMsg, "Async handler got signal %d for tid %d info %d",
sigNo, tid, info->si_code);
- vg_assert(tst->status == VgTs_WaitSys);
-
- /* The thread isn't currently running, make it so before going on */
- VG_(acquire_BigLock)(tid, "async_signalhandler");
-
/* Update thread state properly */
VG_(fixup_guest_state_after_syscall_interrupted)(
tid,
handler. */
resume_scheduler(tid);
- VG_(core_panic)("async_signalhandler: got unexpected signal while outside of scheduler");
+ VG_(core_panic)("async_signalhandler: got unexpected signal "
+ "while outside of scheduler");
}
/* Extend the stack to cover addr. maxsize is the limit the stack can grow to.
Receive a sync signal from the host.
*/
static
-void sync_signalhandler ( Int sigNo, vki_siginfo_t *info, struct vki_ucontext *uc )
+void sync_signalhandler ( Int sigNo,
+ vki_siginfo_t *info, struct vki_ucontext *uc )
{
ThreadId tid = VG_(lwpid_to_vgtid)(VG_(gettid)());
+ if (0)
+ VG_(printf)("sync_sighandler(%d, %p, %p)\n", sigNo, info, uc);
+
vg_assert(info != NULL);
vg_assert(info->si_signo == sigNo);
vg_assert(sigNo == VKI_SIGSEGV ||
sigNo == VKI_SIGILL ||
sigNo == VKI_SIGTRAP);
-#ifdef VGO_linux
+# if defined(VGO_linux)
/* The linux kernel uses the top 16 bits of si_code for it's own
use and only exports the bottom 16 bits to user space - at least
that is the theory, but it turns out that there are some kernels
mask them off) sign extends them when exporting to user space so
we do the same thing here. */
info->si_code = (Short)info->si_code;
-#endif
+# endif
/* // debug code:
if (0) {
Valgrind internally.
*/
VG_(message)(Vg_DebugMsg,
- "VALGRIND INTERNAL ERROR: Valgrind received a signal %d (%s) - exiting",
+ "VALGRIND INTERNAL ERROR: Valgrind received "
+ "a signal %d (%s) - exiting",
sigNo, signame(sigNo));
VG_(message)(Vg_DebugMsg,
blocked in, and return to the scheduler. This doesn't mark the thread
as exiting; that's the caller's job.
*/
-static void sigvgkill_handler(int signo, vki_siginfo_t *si, struct vki_ucontext *uc)
+static void sigvgkill_handler(int signo, vki_siginfo_t *si,
+ struct vki_ucontext *uc)
{
ThreadId tid = VG_(lwpid_to_vgtid)(VG_(gettid)());
ThreadStatus at_signal = VG_(threads)[tid].status;
}
if (VG_(clo_trace_signals))
- VG_(message)(Vg_DebugMsg, "Max kernel-supported signal is %d", VG_(max_signal));
+ VG_(message)(Vg_DebugMsg, "Max kernel-supported signal is %d",
+ VG_(max_signal));
/* Our private internal signals are treated as ignored */
scss.scss_per_sig[VG_SIGVGKILL].scss_handler = VKI_SIG_IGN;