/* * 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. */ #include "defs.h" #include #include "regs.h" #include "ptrace.h" #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) && !defined(X32) # include # endif #else /* !HAVE_ASM_SIGCONTEXT_H */ # 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 /* !HAVE_ASM_SIGCONTEXT_H */ #ifndef NSIG # warning: NSIG is not defined, using 32 # define NSIG 32 #elif NSIG < 32 # error: NSIG < 32 #endif /* 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 # ifdef ASM_SA_RESTORER # define SA_RESTORER ASM_SA_RESTORER # endif #endif /* * Some architectures define SA_RESTORER in their headers, * but do not actually have sa_restorer. * * Some architectures, otherwise, do not define SA_RESTORER in their headers, * but actually have sa_restorer. */ #ifdef SA_RESTORER # if defined HPPA || defined IA64 # define HAVE_SA_RESTORER 0 # else # define HAVE_SA_RESTORER 1 # endif #else /* !SA_RESTORER */ # if defined SPARC || defined SPARC64 # define HAVE_SA_RESTORER 1 # else # define HAVE_SA_RESTORER 0 # endif #endif #include "xlat/sigact_flags.h" #include "xlat/sigprocmaskcmds.h" /* 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(const int sig) { static char buf[sizeof("SIGRT_%u") + sizeof(int)*3]; if (sig >= 0) { const unsigned int s = sig; if (s < nsignals) return signalent[s]; #ifdef SIGRTMIN if (s >= __SIGRTMIN && s <= __SIGRTMAX) { sprintf(buf, "SIGRT_%u", s - __SIGRTMIN); return buf; } #endif } sprintf(buf, "%d", sig); return buf; } static unsigned int popcount32(const uint32_t *a, unsigned int size) { unsigned int count = 0; for (; size; ++a, --size) { uint32_t x = *a; #ifdef HAVE___BUILTIN_POPCOUNT count += __builtin_popcount(x); #else for (; x; ++count) x &= x - 1; #endif } return count; } static const char * sprintsigmask_n(const char *prefix, const void *sig_mask, unsigned int bytes) { /* * The maximum number of signal names to be printed is NSIG * 2 / 3. * Most of signal names have length 7, * average length of signal names is less than 7. * The length of prefix string does not exceed 16. */ static char outstr[128 + 8 * (NSIG * 2 / 3)]; char *s; const uint32_t *mask; uint32_t inverted_mask[NSIG / 32]; unsigned int size; int i; char sep; s = stpcpy(outstr, prefix); mask = sig_mask; /* length of signal mask in 4-byte words */ size = (bytes >= NSIG / 8) ? NSIG / 32 : (bytes + 3) / 4; /* check whether 2/3 or more bits are set */ if (popcount32(mask, size) >= size * 32 * 2 / 3) { /* show those signals that are NOT in the mask */ unsigned int j; for (j = 0; j < size; ++j) inverted_mask[j] = ~mask[j]; mask = inverted_mask; *s++ = '~'; } sep = '['; for (i = 0; (i = next_set_bit(mask, i, size * 32)) >= 0; ) { ++i; *s++ = sep; if ((unsigned) i < nsignals) { s = stpcpy(s, signalent[i] + 3); } #ifdef SIGRTMIN else if (i >= __SIGRTMIN && i <= __SIGRTMAX) { s += sprintf(s, "RT_%u", i - __SIGRTMIN); } #endif else { s += sprintf(s, "%u", i); } sep = ' '; } if (sep == '[') *s++ = sep; *s++ = ']'; *s = '\0'; return outstr; } #define tprintsigmask_addr(prefix, mask) \ tprints(sprintsigmask_n((prefix), (mask), sizeof(mask))) #define sprintsigmask_val(prefix, mask) \ sprintsigmask_n((prefix), &(mask), sizeof(mask)) #define tprintsigmask_val(prefix, mask) \ tprints(sprintsigmask_n((prefix), &(mask), sizeof(mask))) void printsignal(int nr) { tprints(signame(nr)); } void print_sigset_addr_len(struct tcb *tcp, long addr, long len) { char mask[NSIG / 8]; if (!addr) { tprints("NULL"); return; } /* Here len is usually equals NSIG / 8 or current_wordsize. * But we code this defensively: */ if (len < 0) { bad: tprintf("%#lx", addr); return; } if (len >= NSIG / 8) len = NSIG / 8; else len = (len + 3) & ~3; if (umoven(tcp, addr, len, mask) < 0) goto bad; tprints(sprintsigmask_n("", mask, len)); } #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 SYS_SECCOMP 1 /* seccomp triggered */ #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_DETHREAD -7 /* sent by execve killing subsidiary threads */ #define SI_ASYNCNL -60 /* sent by asynch name lookup completion */ #endif #ifndef SI_FROMUSER # define SI_FROMUSER(sip) ((sip)->si_code <= 0) #endif #include "xlat/siginfo_codes.h" #include "xlat/sigill_codes.h" #include "xlat/sigfpe_codes.h" #include "xlat/sigtrap_codes.h" #include "xlat/sigchld_codes.h" #include "xlat/sigpoll_codes.h" #include "xlat/sigprof_codes.h" #ifdef SIGEMT #include "xlat/sigemt_codes.h" #endif #include "xlat/sigsegv_codes.h" #include "xlat/sigbus_codes.h" #ifndef SYS_SECCOMP # define SYS_SECCOMP 1 #endif #include "xlat/sigsys_codes.h" static void printsigsource(const siginfo_t *sip) { tprintf(", si_pid=%lu, si_uid=%lu", (unsigned long) sip->si_pid, (unsigned long) sip->si_uid); } static void printsigval(const siginfo_t *sip, int verbose) { if (!verbose) tprints(", ..."); else tprintf(", si_value={int=%u, ptr=%#lx}", sip->si_int, (unsigned long) sip->si_ptr); } void printsiginfo(const 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; case SIGSYS: code = xlookup(sigsys_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) { tprints(", si_errno="); if ((unsigned) sip->si_errno < nerrnos && errnoent[sip->si_errno]) tprints(errnoent[sip->si_errno]); else tprintf("%d", sip->si_errno); } #ifdef SI_FROMUSER if (SI_FROMUSER(sip)) { switch (sip->si_code) { #ifdef SI_USER case SI_USER: printsigsource(sip); break; #endif #ifdef SI_TKILL case SI_TKILL: printsigsource(sip); break; #endif #if defined SI_TIMER \ && defined HAVE_SIGINFO_T_SI_TIMERID && defined HAVE_SIGINFO_T_SI_OVERRUN case SI_TIMER: tprintf(", si_timerid=%#x, si_overrun=%d", sip->si_timerid, sip->si_overrun); printsigval(sip, verbose); break; #endif default: printsigsource(sip); if (sip->si_ptr) printsigval(sip, verbose); break; } } else #endif /* SI_FROMUSER */ { switch (sip->si_signo) { case SIGCHLD: printsigsource(sip); tprints(", si_status="); if (sip->si_code == CLD_EXITED) tprintf("%d", sip->si_status); else printsignal(sip->si_status); if (!verbose) tprints(", ..."); else tprintf(", si_utime=%llu, si_stime=%llu", (unsigned long long) sip->si_utime, (unsigned long long) sip->si_stime); 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 HAVE_SIGINFO_T_SI_SYSCALL case SIGSYS: tprintf(", si_call_addr=%#lx, si_syscall=%d, si_arch=%u", (unsigned long) sip->si_call_addr, sip->si_syscall, sip->si_arch); break; #endif default: if (sip->si_pid || sip->si_uid) printsigsource(sip); if (sip->si_ptr) printsigval(sip, verbose); } } } tprints("}"); } void printsiginfo_at(struct tcb *tcp, long addr) { siginfo_t si; if (!addr) { tprints("NULL"); return; } if (syserror(tcp)) { tprintf("%#lx", addr); return; } if (umove(tcp, addr, &si) < 0) { tprints("{???}"); return; } printsiginfo(&si, verbose(tcp)); } int sys_sigsetmask(struct tcb *tcp) { if (entering(tcp)) { tprintsigmask_val("", tcp->u_arg[0]); } else if (!syserror(tcp)) { tcp->auxstr = sprintsigmask_val("old mask ", tcp->u_rval); return RVAL_HEX | RVAL_STR; } return 0; } #ifdef HAVE_SIGACTION struct old_sigaction { /* sa_handler may be a libc #define, need to use other name: */ #ifdef MIPS unsigned int sa_flags; void (*__sa_handler)(int); /* Kernel treats sa_mask as an array of longs. */ unsigned long sa_mask[NSIG / sizeof(long) ? NSIG / sizeof(long) : 1]; #else void (*__sa_handler)(int); unsigned long sa_mask; unsigned long sa_flags; #endif /* !MIPS */ #if HAVE_SA_RESTORER void (*sa_restorer)(void); #endif }; struct old_sigaction32 { /* sa_handler may be a libc #define, need to use other name: */ uint32_t __sa_handler; uint32_t sa_mask; uint32_t sa_flags; #if HAVE_SA_RESTORER uint32_t sa_restorer; #endif }; static void decode_old_sigaction(struct tcb *tcp, long addr) { struct old_sigaction sa; int r; if (!addr) { tprints("NULL"); return; } if (!verbose(tcp) || (exiting(tcp) && syserror(tcp))) { tprintf("%#lx", addr); return; } #if SUPPORTED_PERSONALITIES > 1 && SIZEOF_LONG > 4 if (current_wordsize != sizeof(sa.__sa_handler) && current_wordsize == 4) { struct old_sigaction32 sa32; r = umove(tcp, addr, &sa32); if (r >= 0) { memset(&sa, 0, sizeof(sa)); sa.__sa_handler = (void*)(uintptr_t)sa32.__sa_handler; sa.sa_flags = sa32.sa_flags; #if HAVE_SA_RESTORER && defined SA_RESTORER sa.sa_restorer = (void*)(uintptr_t)sa32.sa_restorer; #endif sa.sa_mask = sa32.sa_mask; } } else #endif { r = umove(tcp, addr, &sa); } if (r < 0) { tprints("{...}"); return; } /* 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); #ifdef MIPS tprintsigmask_addr("", sa.sa_mask); #else tprintsigmask_val("", sa.sa_mask); #endif tprints(", "); printflags(sigact_flags, sa.sa_flags, "SA_???"); #if HAVE_SA_RESTORER && defined SA_RESTORER if (sa.sa_flags & SA_RESTORER) tprintf(", %p", sa.sa_restorer); #endif tprints("}"); } int sys_sigaction(struct tcb *tcp) { if (entering(tcp)) { printsignal(tcp->u_arg[0]); tprints(", "); decode_old_sigaction(tcp, tcp->u_arg[1]); tprints(", "); } else decode_old_sigaction(tcp, tcp->u_arg[2]); 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: tprints("SIG_IGN"); break; default: 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; } #endif /* HAVE_SIGACTION */ int sys_sigreturn(struct tcb *tcp) { #if defined AARCH64 || defined ARM if (entering(tcp)) { # define SIZEOF_STRUCT_SIGINFO 128 # define SIZEOF_STRUCT_SIGCONTEXT (21 * 4) # define OFFSETOF_STRUCT_UCONTEXT_UC_SIGMASK (5 * 4 + SIZEOF_STRUCT_SIGCONTEXT) const long addr = # ifdef AARCH64 current_personality == 0 ? (*aarch64_sp_ptr + SIZEOF_STRUCT_SIGINFO + offsetof(struct ucontext, uc_sigmask)) : # endif (*arm_sp_ptr + OFFSETOF_STRUCT_UCONTEXT_UC_SIGMASK); tprints(") (mask "); print_sigset_addr_len(tcp, addr, NSIG / 8); } #elif defined(S390) || defined(S390X) if (entering(tcp)) { long usp; long mask[NSIG / 8 / sizeof(long)]; if (upeek(tcp->pid, PT_GPR15, &usp) < 0) return 0; if (umove(tcp, usp + __SIGNAL_FRAMESIZE, &mask) < 0) return 0; # ifdef S390 usp = mask[0]; mask[0] = mask[1]; mask[1] = usp; # endif tprintsigmask_addr(") (mask ", mask); } #elif defined I386 || defined X86_64 || defined X32 if (entering(tcp)) { # ifndef I386 if (current_personality != 1) { const unsigned long addr = (unsigned long) *x86_64_rsp_ptr + offsetof(struct ucontext, uc_sigmask); tprints(") (mask "); print_sigset_addr_len(tcp, addr, NSIG / 8); return 0; } # endif struct i386_sigcontext_struct { uint16_t gs, __gsh; uint16_t fs, __fsh; uint16_t es, __esh; uint16_t ds, __dsh; uint32_t edi; uint32_t esi; uint32_t ebp; uint32_t esp; uint32_t ebx; uint32_t edx; uint32_t ecx; uint32_t eax; uint32_t trapno; uint32_t err; uint32_t eip; uint16_t cs, __csh; uint32_t eflags; uint32_t esp_at_signal; uint16_t ss, __ssh; uint32_t i387; uint32_t oldmask; uint32_t cr2; }; struct i386_fpstate { uint32_t cw; uint32_t sw; uint32_t tag; uint32_t ipoff; uint32_t cssel; uint32_t dataoff; uint32_t datasel; uint8_t st[8][10]; /* 8*10 bytes: FP regs */ uint16_t status; uint16_t magic; uint32_t fxsr_env[6]; uint32_t mxcsr; uint32_t reserved; uint8_t stx[8][16]; /* 8*16 bytes: FP regs, each padded to 16 bytes */ uint8_t xmm[8][16]; /* 8 XMM regs */ uint32_t padding1[44]; uint32_t padding2[12]; /* union with struct _fpx_sw_bytes */ }; struct { struct i386_sigcontext_struct sc; struct i386_fpstate fp; uint32_t extramask[1]; } signal_stack; /* On i386, sc is followed on stack by struct fpstate * and after it an additional u32 extramask[1] which holds * upper half of the mask. */ uint32_t sigmask[2]; if (umove(tcp, *i386_esp_ptr, &signal_stack) < 0) return 0; sigmask[0] = signal_stack.sc.oldmask; sigmask[1] = signal_stack.extramask[0]; tprintsigmask_addr(") (mask ", sigmask); } #elif defined(IA64) if (entering(tcp)) { long addr; if (upeek(tcp->pid, PT_R12, &addr) < 0) return 0; /* offsetof(struct sigframe, sc) */ # define OFFSETOF_STRUCT_SIGFRAME_SC 0xA0 addr += 16 + OFFSETOF_STRUCT_SIGFRAME_SC + offsetof(struct sigcontext, sc_mask); tprints(") (mask "); print_sigset_addr_len(tcp, addr, NSIG / 8); } #elif defined(POWERPC) if (entering(tcp)) { long esp = ppc_regs.gpr[1]; struct sigcontext sc; /* Skip dummy stack frame. */ #ifdef POWERPC64 if (current_personality == 0) esp += 128; else #endif esp += 64; tprints(") (mask "); if (umove(tcp, esp, &sc) < 0) { tprintf("%#lx", esp); } else { unsigned long mask[NSIG / 8 / sizeof(long)]; #ifdef POWERPC64 if (current_personality == 0) mask[0] = sc.oldmask | (sc._unused[3] << 32); else #endif { mask[0] = sc.oldmask; mask[1] = sc._unused[3]; } tprintsigmask_val("", mask); } } #elif defined(M68K) if (entering(tcp)) { long usp; struct sigcontext sc; if (upeek(tcp->pid, 4*PT_USP, &usp) < 0) return 0; if (umove(tcp, usp, &sc) < 0) return 0; tprintsigmask_val(") (mask ", sc.sc_mask); } #elif defined(ALPHA) if (entering(tcp)) { long fp; struct sigcontext sc; if (upeek(tcp->pid, REG_FP, &fp) < 0) return 0; if (umove(tcp, fp, &sc) < 0) return 0; tprintsigmask_val(") (mask ", sc.sc_mask); } #elif defined(SPARC) || defined(SPARC64) if (entering(tcp)) { long fp = sparc_regs.u_regs[U_REG_FP] + sizeof(struct sparc_stackf); struct { m_siginfo_t si; void *fpu_save; long insns[2] __attribute__ ((aligned (8))); unsigned int extramask[NSIG / 8 / sizeof(int) - 1]; } frame; tprints(") (mask "); if (umove(tcp, fp, &frame) < 0) { tprintf("%#lx", fp); } else { unsigned int mask[NSIG / 8 / sizeof(int)]; mask[0] = frame.si.si_mask; memcpy(mask + 1, frame.extramask, sizeof(frame.extramask)); tprintsigmask_val("", mask); } } #elif defined MIPS if (entering(tcp)) { # if defined LINUX_MIPSO32 /* * offsetof(struct sigframe, sf_mask) == * sizeof(sf_ass) + sizeof(sf_pad) + sizeof(struct sigcontext) */ const long addr = mips_REG_SP + 6 * 4 + sizeof(struct sigcontext); # else /* * This decodes rt_sigreturn. * The 64-bit ABIs do not have sigreturn. * * offsetof(struct rt_sigframe, rs_uc) == * sizeof(sf_ass) + sizeof(sf_pad) + sizeof(struct siginfo) */ const long addr = mips_REG_SP + 6 * 4 + 128 + offsetof(struct ucontext, uc_sigmask); # endif tprints(") (mask "); print_sigset_addr_len(tcp, addr, NSIG / 8); } #elif defined(CRISV10) || defined(CRISV32) if (entering(tcp)) { struct sigcontext sc; long regs[PT_MAX+1]; if (ptrace(PTRACE_GETREGS, tcp->pid, NULL, (long)regs) < 0) { perror_msg("sigreturn: PTRACE_GETREGS"); return 0; } if (umove(tcp, regs[PT_USP], &sc) < 0) return 0; tprintsigmask_val(") (mask ", sc.oldmask); } #elif defined(TILE) if (entering(tcp)) { struct ucontext uc; /* offset of ucontext in the kernel's sigframe structure */ # define SIGFRAME_UC_OFFSET C_ABI_SAVE_AREA_SIZE + sizeof(siginfo_t) if (umove(tcp, tile_regs.sp + SIGFRAME_UC_OFFSET, &uc) < 0) return 0; tprintsigmask_val(") (mask ", uc.uc_sigmask); } #elif defined(MICROBLAZE) /* TODO: Verify that this is correct... */ if (entering(tcp)) { struct sigcontext sc; long sp; /* Read r1, the stack pointer. */ if (upeek(tcp->pid, 1 * 4, &sp) < 0) return 0; if (umove(tcp, sp, &sc) < 0) return 0; tprintsigmask_val(") (mask ", sc.oldmask); } #else # warning sigreturn/rt_sigreturn signal mask decoding is not implemented for this architecture #endif return 0; } int sys_siggetmask(struct tcb *tcp) { if (exiting(tcp)) { tcp->auxstr = sprintsigmask_val("mask ", tcp->u_rval); } return RVAL_HEX | RVAL_STR; } int sys_sigsuspend(struct tcb *tcp) { if (entering(tcp)) { tprintsigmask_val("", tcp->u_arg[2]); } return 0; } #if !defined SS_ONSTACK #define SS_ONSTACK 1 #define SS_DISABLE 2 #endif #include "xlat/sigaltstack_flags.h" static void print_stack_t(struct tcb *tcp, unsigned long addr) { stack_t ss; int r; if (!addr) { tprints("NULL"); return; } #if SUPPORTED_PERSONALITIES > 1 && SIZEOF_LONG > 4 if (current_wordsize != sizeof(ss.ss_sp) && current_wordsize == 4) { struct { uint32_t ss_sp; int32_t ss_flags; uint32_t ss_size; } ss32; r = umove(tcp, addr, &ss32); if (r >= 0) { memset(&ss, 0, sizeof(ss)); ss.ss_sp = (void*)(unsigned long) ss32.ss_sp; ss.ss_flags = ss32.ss_flags; ss.ss_size = (unsigned long) ss32.ss_size; } } else #endif { r = umove(tcp, addr, &ss); } if (r < 0) { tprintf("%#lx", addr); } else { 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); } } int sys_sigaltstack(struct tcb *tcp) { if (entering(tcp)) { print_stack_t(tcp, tcp->u_arg[0]); } else { tprints(", "); print_stack_t(tcp, tcp->u_arg[1]); } return 0; } #ifdef HAVE_SIGACTION /* "Old" sigprocmask, which operates with word-sized signal masks */ int sys_sigprocmask(struct tcb *tcp) { # ifdef ALPHA if (entering(tcp)) { /* * Alpha/OSF is different: it doesn't pass in two pointers, * but rather passes in the new bitmask as an argument and * then returns the old bitmask. This "works" because we * only have 64 signals to worry about. If you want more, * use of the rt_sigprocmask syscall is required. * Alpha: * old = osf_sigprocmask(how, new); * Everyone else: * ret = sigprocmask(how, &new, &old, ...); */ printxval(sigprocmaskcmds, tcp->u_arg[0], "SIG_???"); tprintsigmask_val(", ", tcp->u_arg[1]); } else if (!syserror(tcp)) { tcp->auxstr = sprintsigmask_val("old mask ", tcp->u_rval); return RVAL_HEX | RVAL_STR; } # else /* !ALPHA */ if (entering(tcp)) { printxval(sigprocmaskcmds, tcp->u_arg[0], "SIG_???"); tprints(", "); print_sigset_addr_len(tcp, tcp->u_arg[1], current_wordsize); tprints(", "); } else { if (syserror(tcp)) tprintf("%#lx", tcp->u_arg[2]); else print_sigset_addr_len(tcp, tcp->u_arg[2], current_wordsize); } # endif /* !ALPHA */ return 0; } #endif /* HAVE_SIGACTION */ int sys_kill(struct tcb *tcp) { if (entering(tcp)) { tprintf("%ld, %s", widen_to_long(tcp->u_arg[0]), signame(tcp->u_arg[1]) ); } return 0; } int sys_tgkill(struct tcb *tcp) { if (entering(tcp)) { tprintf("%ld, %ld, %s", widen_to_long(tcp->u_arg[0]), widen_to_long(tcp->u_arg[1]), signame(tcp->u_arg[2]) ); } return 0; } int sys_sigpending(struct tcb *tcp) { if (exiting(tcp)) { if (syserror(tcp)) tprintf("%#lx", tcp->u_arg[0]); else print_sigset_addr_len(tcp, tcp->u_arg[0], current_wordsize); } return 0; } int sys_rt_sigprocmask(struct tcb *tcp) { /* Note: arg[3] is the length of the sigset. Kernel requires NSIG / 8 */ if (entering(tcp)) { printxval(sigprocmaskcmds, tcp->u_arg[0], "SIG_???"); tprints(", "); print_sigset_addr_len(tcp, tcp->u_arg[1], tcp->u_arg[3]); tprints(", "); } else { if (syserror(tcp)) tprintf("%#lx", tcp->u_arg[2]); else print_sigset_addr_len(tcp, tcp->u_arg[2], tcp->u_arg[3]); tprintf(", %lu", tcp->u_arg[3]); } return 0; } /* Structure describing the action to be taken when a signal arrives. */ struct new_sigaction { /* sa_handler may be a libc #define, need to use other name: */ #ifdef MIPS unsigned int sa_flags; void (*__sa_handler)(int); #else void (*__sa_handler)(int); unsigned long sa_flags; #endif /* !MIPS */ #if HAVE_SA_RESTORER void (*sa_restorer)(void); #endif /* 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; #if HAVE_SA_RESTORER uint32_t sa_restorer; #endif uint32_t sa_mask[2 * (NSIG / sizeof(long) ? NSIG / sizeof(long) : 1)]; }; static void decode_new_sigaction(struct tcb *tcp, long addr) { struct new_sigaction sa; int r; if (!addr) { tprints("NULL"); return; } if (!verbose(tcp) || (exiting(tcp) && syserror(tcp))) { tprintf("%#lx", addr); return; } #if SUPPORTED_PERSONALITIES > 1 && SIZEOF_LONG > 4 if (current_wordsize != sizeof(sa.sa_flags) && current_wordsize == 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; #if HAVE_SA_RESTORER && defined SA_RESTORER sa.sa_restorer = (void*)(unsigned long)sa32.sa_restorer; #endif /* 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("{...}"); return; } /* 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); /* * Sigset size is in tcp->u_arg[4] (SPARC) * or in tcp->u_arg[3] (all other), * but kernel won't handle sys_rt_sigaction * with wrong sigset size (just returns EINVAL instead). * We just fetch the right size, which is NSIG / 8. */ tprintsigmask_val("", sa.sa_mask); tprints(", "); printflags(sigact_flags, sa.sa_flags, "SA_???"); #if HAVE_SA_RESTORER && defined SA_RESTORER if (sa.sa_flags & SA_RESTORER) tprintf(", %p", sa.sa_restorer); #endif tprints("}"); } int sys_rt_sigaction(struct tcb *tcp) { if (entering(tcp)) { printsignal(tcp->u_arg[0]); tprints(", "); decode_new_sigaction(tcp, tcp->u_arg[1]); tprints(", "); } else { decode_new_sigaction(tcp, tcp->u_arg[2]); #if defined(SPARC) || defined(SPARC64) 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) { if (exiting(tcp)) { /* * One of the few syscalls where sigset size (arg[1]) * is allowed to be <= NSIG / 8, not strictly ==. * This allows non-rt sigpending() syscall * to reuse rt_sigpending() code in kernel. */ if (syserror(tcp)) tprintf("%#lx", tcp->u_arg[0]); else print_sigset_addr_len(tcp, tcp->u_arg[0], tcp->u_arg[1]); tprintf(", %lu", tcp->u_arg[1]); } return 0; } int sys_rt_sigsuspend(struct tcb *tcp) { if (entering(tcp)) { /* NB: kernel requires arg[1] == NSIG / 8 */ print_sigset_addr_len(tcp, tcp->u_arg[0], tcp->u_arg[1]); tprintf(", %lu", tcp->u_arg[1]); } return 0; } static void print_sigqueueinfo(struct tcb *tcp, int sig, unsigned long uinfo) { printsignal(sig); tprints(", "); printsiginfo_at(tcp, uinfo); } int sys_rt_sigqueueinfo(struct tcb *tcp) { if (entering(tcp)) { tprintf("%lu, ", tcp->u_arg[0]); print_sigqueueinfo(tcp, tcp->u_arg[1], tcp->u_arg[2]); } return 0; } int sys_rt_tgsigqueueinfo(struct tcb *tcp) { if (entering(tcp)) { tprintf("%lu, %lu, ", tcp->u_arg[0], tcp->u_arg[1]); print_sigqueueinfo(tcp, tcp->u_arg[2], tcp->u_arg[3]); } return 0; } int sys_rt_sigtimedwait(struct tcb *tcp) { /* NB: kernel requires arg[3] == NSIG / 8 */ if (entering(tcp)) { print_sigset_addr_len(tcp, tcp->u_arg[0], tcp->u_arg[3]); 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 */ printsiginfo_at(tcp, tcp->u_arg[1]); tprints(", "); } else { /* syscall exit, and u_arg[1] was NULL */ return 0; } print_timespec(tcp, tcp->u_arg[2]); tprintf(", %lu", 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) { /* NB: kernel requires arg[2] == NSIG / 8 */ if (entering(tcp)) { printfd(tcp, tcp->u_arg[0]); tprints(", "); print_sigset_addr_len(tcp, tcp->u_arg[1], tcp->u_arg[2]); 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); }