/* * Copyright (c) 1991, 1992 Paul Kranenburg * Copyright (c) 1993 Branko Lankester * Copyright (c) 1993, 1994, 1995, 1996 Rick Sladkey * Copyright (c) 1996-1999 Wichert Akkerman * Copyright (c) 1999 IBM Deutschland Entwicklung GmbH, IBM Corporation * Linux for s390 port by D.J. Barrow * * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * $Id$ */ #include "defs.h" #include #include #include #include #ifdef SVR4 #include #endif /* SVR4 */ #ifdef HAVE_SYS_REG_H # include #ifndef PTRACE_PEEKUSR # define PTRACE_PEEKUSR PTRACE_PEEKUSER #endif #ifndef PTRACE_POKEUSR # define PTRACE_POKEUSR PTRACE_POKEUSER #endif #elif defined(HAVE_LINUX_PTRACE_H) #undef PTRACE_SYSCALL # ifdef HAVE_STRUCT_IA64_FPREG # define ia64_fpreg XXX_ia64_fpreg # endif # ifdef HAVE_STRUCT_PT_ALL_USER_REGS # define pt_all_user_regs XXX_pt_all_user_regs # endif #include # undef ia64_fpreg # undef pt_all_user_regs #endif #ifdef LINUX #ifdef IA64 # include #endif #if defined (LINUX) && defined (SPARC64) # undef PTRACE_GETREGS # define PTRACE_GETREGS PTRACE_GETREGS64 # undef PTRACE_SETREGS # define PTRACE_SETREGS PTRACE_SETREGS64 #endif /* LINUX && SPARC64 */ #if defined (SPARC) || defined (SPARC64) || defined (MIPS) typedef struct { struct pt_regs si_regs; int si_mask; } m_siginfo_t; #elif defined HAVE_ASM_SIGCONTEXT_H #if !defined(IA64) && !defined(X86_64) #include #endif /* !IA64 && !X86_64 */ #else /* !HAVE_ASM_SIGCONTEXT_H */ #if defined I386 && !defined HAVE_STRUCT_SIGCONTEXT_STRUCT struct sigcontext_struct { unsigned short gs, __gsh; unsigned short fs, __fsh; unsigned short es, __esh; unsigned short ds, __dsh; unsigned long edi; unsigned long esi; unsigned long ebp; unsigned long esp; unsigned long ebx; unsigned long edx; unsigned long ecx; unsigned long eax; unsigned long trapno; unsigned long err; unsigned long eip; unsigned short cs, __csh; unsigned long eflags; unsigned long esp_at_signal; unsigned short ss, __ssh; unsigned long i387; unsigned long oldmask; unsigned long cr2; }; #else /* !I386 */ #if defined M68K && !defined HAVE_STRUCT_SIGCONTEXT struct sigcontext { unsigned long sc_mask; unsigned long sc_usp; unsigned long sc_d0; unsigned long sc_d1; unsigned long sc_a0; unsigned long sc_a1; unsigned short sc_sr; unsigned long sc_pc; unsigned short sc_formatvec; }; #endif /* M68K */ #endif /* !I386 */ #endif /* !HAVE_ASM_SIGCONTEXT_H */ #ifndef NSIG #warning: NSIG is not defined, using 32 #define NSIG 32 #endif #ifdef ARM /* Ugh. Is this really correct? ARM has no RT signals?! */ #undef NSIG #define NSIG 32 #endif #endif /* LINUX */ #if defined(SUNOS4) || defined(FREEBSD) static const struct xlat sigvec_flags[] = { { SV_ONSTACK, "SV_ONSTACK" }, { SV_INTERRUPT, "SV_INTERRUPT" }, { SV_RESETHAND, "SV_RESETHAND" }, { SA_NOCLDSTOP, "SA_NOCLDSTOP" }, { 0, NULL }, }; #endif /* SUNOS4 || FREEBSD */ #ifdef HAVE_SIGACTION #if defined LINUX && (defined I386 || defined X86_64) /* The libc headers do not define this constant since it should only be used by the implementation. So we define it here. */ # ifndef SA_RESTORER # define SA_RESTORER 0x04000000 # endif #endif static const struct xlat sigact_flags[] = { #ifdef SA_RESTORER { SA_RESTORER, "SA_RESTORER" }, #endif #ifdef SA_STACK { SA_STACK, "SA_STACK" }, #endif #ifdef SA_RESTART { SA_RESTART, "SA_RESTART" }, #endif #ifdef SA_INTERRUPT { SA_INTERRUPT, "SA_INTERRUPT" }, #endif #ifdef SA_NODEFER { SA_NODEFER, "SA_NODEFER" }, #endif #if defined SA_NOMASK && SA_NODEFER != SA_NOMASK { SA_NOMASK, "SA_NOMASK" }, #endif #ifdef SA_RESETHAND { SA_RESETHAND, "SA_RESETHAND" }, #endif #if defined SA_ONESHOT && SA_ONESHOT != SA_RESETHAND { SA_ONESHOT, "SA_ONESHOT" }, #endif #ifdef SA_SIGINFO { SA_SIGINFO, "SA_SIGINFO" }, #endif #ifdef SA_RESETHAND { SA_RESETHAND, "SA_RESETHAND" }, #endif #ifdef SA_ONSTACK { SA_ONSTACK, "SA_ONSTACK" }, #endif #ifdef SA_NODEFER { SA_NODEFER, "SA_NODEFER" }, #endif #ifdef SA_NOCLDSTOP { SA_NOCLDSTOP, "SA_NOCLDSTOP" }, #endif #ifdef SA_NOCLDWAIT { SA_NOCLDWAIT, "SA_NOCLDWAIT" }, #endif #ifdef _SA_BSDCALL { _SA_BSDCALL, "_SA_BSDCALL" }, #endif #ifdef SA_NOPTRACE { SA_NOPTRACE, "SA_NOPTRACE" }, #endif { 0, NULL }, }; static const struct xlat sigprocmaskcmds[] = { { SIG_BLOCK, "SIG_BLOCK" }, { SIG_UNBLOCK, "SIG_UNBLOCK" }, { SIG_SETMASK, "SIG_SETMASK" }, #ifdef SIG_SETMASK32 { SIG_SETMASK32,"SIG_SETMASK32" }, #endif { 0, NULL }, }; #endif /* HAVE_SIGACTION */ /* Anonymous realtime signals. */ /* Under glibc 2.1, SIGRTMIN et al are functions, but __SIGRTMIN is a constant. This is what we want. Otherwise, just use SIGRTMIN. */ #ifdef SIGRTMIN #ifndef __SIGRTMIN #define __SIGRTMIN SIGRTMIN #define __SIGRTMAX SIGRTMAX /* likewise */ #endif #endif /* Note on the size of sigset_t: * * In glibc, sigset_t is an array with space for 1024 bits (!), * even though all arches supported by Linux have only 64 signals * except MIPS, which has 128. IOW, it is 128 bytes long. * * In-kernel sigset_t is sized correctly (it is either 64 or 128 bit long). * However, some old syscall return only 32 lower bits (one word). * Example: sys_sigpending vs sys_rt_sigpending. * * Be aware of this fact when you try to * memcpy(&tcp->u_arg[1], &something, sizeof(sigset_t)) * - sizeof(sigset_t) is much bigger than you think, * it may overflow tcp->u_arg[] array, and it may try to copy more data * than is really available in . * Similarly, * umoven(tcp, addr, sizeof(sigset_t), &sigset) * may be a bad idea: it'll try to read much more data than needed * to fetch a sigset_t. * Use (NSIG / 8) as a size instead. */ const char * signame(int sig) { static char buf[sizeof("SIGRT_%d") + sizeof(int)*3]; if (sig >= 0 && sig < nsignals) return signalent[sig]; #ifdef SIGRTMIN if (sig >= __SIGRTMIN && sig <= __SIGRTMAX) { sprintf(buf, "SIGRT_%d", (int)(sig - __SIGRTMIN)); return buf; } #endif sprintf(buf, "%d", sig); return buf; } #ifndef UNIXWARE static void long_to_sigset(long l, sigset_t *s) { sigemptyset(s); *(long *)s = l; } #endif static int copy_sigset_len(struct tcb *tcp, long addr, sigset_t *s, int len) { if (len > sizeof(*s)) len = sizeof(*s); sigemptyset(s); if (umoven(tcp, addr, len, (char *)s) < 0) return -1; return 0; } #ifdef LINUX /* Original sigset is unsigned long */ #define copy_sigset(tcp, addr, s) copy_sigset_len(tcp, addr, s, sizeof(long)) #else #define copy_sigset(tcp, addr, s) copy_sigset_len(tcp, addr, s, sizeof(sigset_t)) #endif static const char * sprintsigmask(const char *str, sigset_t *mask, int rt) /* set might include realtime sigs */ { /* Was [8 * sizeof(sigset_t) * 8], but * glibc sigset_t is huge (1024 bits = 128 *bytes*), * and we were ending up with 8k (!) buffer here. * * No Unix system can have sig > 255 * (waitpid API won't be able to indicate death from one) * and sig 0 doesn't exist either. * Therefore max possible no of sigs is 255: 1..255 */ static char outstr[8 * 255]; int i, nsigs; int maxsigs; const char *format; char *s; strcpy(outstr, str); s = outstr + strlen(outstr); nsigs = 0; maxsigs = nsignals; #ifdef __SIGRTMAX if (rt) maxsigs = __SIGRTMAX; /* instead */ #endif for (i = 1; i < maxsigs; i++) { if (sigismember(mask, i) == 1) nsigs++; } if (nsigs >= nsignals * 2 / 3) { *s++ = '~'; for (i = 1; i < maxsigs; i++) { switch (sigismember(mask, i)) { case 1: sigdelset(mask, i); break; case 0: sigaddset(mask, i); break; } } } format = "%s"; *s++ = '['; for (i = 1; i < maxsigs; i++) { if (sigismember(mask, i) == 1) { /* real-time signals on solaris don't have * signalent entries */ if (i < nsignals) { sprintf(s, format, signalent[i] + 3); } #ifdef SIGRTMIN else if (i >= __SIGRTMIN && i <= __SIGRTMAX) { char tsig[40]; sprintf(tsig, "RT_%u", i - __SIGRTMIN); sprintf(s, format, tsig); } #endif /* SIGRTMIN */ else { char tsig[32]; sprintf(tsig, "%u", i); sprintf(s, format, tsig); } s += strlen(s); format = " %s"; } } *s++ = ']'; *s = '\0'; return outstr; } static void printsigmask(sigset_t *mask, int rt) { tprints(sprintsigmask("", mask, rt)); } void printsignal(int nr) { tprints(signame(nr)); } void print_sigset(struct tcb *tcp, long addr, int rt) { sigset_t ss; if (!addr) tprints("NULL"); else if (copy_sigset(tcp, addr, &ss) < 0) tprintf("%#lx", addr); else printsigmask(&ss, rt); } #ifdef LINUX #ifndef ILL_ILLOPC #define ILL_ILLOPC 1 /* illegal opcode */ #define ILL_ILLOPN 2 /* illegal operand */ #define ILL_ILLADR 3 /* illegal addressing mode */ #define ILL_ILLTRP 4 /* illegal trap */ #define ILL_PRVOPC 5 /* privileged opcode */ #define ILL_PRVREG 6 /* privileged register */ #define ILL_COPROC 7 /* coprocessor error */ #define ILL_BADSTK 8 /* internal stack error */ #define FPE_INTDIV 1 /* integer divide by zero */ #define FPE_INTOVF 2 /* integer overflow */ #define FPE_FLTDIV 3 /* floating point divide by zero */ #define FPE_FLTOVF 4 /* floating point overflow */ #define FPE_FLTUND 5 /* floating point underflow */ #define FPE_FLTRES 6 /* floating point inexact result */ #define FPE_FLTINV 7 /* floating point invalid operation */ #define FPE_FLTSUB 8 /* subscript out of range */ #define SEGV_MAPERR 1 /* address not mapped to object */ #define SEGV_ACCERR 2 /* invalid permissions for mapped object */ #define BUS_ADRALN 1 /* invalid address alignment */ #define BUS_ADRERR 2 /* non-existant physical address */ #define BUS_OBJERR 3 /* object specific hardware error */ #define TRAP_BRKPT 1 /* process breakpoint */ #define TRAP_TRACE 2 /* process trace trap */ #define CLD_EXITED 1 /* child has exited */ #define CLD_KILLED 2 /* child was killed */ #define CLD_DUMPED 3 /* child terminated abnormally */ #define CLD_TRAPPED 4 /* traced child has trapped */ #define CLD_STOPPED 5 /* child has stopped */ #define CLD_CONTINUED 6 /* stopped child has continued */ #define POLL_IN 1 /* data input available */ #define POLL_OUT 2 /* output buffers available */ #define POLL_MSG 3 /* input message available */ #define POLL_ERR 4 /* i/o error */ #define POLL_PRI 5 /* high priority input available */ #define POLL_HUP 6 /* device disconnected */ #define SI_KERNEL 0x80 /* sent by kernel */ #define SI_USER 0 /* sent by kill, sigsend, raise */ #define SI_QUEUE -1 /* sent by sigqueue */ #define SI_TIMER -2 /* sent by timer expiration */ #define SI_MESGQ -3 /* sent by real time mesq state change */ #define SI_ASYNCIO -4 /* sent by AIO completion */ #define SI_SIGIO -5 /* sent by SIGIO */ #define SI_TKILL -6 /* sent by tkill */ #define SI_ASYNCNL -60 /* sent by asynch name lookup completion */ #define SI_FROMUSER(sip) ((sip)->si_code <= 0) #endif /* LINUX */ #if __GLIBC_MINOR__ < 1 /* Type for data associated with a signal. */ typedef union sigval { int sival_int; void *sival_ptr; } sigval_t; # define __SI_MAX_SIZE 128 # define __SI_PAD_SIZE ((__SI_MAX_SIZE / sizeof(int)) - 3) typedef struct siginfo { int si_signo; /* Signal number. */ int si_errno; /* If non-zero, an errno value associated with this signal, as defined in . */ int si_code; /* Signal code. */ union { int _pad[__SI_PAD_SIZE]; /* kill(). */ struct { __pid_t si_pid; /* Sending process ID. */ __uid_t si_uid; /* Real user ID of sending process. */ } _kill; /* POSIX.1b timers. */ struct { unsigned int _timer1; unsigned int _timer2; } _timer; /* POSIX.1b signals. */ struct { __pid_t si_pid; /* Sending process ID. */ __uid_t si_uid; /* Real user ID of sending process. */ sigval_t si_sigval; /* Signal value. */ } _rt; /* SIGCHLD. */ struct { __pid_t si_pid; /* Which child. */ int si_status; /* Exit value or signal. */ __clock_t si_utime; __clock_t si_stime; } _sigchld; /* SIGILL, SIGFPE, SIGSEGV, SIGBUS. */ struct { void *si_addr; /* Faulting insn/memory ref. */ } _sigfault; /* SIGPOLL. */ struct { int si_band; /* Band event for SIGPOLL. */ int si_fd; } _sigpoll; } _sifields; } siginfo_t; #define si_pid _sifields._kill.si_pid #define si_uid _sifields._kill.si_uid #define si_status _sifields._sigchld.si_status #define si_utime _sifields._sigchld.si_utime #define si_stime _sifields._sigchld.si_stime #define si_value _sifields._rt.si_sigval #define si_int _sifields._rt.si_sigval.sival_int #define si_ptr _sifields._rt.si_sigval.sival_ptr #define si_addr _sifields._sigfault.si_addr #define si_band _sifields._sigpoll.si_band #define si_fd _sifields._sigpoll.si_fd #endif #endif #if defined (SVR4) || defined (LINUX) static const struct xlat siginfo_codes[] = { #ifdef SI_KERNEL { SI_KERNEL, "SI_KERNEL" }, #endif #ifdef SI_USER { SI_USER, "SI_USER" }, #endif #ifdef SI_QUEUE { SI_QUEUE, "SI_QUEUE" }, #endif #ifdef SI_TIMER { SI_TIMER, "SI_TIMER" }, #endif #ifdef SI_MESGQ { SI_MESGQ, "SI_MESGQ" }, #endif #ifdef SI_ASYNCIO { SI_ASYNCIO, "SI_ASYNCIO" }, #endif #ifdef SI_SIGIO { SI_SIGIO, "SI_SIGIO" }, #endif #ifdef SI_TKILL { SI_TKILL, "SI_TKILL" }, #endif #ifdef SI_ASYNCNL { SI_ASYNCNL, "SI_ASYNCNL" }, #endif #ifdef SI_NOINFO { SI_NOINFO, "SI_NOINFO" }, #endif #ifdef SI_LWP { SI_LWP, "SI_LWP" }, #endif { 0, NULL }, }; static const struct xlat sigill_codes[] = { { ILL_ILLOPC, "ILL_ILLOPC" }, { ILL_ILLOPN, "ILL_ILLOPN" }, { ILL_ILLADR, "ILL_ILLADR" }, { ILL_ILLTRP, "ILL_ILLTRP" }, { ILL_PRVOPC, "ILL_PRVOPC" }, { ILL_PRVREG, "ILL_PRVREG" }, { ILL_COPROC, "ILL_COPROC" }, { ILL_BADSTK, "ILL_BADSTK" }, { 0, NULL }, }; static const struct xlat sigfpe_codes[] = { { FPE_INTDIV, "FPE_INTDIV" }, { FPE_INTOVF, "FPE_INTOVF" }, { FPE_FLTDIV, "FPE_FLTDIV" }, { FPE_FLTOVF, "FPE_FLTOVF" }, { FPE_FLTUND, "FPE_FLTUND" }, { FPE_FLTRES, "FPE_FLTRES" }, { FPE_FLTINV, "FPE_FLTINV" }, { FPE_FLTSUB, "FPE_FLTSUB" }, { 0, NULL }, }; static const struct xlat sigtrap_codes[] = { { TRAP_BRKPT, "TRAP_BRKPT" }, { TRAP_TRACE, "TRAP_TRACE" }, { 0, NULL }, }; static const struct xlat sigchld_codes[] = { { CLD_EXITED, "CLD_EXITED" }, { CLD_KILLED, "CLD_KILLED" }, { CLD_DUMPED, "CLD_DUMPED" }, { CLD_TRAPPED, "CLD_TRAPPED" }, { CLD_STOPPED, "CLD_STOPPED" }, { CLD_CONTINUED,"CLD_CONTINUED" }, { 0, NULL }, }; static const struct xlat sigpoll_codes[] = { { POLL_IN, "POLL_IN" }, { POLL_OUT, "POLL_OUT" }, { POLL_MSG, "POLL_MSG" }, { POLL_ERR, "POLL_ERR" }, { POLL_PRI, "POLL_PRI" }, { POLL_HUP, "POLL_HUP" }, { 0, NULL }, }; static const struct xlat sigprof_codes[] = { #ifdef PROF_SIG { PROF_SIG, "PROF_SIG" }, #endif { 0, NULL }, }; #ifdef SIGEMT static const struct xlat sigemt_codes[] = { #ifdef EMT_TAGOVF { EMT_TAGOVF, "EMT_TAGOVF" }, #endif { 0, NULL }, }; #endif static const struct xlat sigsegv_codes[] = { { SEGV_MAPERR, "SEGV_MAPERR" }, { SEGV_ACCERR, "SEGV_ACCERR" }, { 0, NULL }, }; static const struct xlat sigbus_codes[] = { { BUS_ADRALN, "BUS_ADRALN" }, { BUS_ADRERR, "BUS_ADRERR" }, { BUS_OBJERR, "BUS_OBJERR" }, { 0, NULL }, }; void printsiginfo(siginfo_t *sip, int verbose) { const char *code; if (sip->si_signo == 0) { tprints("{}"); return; } tprints("{si_signo="); printsignal(sip->si_signo); code = xlookup(siginfo_codes, sip->si_code); if (!code) { switch (sip->si_signo) { case SIGTRAP: code = xlookup(sigtrap_codes, sip->si_code); break; case SIGCHLD: code = xlookup(sigchld_codes, sip->si_code); break; case SIGPOLL: code = xlookup(sigpoll_codes, sip->si_code); break; case SIGPROF: code = xlookup(sigprof_codes, sip->si_code); break; case SIGILL: code = xlookup(sigill_codes, sip->si_code); break; #ifdef SIGEMT case SIGEMT: code = xlookup(sigemt_codes, sip->si_code); break; #endif case SIGFPE: code = xlookup(sigfpe_codes, sip->si_code); break; case SIGSEGV: code = xlookup(sigsegv_codes, sip->si_code); break; case SIGBUS: code = xlookup(sigbus_codes, sip->si_code); break; } } if (code) tprintf(", si_code=%s", code); else tprintf(", si_code=%#x", sip->si_code); #ifdef SI_NOINFO if (sip->si_code != SI_NOINFO) #endif { if (sip->si_errno) { if (sip->si_errno < 0 || sip->si_errno >= nerrnos) tprintf(", si_errno=%d", sip->si_errno); else tprintf(", si_errno=%s", errnoent[sip->si_errno]); } #ifdef SI_FROMUSER if (SI_FROMUSER(sip)) { tprintf(", si_pid=%lu, si_uid=%lu", (unsigned long) sip->si_pid, (unsigned long) sip->si_uid); switch (sip->si_code) { #ifdef SI_USER case SI_USER: break; #endif #ifdef SI_TKILL case SI_TKILL: break; #endif #ifdef SI_TIMER case SI_TIMER: tprintf(", si_value=%d", sip->si_int); break; #endif #ifdef LINUX default: if (!sip->si_ptr) break; if (!verbose) tprints(", ..."); else tprintf(", si_value={int=%u, ptr=%#lx}", sip->si_int, (unsigned long) sip->si_ptr); break; #endif } } else #endif /* SI_FROMUSER */ { switch (sip->si_signo) { case SIGCHLD: tprintf(", si_pid=%ld, si_status=", (long) sip->si_pid); if (sip->si_code == CLD_EXITED) tprintf("%d", sip->si_status); else printsignal(sip->si_status); #if LINUX if (!verbose) tprints(", ..."); else tprintf(", si_utime=%lu, si_stime=%lu", sip->si_utime, sip->si_stime); #endif break; case SIGILL: case SIGFPE: case SIGSEGV: case SIGBUS: tprintf(", si_addr=%#lx", (unsigned long) sip->si_addr); break; case SIGPOLL: switch (sip->si_code) { case POLL_IN: case POLL_OUT: case POLL_MSG: tprintf(", si_band=%ld", (long) sip->si_band); break; } break; #ifdef LINUX default: if (sip->si_pid || sip->si_uid) tprintf(", si_pid=%lu, si_uid=%lu", (unsigned long) sip->si_pid, (unsigned long) sip->si_uid); if (!sip->si_ptr) break; if (!verbose) tprints(", ..."); else { tprintf(", si_value={int=%u, ptr=%#lx}", sip->si_int, (unsigned long) sip->si_ptr); } #endif } } } tprints("}"); } #endif /* SVR4 || LINUX */ #if defined(SUNOS4) || defined(FREEBSD) int sys_sigvec(struct tcb *tcp) { struct sigvec sv; long addr; if (entering(tcp)) { printsignal(tcp->u_arg[0]); tprints(", "); addr = tcp->u_arg[1]; } else { addr = tcp->u_arg[2]; } if (addr == 0) tprints("NULL"); else if (!verbose(tcp)) tprintf("%#lx", addr); else if (umove(tcp, addr, &sv) < 0) tprints("{...}"); else { switch ((int) sv.sv_handler) { case (int) SIG_ERR: tprints("{SIG_ERR}"); break; case (int) SIG_DFL: tprints("{SIG_DFL}"); break; case (int) SIG_IGN: if (tcp->u_arg[0] == SIGTRAP) { tcp->flags |= TCB_SIGTRAPPED; kill(tcp->pid, SIGSTOP); } tprints("{SIG_IGN}"); break; case (int) SIG_HOLD: if (tcp->u_arg[0] == SIGTRAP) { tcp->flags |= TCB_SIGTRAPPED; kill(tcp->pid, SIGSTOP); } tprints("SIG_HOLD"); break; default: if (tcp->u_arg[0] == SIGTRAP) { tcp->flags |= TCB_SIGTRAPPED; kill(tcp->pid, SIGSTOP); } tprintf("{%#lx, ", (unsigned long) sv.sv_handler); printsigmask(&sv.sv_mask, 0); tprints(", "); printflags(sigvec_flags, sv.sv_flags, "SV_???"); tprints("}"); } } if (entering(tcp)) tprints(", "); return 0; } int sys_sigpause(struct tcb *tcp) { if (entering(tcp)) { /* WTA: UD had a bug here: he forgot the braces */ sigset_t sigm; long_to_sigset(tcp->u_arg[0], &sigm); printsigmask(&sigm, 0); } return 0; } int sys_sigstack(struct tcb *tcp) { struct sigstack ss; long addr; if (entering(tcp)) addr = tcp->u_arg[0]; else addr = tcp->u_arg[1]; if (addr == 0) tprints("NULL"); else if (umove(tcp, addr, &ss) < 0) tprintf("%#lx", addr); else { tprintf("{ss_sp %#lx ", (unsigned long) ss.ss_sp); tprintf("ss_onstack %s}", ss.ss_onstack ? "YES" : "NO"); } if (entering(tcp)) tprints(", "); return 0; } int sys_sigcleanup(struct tcb *tcp) { return 0; } #endif /* SUNOS4 || FREEBSD */ #ifndef SVR4 int sys_sigsetmask(struct tcb *tcp) { if (entering(tcp)) { sigset_t sigm; long_to_sigset(tcp->u_arg[0], &sigm); printsigmask(&sigm, 0); #ifndef USE_PROCFS if ((tcp->u_arg[0] & sigmask(SIGTRAP))) { /* Mark attempt to block SIGTRAP */ tcp->flags |= TCB_SIGTRAPPED; /* Send unblockable signal */ kill(tcp->pid, SIGSTOP); } #endif /* !USE_PROCFS */ } else if (!syserror(tcp)) { sigset_t sigm; long_to_sigset(tcp->u_rval, &sigm); tcp->auxstr = sprintsigmask("old mask ", &sigm, 0); return RVAL_HEX | RVAL_STR; } return 0; } #if defined(SUNOS4) || defined(FREEBSD) int sys_sigblock(struct tcb *tcp) { return sys_sigsetmask(tcp); } #endif /* SUNOS4 || FREEBSD */ #endif /* !SVR4 */ #ifdef HAVE_SIGACTION #ifdef LINUX struct old_sigaction { __sighandler_t __sa_handler; unsigned long sa_mask; unsigned long sa_flags; void (*sa_restorer)(void); }; #define SA_HANDLER __sa_handler #endif /* LINUX */ #ifndef SA_HANDLER #define SA_HANDLER sa_handler #endif int sys_sigaction(struct tcb *tcp) { long addr; #ifdef LINUX sigset_t sigset; struct old_sigaction sa; #else struct sigaction sa; #endif if (entering(tcp)) { printsignal(tcp->u_arg[0]); tprints(", "); addr = tcp->u_arg[1]; } else addr = tcp->u_arg[2]; if (addr == 0) tprints("NULL"); else if (!verbose(tcp)) tprintf("%#lx", addr); else if (umove(tcp, addr, &sa) < 0) tprints("{...}"); else { /* Architectures using function pointers, like * hppa, may need to manipulate the function pointer * to compute the result of a comparison. However, * the SA_HANDLER function pointer exists only in * the address space of the traced process, and can't * be manipulated by strace. In order to prevent the * compiler from generating code to manipulate * SA_HANDLER we cast the function pointers to long. */ if ((long)sa.SA_HANDLER == (long)SIG_ERR) tprints("{SIG_ERR, "); else if ((long)sa.SA_HANDLER == (long)SIG_DFL) tprints("{SIG_DFL, "); else if ((long)sa.SA_HANDLER == (long)SIG_IGN) { #ifndef USE_PROCFS if (tcp->u_arg[0] == SIGTRAP) { tcp->flags |= TCB_SIGTRAPPED; kill(tcp->pid, SIGSTOP); } #endif /* !USE_PROCFS */ tprints("{SIG_IGN, "); } else { #ifndef USE_PROCFS if (tcp->u_arg[0] == SIGTRAP) { tcp->flags |= TCB_SIGTRAPPED; kill(tcp->pid, SIGSTOP); } #endif /* !USE_PROCFS */ tprintf("{%#lx, ", (long) sa.SA_HANDLER); #ifndef LINUX printsigmask(&sa.sa_mask, 0); #else long_to_sigset(sa.sa_mask, &sigset); printsigmask(&sigset, 0); #endif tprints(", "); printflags(sigact_flags, sa.sa_flags, "SA_???"); #ifdef SA_RESTORER if (sa.sa_flags & SA_RESTORER) tprintf(", %p", sa.sa_restorer); #endif tprints("}"); } } if (entering(tcp)) tprints(", "); #ifdef LINUX else tprintf(", %#lx", (unsigned long) sa.sa_restorer); #endif return 0; } int sys_signal(struct tcb *tcp) { if (entering(tcp)) { printsignal(tcp->u_arg[0]); tprints(", "); switch (tcp->u_arg[1]) { case (long) SIG_ERR: tprints("SIG_ERR"); break; case (long) SIG_DFL: tprints("SIG_DFL"); break; case (long) SIG_IGN: #ifndef USE_PROCFS if (tcp->u_arg[0] == SIGTRAP) { tcp->flags |= TCB_SIGTRAPPED; kill(tcp->pid, SIGSTOP); } #endif /* !USE_PROCFS */ tprints("SIG_IGN"); break; default: #ifndef USE_PROCFS if (tcp->u_arg[0] == SIGTRAP) { tcp->flags |= TCB_SIGTRAPPED; kill(tcp->pid, SIGSTOP); } #endif /* !USE_PROCFS */ tprintf("%#lx", tcp->u_arg[1]); } return 0; } else if (!syserror(tcp)) { switch (tcp->u_rval) { case (long) SIG_ERR: tcp->auxstr = "SIG_ERR"; break; case (long) SIG_DFL: tcp->auxstr = "SIG_DFL"; break; case (long) SIG_IGN: tcp->auxstr = "SIG_IGN"; break; default: tcp->auxstr = NULL; } return RVAL_HEX | RVAL_STR; } return 0; } #ifdef SVR4 int sys_sighold(struct tcb *tcp) { if (entering(tcp)) { printsignal(tcp->u_arg[0]); } return 0; } #endif /* SVR4 */ #endif /* HAVE_SIGACTION */ #ifdef LINUX int sys_sigreturn(struct tcb *tcp) { #if defined(ARM) if (entering(tcp)) { struct pt_regs regs; struct sigcontext_struct sc; tcp->u_arg[0] = 0; if (ptrace(PTRACE_GETREGS, tcp->pid, NULL, (void *)®s) == -1) return 0; if (umove(tcp, regs.ARM_sp, &sc) < 0) return 0; tcp->u_arg[0] = 1; tcp->u_arg[1] = sc.oldmask; } else { sigset_t sigm; tcp->u_rval = tcp->u_error = 0; if (tcp->u_arg[0] == 0) return 0; long_to_sigset(tcp->u_arg[1], &sigm); tcp->auxstr = sprintsigmask("mask now ", &sigm, 0); return RVAL_NONE | RVAL_STR; } return 0; #elif defined(S390) || defined(S390X) if (entering(tcp)) { long usp; struct sigcontext_struct sc; tcp->u_arg[0] = 0; if (upeek(tcp, PT_GPR15, &usp) < 0) return 0; if (umove(tcp, usp+__SIGNAL_FRAMESIZE, &sc) < 0) return 0; tcp->u_arg[0] = 1; memcpy(&tcp->u_arg[1], &sc.oldmask[0], NSIG / 8); } else { tcp->u_rval = tcp->u_error = 0; if (tcp->u_arg[0] == 0) return 0; tcp->auxstr = sprintsigmask("mask now ", (sigset_t *)&tcp->u_arg[1], 0); return RVAL_NONE | RVAL_STR; } return 0; #elif defined(I386) if (entering(tcp)) { long esp; struct sigcontext_struct sc; tcp->u_arg[0] = 0; if (upeek(tcp, 4*UESP, &esp) < 0) return 0; if (umove(tcp, esp, &sc) < 0) return 0; tcp->u_arg[0] = 1; tcp->u_arg[1] = sc.oldmask; } else { sigset_t sigm; tcp->u_rval = tcp->u_error = 0; if (tcp->u_arg[0] == 0) return 0; long_to_sigset(tcp->u_arg[1], &sigm); tcp->auxstr = sprintsigmask("mask now ", &sigm, 0); return RVAL_NONE | RVAL_STR; } return 0; #elif defined(IA64) if (entering(tcp)) { struct sigcontext sc; long sp; /* offset of sigcontext in the kernel's sigframe structure: */ # define SIGFRAME_SC_OFFSET 0x90 tcp->u_arg[0] = 0; if (upeek(tcp, PT_R12, &sp) < 0) return 0; if (umove(tcp, sp + 16 + SIGFRAME_SC_OFFSET, &sc) < 0) return 0; tcp->u_arg[0] = 1; memcpy(tcp->u_arg + 1, &sc.sc_mask, NSIG / 8); } else { sigset_t sigm; tcp->u_rval = tcp->u_error = 0; if (tcp->u_arg[0] == 0) return 0; sigemptyset(&sigm); memcpy(&sigm, tcp->u_arg + 1, NSIG / 8); tcp->auxstr = sprintsigmask("mask now ", &sigm, 0); return RVAL_NONE | RVAL_STR; } return 0; #elif defined(POWERPC) if (entering(tcp)) { long esp; struct sigcontext_struct sc; tcp->u_arg[0] = 0; if (upeek(tcp, sizeof(unsigned long)*PT_R1, &esp) < 0) return 0; /* Skip dummy stack frame. */ #ifdef POWERPC64 if (current_personality == 0) esp += 128; else esp += 64; #else esp += 64; #endif if (umove(tcp, esp, &sc) < 0) return 0; tcp->u_arg[0] = 1; tcp->u_arg[1] = sc.oldmask; } else { sigset_t sigm; tcp->u_rval = tcp->u_error = 0; if (tcp->u_arg[0] == 0) return 0; long_to_sigset(tcp->u_arg[1], &sigm); tcp->auxstr = sprintsigmask("mask now ", &sigm, 0); return RVAL_NONE | RVAL_STR; } return 0; #elif defined(M68K) if (entering(tcp)) { long usp; struct sigcontext sc; tcp->u_arg[0] = 0; if (upeek(tcp, 4*PT_USP, &usp) < 0) return 0; if (umove(tcp, usp, &sc) < 0) return 0; tcp->u_arg[0] = 1; tcp->u_arg[1] = sc.sc_mask; } else { sigset_t sigm; tcp->u_rval = tcp->u_error = 0; if (tcp->u_arg[0] == 0) return 0; long_to_sigset(tcp->u_arg[1], &sigm); tcp->auxstr = sprintsigmask("mask now ", &sigm, 0); return RVAL_NONE | RVAL_STR; } return 0; #elif defined(ALPHA) if (entering(tcp)) { long fp; struct sigcontext_struct sc; tcp->u_arg[0] = 0; if (upeek(tcp, REG_FP, &fp) < 0) return 0; if (umove(tcp, fp, &sc) < 0) return 0; tcp->u_arg[0] = 1; tcp->u_arg[1] = sc.sc_mask; } else { sigset_t sigm; tcp->u_rval = tcp->u_error = 0; if (tcp->u_arg[0] == 0) return 0; long_to_sigset(tcp->u_arg[1], &sigm); tcp->auxstr = sprintsigmask("mask now ", &sigm, 0); return RVAL_NONE | RVAL_STR; } return 0; #elif defined (SPARC) || defined (SPARC64) if (entering(tcp)) { long i1; struct pt_regs regs; m_siginfo_t si; tcp->u_arg[0] = 0; if (ptrace(PTRACE_GETREGS, tcp->pid, (char *)®s, 0) < 0) { perror("sigreturn: PTRACE_GETREGS"); return 0; } i1 = regs.u_regs[U_REG_O1]; if (umove(tcp, i1, &si) < 0) { perror("sigreturn: umove"); return 0; } tcp->u_arg[0] = 1; tcp->u_arg[1] = si.si_mask; } else { sigset_t sigm; tcp->u_rval = tcp->u_error = 0; if (tcp->u_arg[0] == 0) return 0; long_to_sigset(tcp->u_arg[1], &sigm); tcp->auxstr = sprintsigmask("mask now ", &sigm, 0); return RVAL_NONE | RVAL_STR; } return 0; #elif defined (LINUX_MIPSN32) || defined (LINUX_MIPSN64) /* This decodes rt_sigreturn. The 64-bit ABIs do not have sigreturn. */ if (entering(tcp)) { long sp; struct ucontext uc; tcp->u_arg[0] = 0; if (upeek(tcp, REG_SP, &sp) < 0) return 0; /* There are six words followed by a 128-byte siginfo. */ sp = sp + 6 * 4 + 128; if (umove(tcp, sp, &uc) < 0) return 0; tcp->u_arg[0] = 1; tcp->u_arg[1] = *(long *) &uc.uc_sigmask; } else { sigset_t sigm; tcp->u_rval = tcp->u_error = 0; if (tcp->u_arg[0] == 0) return 0; long_to_sigset(tcp->u_arg[1], &sigm); tcp->auxstr = sprintsigmask("mask now ", &sigm, 0); return RVAL_NONE | RVAL_STR; } return 0; #elif defined(MIPS) if (entering(tcp)) { long sp; struct pt_regs regs; m_siginfo_t si; tcp->u_arg[0] = 0; if (ptrace(PTRACE_GETREGS, tcp->pid, (char *)®s, 0) < 0) { perror("sigreturn: PTRACE_GETREGS"); return 0; } sp = regs.regs[29]; if (umove(tcp, sp, &si) < 0) return 0; tcp->u_arg[0] = 1; tcp->u_arg[1] = si.si_mask; } else { sigset_t sigm; tcp->u_rval = tcp->u_error = 0; if (tcp->u_arg[0] == 0) return 0; long_to_sigset(tcp->u_arg[1], &sigm); tcp->auxstr = sprintsigmask("mask now ", &sigm, 0); return RVAL_NONE | RVAL_STR; } return 0; #elif defined(CRISV10) || defined(CRISV32) if (entering(tcp)) { struct sigcontext sc; long regs[PT_MAX+1]; tcp->u_arg[0] = 0; if (ptrace(PTRACE_GETREGS, tcp->pid, NULL, (long)regs) < 0) { perror("sigreturn: PTRACE_GETREGS"); return 0; } if (umove(tcp, regs[PT_USP], &sc) < 0) return 0; tcp->u_arg[0] = 1; tcp->u_arg[1] = sc.oldmask; } else { sigset_t sigm; tcp->u_rval = tcp->u_error = 0; if (tcp->u_arg[0] == 0) return 0; long_to_sigset(tcp->u_arg[1], &sigm); tcp->auxstr = sprintsigmask("mask now ", &sigm, 0); return RVAL_NONE | RVAL_STR; } return 0; #elif defined(TILE) if (entering(tcp)) { struct ucontext uc; long sp; /* offset of ucontext in the kernel's sigframe structure */ # define SIGFRAME_UC_OFFSET C_ABI_SAVE_AREA_SIZE + sizeof(struct siginfo) tcp->u_arg[0] = 0; if (upeek(tcp, PTREGS_OFFSET_SP, &sp) < 0) return 0; if (umove(tcp, sp + SIGFRAME_UC_OFFSET, &uc) < 0) return 0; tcp->u_arg[0] = 1; memcpy(tcp->u_arg + 1, &uc.uc_sigmask, NSIG / 8); } else { sigset_t sigm; tcp->u_rval = tcp->u_error = 0; if (tcp->u_arg[0] == 0) return 0; sigemptyset(&sigm); memcpy(&sigm, tcp->u_arg + 1, NSIG / 8); tcp->auxstr = sprintsigmask("mask now ", &sigm, 0); return RVAL_NONE | RVAL_STR; } return 0; #elif defined(MICROBLAZE) /* TODO: Verify that this is correct... */ if (entering(tcp)) { struct sigcontext sc; long sp; tcp->u_arg[0] = 0; /* Read r1, the stack pointer. */ if (upeek(tcp, 1 * 4, &sp) < 0) return 0; if (umove(tcp, sp, &sc) < 0) return 0; tcp->u_arg[0] = 1; tcp->u_arg[1] = sc.oldmask; } else { sigset_t sigm; tcp->u_rval = tcp->u_error = 0; if (tcp->u_arg[0] == 0) return 0; long_to_sigset(tcp->u_arg[1], &sigm); tcp->auxstr = sprintsigmask("mask now ", &sigm, 0); return RVAL_NONE | RVAL_STR; } return 0; #else #warning No sys_sigreturn() for this architecture #warning (no problem, just a reminder :-) return 0; #endif } int sys_siggetmask(struct tcb *tcp) { if (exiting(tcp)) { sigset_t sigm; long_to_sigset(tcp->u_rval, &sigm); tcp->auxstr = sprintsigmask("mask ", &sigm, 0); } return RVAL_HEX | RVAL_STR; } int sys_sigsuspend(struct tcb *tcp) { if (entering(tcp)) { sigset_t sigm; long_to_sigset(tcp->u_arg[2], &sigm); printsigmask(&sigm, 0); } return 0; } #endif /* LINUX */ #if defined(SVR4) || defined(FREEBSD) int sys_sigsuspend(struct tcb *tcp) { sigset_t sigset; if (entering(tcp)) { if (umove(tcp, tcp->u_arg[0], &sigset) < 0) tprints("[?]"); else printsigmask(&sigset, 0); } return 0; } #ifndef FREEBSD static const struct xlat ucontext_flags[] = { { UC_SIGMASK, "UC_SIGMASK" }, { UC_STACK, "UC_STACK" }, { UC_CPU, "UC_CPU" }, #ifdef UC_FPU { UC_FPU, "UC_FPU" }, #endif #ifdef UC_INTR { UC_INTR, "UC_INTR" }, #endif { 0, NULL }, }; #endif /* !FREEBSD */ #endif /* SVR4 || FREEBSD */ #if defined SVR4 || defined LINUX || defined FREEBSD #if defined LINUX && !defined SS_ONSTACK #define SS_ONSTACK 1 #define SS_DISABLE 2 #if __GLIBC_MINOR__ == 0 typedef struct { __ptr_t ss_sp; int ss_flags; size_t ss_size; } stack_t; #endif #endif #ifdef FREEBSD #define stack_t struct sigaltstack #endif static const struct xlat sigaltstack_flags[] = { { SS_ONSTACK, "SS_ONSTACK" }, { SS_DISABLE, "SS_DISABLE" }, { 0, NULL }, }; #endif #ifdef SVR4 static void printcontext(struct tcb *tcp, ucontext_t *ucp) { tprints("{"); if (!abbrev(tcp)) { tprints("uc_flags="); printflags(ucontext_flags, ucp->uc_flags, "UC_???"); tprintf(", uc_link=%#lx, ", (unsigned long) ucp->uc_link); } tprints("uc_sigmask="); printsigmask(&ucp->uc_sigmask, 0); if (!abbrev(tcp)) { tprintf(", uc_stack={ss_sp=%#lx, ss_size=%d, ss_flags=", (unsigned long) ucp->uc_stack.ss_sp, ucp->uc_stack.ss_size); printflags(sigaltstack_flags, ucp->uc_stack.ss_flags, "SS_???"); tprints("}"); } tprints(", ...}"); } int sys_getcontext(struct tcb *tcp) { ucontext_t uc; if (exiting(tcp)) { if (tcp->u_error) tprintf("%#lx", tcp->u_arg[0]); else if (!tcp->u_arg[0]) tprints("NULL"); else if (umove(tcp, tcp->u_arg[0], &uc) < 0) tprints("{...}"); else printcontext(tcp, &uc); } return 0; } int sys_setcontext(struct tcb *tcp) { ucontext_t uc; if (entering(tcp)) { if (!tcp->u_arg[0]) tprints("NULL"); else if (umove(tcp, tcp->u_arg[0], &uc) < 0) tprints("{...}"); else printcontext(tcp, &uc); } else { tcp->u_rval = tcp->u_error = 0; if (tcp->u_arg[0] == 0) return 0; return RVAL_NONE; } return 0; } #endif /* SVR4 */ #if defined(LINUX) || defined(FREEBSD) static int print_stack_t(struct tcb *tcp, unsigned long addr) { stack_t ss; if (umove(tcp, addr, &ss) < 0) return -1; tprintf("{ss_sp=%#lx, ss_flags=", (unsigned long) ss.ss_sp); printflags(sigaltstack_flags, ss.ss_flags, "SS_???"); tprintf(", ss_size=%lu}", (unsigned long) ss.ss_size); return 0; } int sys_sigaltstack(struct tcb *tcp) { if (entering(tcp)) { if (tcp->u_arg[0] == 0) tprints("NULL"); else if (print_stack_t(tcp, tcp->u_arg[0]) < 0) return -1; } else { tprints(", "); if (tcp->u_arg[1] == 0) tprints("NULL"); else if (print_stack_t(tcp, tcp->u_arg[1]) < 0) return -1; } return 0; } #endif #ifdef HAVE_SIGACTION int sys_sigprocmask(struct tcb *tcp) { #ifdef ALPHA if (entering(tcp)) { printxval(sigprocmaskcmds, tcp->u_arg[0], "SIG_???"); tprints(", "); printsigmask(tcp->u_arg[1], 0); } else if (!syserror(tcp)) { tcp->auxstr = sprintsigmask("old mask ", tcp->u_rval, 0); return RVAL_HEX | RVAL_STR; } #else /* !ALPHA */ if (entering(tcp)) { #ifdef SVR4 if (tcp->u_arg[0] == 0) tprints("0"); else #endif /* SVR4 */ printxval(sigprocmaskcmds, tcp->u_arg[0], "SIG_???"); tprints(", "); print_sigset(tcp, tcp->u_arg[1], 0); tprints(", "); } else { if (!tcp->u_arg[2]) tprints("NULL"); else if (syserror(tcp)) tprintf("%#lx", tcp->u_arg[2]); else print_sigset(tcp, tcp->u_arg[2], 0); } #endif /* !ALPHA */ return 0; } #endif /* HAVE_SIGACTION */ int sys_kill(struct tcb *tcp) { if (entering(tcp)) { long pid = tcp->u_arg[0]; #if SUPPORTED_PERSONALITIES > 1 /* Sign-extend a 32-bit value when that's what it is. */ if (personality_wordsize[current_personality] < sizeof pid) pid = (long) (int) pid; #endif tprintf("%ld, %s", pid, signame(tcp->u_arg[1])); } return 0; } #if defined(FREEBSD) || defined(SUNOS4) int sys_killpg(struct tcb *tcp) { return sys_kill(tcp); } #endif /* FREEBSD || SUNOS4 */ #ifdef LINUX int sys_tgkill(struct tcb *tcp) { if (entering(tcp)) { tprintf("%ld, %ld, %s", tcp->u_arg[0], tcp->u_arg[1], signame(tcp->u_arg[2])); } return 0; } #endif int sys_sigpending(struct tcb *tcp) { sigset_t sigset; if (exiting(tcp)) { if (syserror(tcp)) tprintf("%#lx", tcp->u_arg[0]); else if (copy_sigset(tcp, tcp->u_arg[0], &sigset) < 0) tprints("[?]"); else printsigmask(&sigset, 0); } return 0; } #ifdef SVR4 int sys_sigwait(struct tcb *tcp) { sigset_t sigset; if (entering(tcp)) { if (copy_sigset(tcp, tcp->u_arg[0], &sigset) < 0) tprints("[?]"); else printsigmask(&sigset, 0); } else { if (!syserror(tcp)) { tcp->auxstr = signalent[tcp->u_rval]; return RVAL_DECIMAL | RVAL_STR; } } return 0; } #endif /* SVR4 */ #ifdef LINUX int sys_rt_sigprocmask(struct tcb *tcp) { sigset_t sigset; /* Note: arg[3] is the length of the sigset. */ if (entering(tcp)) { printxval(sigprocmaskcmds, tcp->u_arg[0], "SIG_???"); tprints(", "); if (!tcp->u_arg[1]) tprints("NULL, "); else if (copy_sigset_len(tcp, tcp->u_arg[1], &sigset, tcp->u_arg[3]) < 0) tprintf("%#lx, ", tcp->u_arg[1]); else { printsigmask(&sigset, 1); tprints(", "); } } else { if (!tcp->u_arg[2]) tprints("NULL"); else if (syserror(tcp)) tprintf("%#lx", tcp->u_arg[2]); else if (copy_sigset_len(tcp, tcp->u_arg[2], &sigset, tcp->u_arg[3]) < 0) tprints("[?]"); else printsigmask(&sigset, 1); tprintf(", %lu", tcp->u_arg[3]); } return 0; } /* Structure describing the action to be taken when a signal arrives. */ struct new_sigaction { __sighandler_t __sa_handler; unsigned long sa_flags; void (*sa_restorer) (void); /* Kernel treats sa_mask as an array of longs. */ unsigned long sa_mask[NSIG / sizeof(long) ? NSIG / sizeof(long) : 1]; }; /* Same for i386-on-x86_64 and similar cases */ struct new_sigaction32 { uint32_t __sa_handler; uint32_t sa_flags; uint32_t sa_restorer; uint32_t sa_mask[2 * (NSIG / sizeof(long) ? NSIG / sizeof(long) : 1)]; }; int sys_rt_sigaction(struct tcb *tcp) { struct new_sigaction sa; sigset_t sigset; long addr; int r; if (entering(tcp)) { printsignal(tcp->u_arg[0]); tprints(", "); addr = tcp->u_arg[1]; } else addr = tcp->u_arg[2]; if (addr == 0) { tprints("NULL"); goto after_sa; } if (!verbose(tcp)) { tprintf("%#lx", addr); goto after_sa; } #if SUPPORTED_PERSONALITIES > 1 if (personality_wordsize[current_personality] != sizeof(sa.sa_flags) && personality_wordsize[current_personality] == 4 ) { struct new_sigaction32 sa32; r = umove(tcp, addr, &sa32); if (r >= 0) { memset(&sa, 0, sizeof(sa)); sa.__sa_handler = (void*)(unsigned long)sa32.__sa_handler; sa.sa_flags = sa32.sa_flags; sa.sa_restorer = (void*)(unsigned long)sa32.sa_restorer; /* Kernel treats sa_mask as an array of longs. * For 32-bit process, "long" is uint32_t, thus, for example, * 32th bit in sa_mask will end up as bit 0 in sa_mask[1]. * But for (64-bit) kernel, 32th bit in sa_mask is * 32th bit in 0th (64-bit) long! * For little-endian, it's the same. * For big-endian, we swap 32-bit words. */ sa.sa_mask[0] = sa32.sa_mask[0] + ((long)(sa32.sa_mask[1]) << 32); } } else #endif { r = umove(tcp, addr, &sa); } if (r < 0) { tprints("{...}"); goto after_sa; } /* Architectures using function pointers, like * hppa, may need to manipulate the function pointer * to compute the result of a comparison. However, * the SA_HANDLER function pointer exists only in * the address space of the traced process, and can't * be manipulated by strace. In order to prevent the * compiler from generating code to manipulate * SA_HANDLER we cast the function pointers to long. */ if ((long)sa.__sa_handler == (long)SIG_ERR) tprints("{SIG_ERR, "); else if ((long)sa.__sa_handler == (long)SIG_DFL) tprints("{SIG_DFL, "); else if ((long)sa.__sa_handler == (long)SIG_IGN) tprints("{SIG_IGN, "); else tprintf("{%#lx, ", (long) sa.__sa_handler); /* Questionable code below. * Kernel won't handle sys_rt_sigaction * with wrong sigset size (just returns EINVAL) * therefore tcp->u_arg[3(4)] _must_ be NSIG / 8 here, * and we always use smaller memcpy. */ sigemptyset(&sigset); #ifdef LINUXSPARC if (tcp->u_arg[4] <= sizeof(sigset)) memcpy(&sigset, &sa.sa_mask, tcp->u_arg[4]); #else if (tcp->u_arg[3] <= sizeof(sigset)) memcpy(&sigset, &sa.sa_mask, tcp->u_arg[3]); #endif else memcpy(&sigset, &sa.sa_mask, sizeof(sigset)); printsigmask(&sigset, 1); tprints(", "); printflags(sigact_flags, sa.sa_flags, "SA_???"); #ifdef SA_RESTORER if (sa.sa_flags & SA_RESTORER) tprintf(", %p", sa.sa_restorer); #endif tprints("}"); after_sa: if (entering(tcp)) tprints(", "); else #ifdef LINUXSPARC tprintf(", %#lx, %lu", tcp->u_arg[3], tcp->u_arg[4]); #elif defined(ALPHA) tprintf(", %lu, %#lx", tcp->u_arg[3], tcp->u_arg[4]); #else tprintf(", %lu", tcp->u_arg[3]); #endif return 0; } int sys_rt_sigpending(struct tcb *tcp) { sigset_t sigset; if (exiting(tcp)) { if (syserror(tcp)) tprintf("%#lx", tcp->u_arg[0]); else if (copy_sigset_len(tcp, tcp->u_arg[0], &sigset, tcp->u_arg[1]) < 0) tprints("[?]"); else printsigmask(&sigset, 1); } return 0; } int sys_rt_sigsuspend(struct tcb *tcp) { if (entering(tcp)) { sigset_t sigm; if (copy_sigset_len(tcp, tcp->u_arg[0], &sigm, tcp->u_arg[1]) < 0) tprints("[?]"); else printsigmask(&sigm, 1); } return 0; } int sys_rt_sigqueueinfo(struct tcb *tcp) { if (entering(tcp)) { siginfo_t si; tprintf("%lu, ", tcp->u_arg[0]); printsignal(tcp->u_arg[1]); tprints(", "); if (umove(tcp, tcp->u_arg[2], &si) < 0) tprintf("%#lx", tcp->u_arg[2]); else printsiginfo(&si, verbose(tcp)); } return 0; } int sys_rt_sigtimedwait(struct tcb *tcp) { if (entering(tcp)) { sigset_t sigset; if (copy_sigset_len(tcp, tcp->u_arg[0], &sigset, tcp->u_arg[3]) < 0) tprints("[?]"); else printsigmask(&sigset, 1); tprints(", "); /* This is the only "return" parameter, */ if (tcp->u_arg[1] != 0) return 0; /* ... if it's NULL, can decode all on entry */ tprints("NULL, "); } else if (tcp->u_arg[1] != 0) { /* syscall exit, and u_arg[1] wasn't NULL */ if (syserror(tcp)) tprintf("%#lx, ", tcp->u_arg[1]); else { siginfo_t si; if (umove(tcp, tcp->u_arg[1], &si) < 0) tprintf("%#lx, ", tcp->u_arg[1]); else { printsiginfo(&si, verbose(tcp)); tprints(", "); } } } else { /* syscall exit, and u_arg[1] was NULL */ return 0; } print_timespec(tcp, tcp->u_arg[2]); tprintf(", %d", (int) tcp->u_arg[3]); return 0; }; int sys_restart_syscall(struct tcb *tcp) { if (entering(tcp)) tprints("<... resuming interrupted call ...>"); return 0; } static int do_signalfd(struct tcb *tcp, int flags_arg) { if (entering(tcp)) { printfd(tcp, tcp->u_arg[0]); tprints(", "); print_sigset(tcp, tcp->u_arg[1], 1); tprintf(", %lu", tcp->u_arg[2]); if (flags_arg >= 0) { tprints(", "); printflags(open_mode_flags, tcp->u_arg[flags_arg], "O_???"); } } return 0; } int sys_signalfd(struct tcb *tcp) { return do_signalfd(tcp, -1); } int sys_signalfd4(struct tcb *tcp) { return do_signalfd(tcp, 3); } #endif /* LINUX */