X-Git-Url: https://granicus.if.org/sourcecode?a=blobdiff_plain;f=signal.c;h=06864d1beb95b5869ad8302db51b3c43abc8730a;hb=3138213bc9a827a372ad9f8009ebcc5d8797ce2d;hp=7f39fe9a61923749205ad45c2004f7aedc4813cc;hpb=10a88d09ebe283d0dd2ba5deccfe50dc20ea5821;p=strace diff --git a/signal.c b/signal.c index 7f39fe9a..06864d1b 100644 --- a/signal.c +++ b/signal.c @@ -35,6 +35,7 @@ #include "defs.h" +#include #include #include #include @@ -53,7 +54,15 @@ #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 @@ -63,31 +72,24 @@ # include #endif /* !IA64 */ -#if HAVE_ASM_REG_H -#ifdef SPARC -# define fpq kernel_fpq -# define fq kernel_fq -# define fpu kernel_fpu -#endif -#include -#ifdef SPARC -# undef fpq -# undef fq -# undef fpu -#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 */ -#endif /* HAVE_ASM_REG_H */ -#ifdef HAVE_ASM_SIGCONTEXT_H -#ifdef SPARC +#if defined (SPARC) || defined (SPARC64) || defined (MIPS) typedef struct { - struct regs si_regs; + struct pt_regs si_regs; int si_mask; } m_siginfo_t; -#elif !defined(IA64) && !defined(X86_64) +#elif defined HAVE_ASM_SIGCONTEXT_H +#if !defined(IA64) && !defined(X86_64) #include -#endif /* SPARC */ +#endif /* !IA64 && !X86_64 */ #else /* !HAVE_ASM_SIGCONTEXT_H */ -#ifdef I386 +#if defined I386 && !defined HAVE_STRUCT_SIGCONTEXT_STRUCT struct sigcontext_struct { unsigned short gs, __gsh; unsigned short fs, __fsh; @@ -113,7 +115,7 @@ struct sigcontext_struct { unsigned long cr2; }; #else /* !I386 */ -#ifdef M68K +#if defined M68K && !defined HAVE_STRUCT_SIGCONTEXT struct sigcontext { unsigned long sc_mask; @@ -138,31 +140,31 @@ struct sigcontext #endif #endif /* LINUX */ -char *signalent0[] = { +const char *const signalent0[] = { #include "signalent.h" }; -int nsignals0 = sizeof signalent0 / sizeof signalent0[0]; +const int nsignals0 = sizeof signalent0 / sizeof signalent0[0]; #if SUPPORTED_PERSONALITIES >= 2 -char *signalent1[] = { +const char *const signalent1[] = { #include "signalent1.h" }; -int nsignals1 = sizeof signalent1 / sizeof signalent1[0]; +const int nsignals1 = sizeof signalent1 / sizeof signalent1[0]; #endif /* SUPPORTED_PERSONALITIES >= 2 */ #if SUPPORTED_PERSONALITIES >= 3 -char *signalent2[] = { +const char *const signalent2[] = { #include "signalent2.h" }; -int nsignals2 = sizeof signalent2 / sizeof signalent2[0]; +const int nsignals2 = sizeof signalent2 / sizeof signalent2[0]; #endif /* SUPPORTED_PERSONALITIES >= 3 */ -char **signalent; +const char *const *signalent; int nsignals; #if defined(SUNOS4) || defined(FREEBSD) -static struct xlat sigvec_flags[] = { +static const struct xlat sigvec_flags[] = { { SV_ONSTACK, "SV_ONSTACK" }, { SV_INTERRUPT, "SV_INTERRUPT" }, { SV_RESETHAND, "SV_RESETHAND" }, @@ -174,7 +176,15 @@ static struct xlat sigvec_flags[] = { #ifdef HAVE_SIGACTION -static struct xlat sigact_flags[] = { +#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 wwe 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 @@ -187,10 +197,16 @@ static struct xlat sigact_flags[] = { #ifdef SA_INTERRUPT { SA_INTERRUPT, "SA_INTERRUPT" }, #endif -#ifdef SA_NOMASK +#ifdef SA_NODEFER + { SA_NODEFER, "SA_NODEFER" }, +#endif +#if defined SA_NOMASK && SA_NODEFER != SA_NOMASK { SA_NOMASK, "SA_NOMASK" }, #endif -#ifdef SA_ONESHOT +#ifdef SA_RESETHAND + { SA_RESETHAND, "SA_RESETHAND" }, +#endif +#if defined SA_ONESHOT && SA_ONESHOT != SA_RESETHAND { SA_ONESHOT, "SA_ONESHOT" }, #endif #ifdef SA_SIGINFO @@ -213,11 +229,14 @@ static struct xlat sigact_flags[] = { #endif #ifdef _SA_BSDCALL { _SA_BSDCALL, "_SA_BSDCALL" }, +#endif +#ifdef SA_NOPTRACE + { SA_NOPTRACE, "SA_NOPTRACE" }, #endif { 0, NULL }, }; -static struct xlat sigprocmaskcmds[] = { +static const struct xlat sigprocmaskcmds[] = { { SIG_BLOCK, "SIG_BLOCK" }, { SIG_UNBLOCK, "SIG_UNBLOCK" }, { SIG_SETMASK, "SIG_SETMASK" }, @@ -239,12 +258,12 @@ static struct xlat sigprocmaskcmds[] = { #endif #endif -char * +const char * signame(sig) int sig; { static char buf[30]; - if (sig < nsignals) { + if (sig >= 0 && sig < nsignals) { return signalent[sig]; #ifdef SIGRTMIN } else if (sig >= __SIGRTMIN && sig <= __SIGRTMAX) { @@ -290,18 +309,17 @@ int len; #define copy_sigset(tcp, addr, s) copy_sigset_len(tcp, addr, s, sizeof(sigset_t)) #endif -static char * -sprintsigmask(s, mask, rt) -char *s; -sigset_t *mask; -int rt; /* set might include realtime sigs */ +static const char * +sprintsigmask(const char *str, sigset_t *mask, int rt) +/* set might include realtime sigs */ { int i, nsigs; int maxsigs; - char *format; - static char outstr[256]; + const char *format; + char *s; + static char outstr[8 * sizeof(sigset_t) * 8]; - strcpy(outstr, s); + strcpy(outstr, str); s = outstr + strlen(outstr); nsigs = 0; maxsigs = nsignals; @@ -336,6 +354,13 @@ int rt; /* set might include realtime sigs */ 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); @@ -362,7 +387,20 @@ void printsignal(nr) int nr; { - tprintf(signame(nr)); + tprintf("%s", signame(nr)); +} + +void +print_sigset(struct tcb *tcp, long addr, int rt) +{ + sigset_t ss; + + if (!addr) + tprintf("NULL"); + else if (copy_sigset(tcp, addr, &ss) < 0) + tprintf("%#lx", addr); + else + printsigmask(&ss, rt); } #ifdef LINUX @@ -408,6 +446,8 @@ int nr; #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 */ #endif #if __GLIBC_MINOR__ < 1 @@ -496,7 +536,7 @@ typedef struct siginfo #if defined (SVR4) || defined (LINUX) -static struct xlat siginfo_codes[] = { +static const struct xlat siginfo_codes[] = { #ifdef SI_NOINFO { SI_NOINFO, "SI_NOINFO" }, #endif @@ -517,11 +557,17 @@ static struct xlat siginfo_codes[] = { #endif #ifdef SI_MESGQ { SI_MESGQ, "SI_MESGQ" }, +#endif +#ifdef SI_SIGIO + { SI_SIGIO, "SI_SIGIO" }, +#endif +#ifdef SI_TKILL + { SI_TKILL, "SI_TKILL" }, #endif { 0, NULL }, }; -static struct xlat sigill_codes[] = { +static const struct xlat sigill_codes[] = { { ILL_ILLOPC, "ILL_ILLOPC" }, { ILL_ILLOPN, "ILL_ILLOPN" }, { ILL_ILLADR, "ILL_ILLADR" }, @@ -533,7 +579,7 @@ static struct xlat sigill_codes[] = { { 0, NULL }, }; -static struct xlat sigfpe_codes[] = { +static const struct xlat sigfpe_codes[] = { { FPE_INTDIV, "FPE_INTDIV" }, { FPE_INTOVF, "FPE_INTOVF" }, { FPE_FLTDIV, "FPE_FLTDIV" }, @@ -545,13 +591,13 @@ static struct xlat sigfpe_codes[] = { { 0, NULL }, }; -static struct xlat sigtrap_codes[] = { +static const struct xlat sigtrap_codes[] = { { TRAP_BRKPT, "TRAP_BRKPT" }, { TRAP_TRACE, "TRAP_TRACE" }, { 0, NULL }, }; -static struct xlat sigchld_codes[] = { +static const struct xlat sigchld_codes[] = { { CLD_EXITED, "CLD_EXITED" }, { CLD_KILLED, "CLD_KILLED" }, { CLD_DUMPED, "CLD_DUMPED" }, @@ -561,7 +607,7 @@ static struct xlat sigchld_codes[] = { { 0, NULL }, }; -static struct xlat sigpoll_codes[] = { +static const struct xlat sigpoll_codes[] = { { POLL_IN, "POLL_IN" }, { POLL_OUT, "POLL_OUT" }, { POLL_MSG, "POLL_MSG" }, @@ -571,7 +617,7 @@ static struct xlat sigpoll_codes[] = { { 0, NULL }, }; -static struct xlat sigprof_codes[] = { +static const struct xlat sigprof_codes[] = { #ifdef PROF_SIG { PROF_SIG, "PROF_SIG" }, #endif @@ -579,7 +625,7 @@ static struct xlat sigprof_codes[] = { }; #ifdef SIGEMT -static struct xlat sigemt_codes[] = { +static const struct xlat sigemt_codes[] = { #ifdef EMT_TAGOVF { EMT_TAGOVF, "EMT_TAGOVF" }, #endif @@ -587,13 +633,13 @@ static struct xlat sigemt_codes[] = { }; #endif -static struct xlat sigsegv_codes[] = { +static const struct xlat sigsegv_codes[] = { { SEGV_MAPERR, "SEGV_MAPERR" }, { SEGV_ACCERR, "SEGV_ACCERR" }, { 0, NULL }, }; -static struct xlat sigbus_codes[] = { +static const struct xlat sigbus_codes[] = { { BUS_ADRALN, "BUS_ADRALN" }, { BUS_ADRERR, "BUS_ADRERR" }, { BUS_OBJERR, "BUS_OBJERR" }, @@ -605,7 +651,7 @@ printsiginfo(sip, verbose) siginfo_t *sip; int verbose; { - char *code; + const char *code; if (sip->si_signo == 0) { tprintf ("{}"); @@ -728,7 +774,7 @@ int verbose; (unsigned long) sip->si_ptr); } #endif - + } } } @@ -740,18 +786,26 @@ int verbose; #ifdef LINUX static void -parse_sigset_t (const char *str, sigset_t *set) +parse_sigset_t(const char *str, sigset_t *set) { + const char *p; unsigned int digit; int i; sigemptyset(set); - for (i = _NSIG - 4; i >= 0; i -= 4, ++str) { - if (*str >= 'a') - digit = (*str - 'a') + 10; + p = strchr(str, '\n'); + if (p == NULL) + p = strchr(str, '\0'); + for (i = 0; p-- > str; i += 4) { + if (*p >= '0' && *p <= '9') + digit = *p - '0'; + else if (*p >= 'a' && *p <= 'f') + digit = *p - 'a' + 10; + else if (*p >= 'A' && *p <= 'F') + digit = *p - 'A' + 10; else - digit = *str - '0'; + break; if (digit & 1) sigaddset(set, i + 1); if (digit & 2) @@ -779,7 +833,7 @@ int sig; int sfd; char sname[32]; char buf[2048]; - char *s; + const char *s; int i; sigset_t ignored, caught; #endif @@ -853,7 +907,7 @@ int sig; #ifdef SUNOS4 void (*u_signal)(); - if (upeek(tcp->pid, uoff(u_signal[0]) + sig*sizeof(u_signal), + if (upeek(tcp, uoff(u_signal[0]) + sig*sizeof(u_signal), (long *) &u_signal) < 0) { return 0; } @@ -916,8 +970,7 @@ struct tcb *tcp; tprintf("{%#lx, ", (unsigned long) sv.sv_handler); printsigmask(&sv.sv_mask, 0); tprintf(", "); - if (!printflags(sigvec_flags, sv.sv_flags)) - tprintf("0"); + printflags(sigvec_flags, sv.sv_flags, "SV_???"); tprintf("}"); } } @@ -988,7 +1041,7 @@ struct tcb *tcp; /* Send unblockable signal */ kill(tcp->pid, SIGSTOP); } -#endif /* !USE_PROCFS */ +#endif /* !USE_PROCFS */ } else if (!syserror(tcp)) { sigset_t sigm; @@ -1000,12 +1053,14 @@ struct tcb *tcp; return 0; } +#if defined(SUNOS4) || defined(FREEBSD) int sys_sigblock(tcp) struct tcb *tcp; { return sys_sigsetmask(tcp); } +#endif /* SUNOS4 || FREEBSD */ #endif /* !SVR4 */ @@ -1021,8 +1076,8 @@ struct old_sigaction { #define SA_HANDLER __sa_handler #endif /* LINUX */ -#ifndef SA_HANDLER -#define SA_HANDLER sa_handler +#ifndef SA_HANDLER +#define SA_HANDLER sa_handler #endif int @@ -1051,23 +1106,28 @@ struct tcb *tcp; else if (umove(tcp, addr, &sa) < 0) tprintf("{...}"); else { - switch ((long) sa.SA_HANDLER) { - case (long) SIG_ERR: - tprintf("{SIG_ERR}"); - break; - case (long) SIG_DFL: - tprintf("{SIG_DFL}"); - break; - case (long) SIG_IGN: + /* 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) + tprintf("{SIG_ERR, "); + else if ((long)sa.SA_HANDLER == (long)SIG_DFL) + tprintf("{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 */ - tprintf("{SIG_IGN}"); - break; - default: + tprintf("{SIG_IGN, "); + } + else { #ifndef USE_PROCFS if (tcp->u_arg[0] == SIGTRAP) { tcp->flags |= TCB_SIGTRAPPED; @@ -1082,8 +1142,11 @@ struct tcb *tcp; printsigmask(&sigset, 0); #endif tprintf(", "); - if (!printflags(sigact_flags, sa.sa_flags)) - tprintf("0"); + printflags(sigact_flags, sa.sa_flags, "SA_???"); +#ifdef SA_RESTORER + if (sa.sa_flags & SA_RESTORER) + tprintf(", %p", sa.sa_restorer); +#endif tprintf("}"); } } @@ -1104,13 +1167,13 @@ struct tcb *tcp; printsignal(tcp->u_arg[0]); tprintf(", "); switch (tcp->u_arg[1]) { - case (int) SIG_ERR: + case (long) SIG_ERR: tprintf("SIG_ERR"); break; - case (int) SIG_DFL: + case (long) SIG_DFL: tprintf("SIG_DFL"); break; - case (int) SIG_IGN: + case (long) SIG_IGN: #ifndef USE_PROCFS if (tcp->u_arg[0] == SIGTRAP) { tcp->flags |= TCB_SIGTRAPPED; @@ -1130,21 +1193,23 @@ struct tcb *tcp; } return 0; } - else { + else if (!syserror(tcp)) { switch (tcp->u_rval) { - case (int) SIG_ERR: + case (long) SIG_ERR: tcp->auxstr = "SIG_ERR"; break; - case (int) SIG_DFL: + case (long) SIG_DFL: tcp->auxstr = "SIG_DFL"; break; - case (int) SIG_IGN: + 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(tcp) struct tcb *tcp; @@ -1154,43 +1219,67 @@ struct tcb *tcp; } return 0; } +#endif /* SVR4 */ #endif /* HAVE_SIGACTION */ #ifdef LINUX int -sys_sigreturn(tcp) -struct tcb *tcp; +sys_sigreturn(struct tcb *tcp) { -#if defined(S390) || defined(S390X) - long usp; - struct sigcontext_struct sc; - - if (entering(tcp)) { - tcp->u_arg[0] = 0; - if (upeek(tcp->pid,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],sizeof(sigset_t)); - } 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; -#else -#ifdef I386 +#if defined(ARM) + struct pt_regs regs; + struct sigcontext_struct sc; + + if (entering(tcp)) { + 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; + long_to_sigset(tcp->u_arg[1], &sigm); + tcp->u_rval = tcp->u_error = 0; + if (tcp->u_arg[0] == 0) + return 0; + tcp->auxstr = sprintsigmask("mask now ", &sigm, 0); + return RVAL_NONE | RVAL_STR; + } + return 0; +#elif defined(S390) || defined(S390X) + long usp; + struct sigcontext_struct sc; + + if (entering(tcp)) { + 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],sizeof(sigset_t)); + } 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) long esp; struct sigcontext_struct sc; if (entering(tcp)) { tcp->u_arg[0] = 0; - if (upeek(tcp->pid, 4*UESP, &esp) < 0) + if (upeek(tcp, 4*UESP, &esp) < 0) return 0; if (umove(tcp, esp, &sc) < 0) return 0; @@ -1207,8 +1296,7 @@ struct tcb *tcp; return RVAL_NONE | RVAL_STR; } return 0; -#else /* !I386 */ -#ifdef IA64 +#elif defined(IA64) struct sigcontext sc; long sp; @@ -1216,7 +1304,7 @@ struct tcb *tcp; /* offset of sigcontext in the kernel's sigframe structure: */ # define SIGFRAME_SC_OFFSET 0x90 tcp->u_arg[0] = 0; - if (upeek(tcp->pid, PT_R12, &sp) < 0) + if (upeek(tcp, PT_R12, &sp) < 0) return 0; if (umove(tcp, sp + 16 + SIGFRAME_SC_OFFSET, &sc) < 0) return 0; @@ -1234,91 +1322,96 @@ struct tcb *tcp; return RVAL_NONE | RVAL_STR; } return 0; -#else /* !IA64 */ -#ifdef POWERPC - long esp; - struct sigcontext_struct sc; - - if (entering(tcp)) { - tcp->u_arg[0] = 0; - if (upeek(tcp->pid, 4*PT_R1, &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; - long_to_sigset(tcp->u_arg[1], &sigm); - tcp->u_rval = tcp->u_error = 0; - if (tcp->u_arg[0] == 0) - return 0; - tcp->auxstr = sprintsigmask("mask now ", &sigm, 0); - return RVAL_NONE | RVAL_STR; - } - return 0; -#else /* !POWERPC */ -#ifdef M68K +#elif defined(POWERPC) + long esp; + struct sigcontext_struct sc; + + if (entering(tcp)) { + 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; + long_to_sigset(tcp->u_arg[1], &sigm); + tcp->u_rval = tcp->u_error = 0; + if (tcp->u_arg[0] == 0) + return 0; + tcp->auxstr = sprintsigmask("mask now ", &sigm, 0); + return RVAL_NONE | RVAL_STR; + } + return 0; +#elif defined(M68K) long usp; struct sigcontext sc; if (entering(tcp)) { - tcp->u_arg[0] = 0; - if (upeek(tcp->pid, 4*PT_USP, &usp) < 0) + tcp->u_arg[0] = 0; + if (upeek(tcp, 4*PT_USP, &usp) < 0) return 0; - if (umove(tcp, usp, &sc) < 0) + if (umove(tcp, usp, &sc) < 0) return 0; - tcp->u_arg[0] = 1; - tcp->u_arg[1] = sc.sc_mask; + tcp->u_arg[0] = 1; + tcp->u_arg[1] = sc.sc_mask; } else { - sigset_t sigm; - long_to_sigset(tcp->u_arg[1], &sigm); - tcp->u_rval = tcp->u_error = 0; - if (tcp->u_arg[0] == 0) + sigset_t sigm; + long_to_sigset(tcp->u_arg[1], &sigm); + tcp->u_rval = tcp->u_error = 0; + if (tcp->u_arg[0] == 0) return 0; - tcp->auxstr = sprintsigmask("mask now ", &sigm, 0); - return RVAL_NONE | RVAL_STR; + tcp->auxstr = sprintsigmask("mask now ", &sigm, 0); + return RVAL_NONE | RVAL_STR; } return 0; -#else /* !M68K */ -#ifdef ALPHA +#elif defined(ALPHA) long fp; struct sigcontext_struct sc; if (entering(tcp)) { - tcp->u_arg[0] = 0; - if (upeek(tcp->pid, REG_FP, &fp) < 0) + tcp->u_arg[0] = 0; + if (upeek(tcp, REG_FP, &fp) < 0) return 0; - if (umove(tcp, fp, &sc) < 0) + if (umove(tcp, fp, &sc) < 0) return 0; - tcp->u_arg[0] = 1; - tcp->u_arg[1] = sc.sc_mask; + tcp->u_arg[0] = 1; + tcp->u_arg[1] = sc.sc_mask; } else { - sigset_t sigm; - long_to_sigset(tcp->u_arg[1], &sigm); - tcp->u_rval = tcp->u_error = 0; - if (tcp->u_arg[0] == 0) + sigset_t sigm; + long_to_sigset(tcp->u_arg[1], &sigm); + tcp->u_rval = tcp->u_error = 0; + if (tcp->u_arg[0] == 0) return 0; - tcp->auxstr = sprintsigmask("mask now ", &sigm, 0); - return RVAL_NONE | RVAL_STR; + tcp->auxstr = sprintsigmask("mask now ", &sigm, 0); + return RVAL_NONE | RVAL_STR; } return 0; -#else -#ifdef SPARC +#elif defined (SPARC) || defined (SPARC64) long i1; - struct regs regs; + struct pt_regs regs; m_siginfo_t si; if(ptrace(PTRACE_GETREGS, tcp->pid, (char *)®s, 0) < 0) { - perror("sigreturn: PTRACE_GETREGS "); - return 0; + perror("sigreturn: PTRACE_GETREGS "); + return 0; } if(entering(tcp)) { tcp->u_arg[0] = 0; - i1 = regs.r_o1; + i1 = regs.u_regs[U_REG_O1]; if(umove(tcp, i1, &si) < 0) { perror("sigreturn: umove "); return 0; @@ -1335,24 +1428,134 @@ struct tcb *tcp; return RVAL_NONE | RVAL_STR; } return 0; -#else -#ifdef MIPS +#elif defined (LINUX_MIPSN32) || defined (LINUX_MIPSN64) + /* This decodes rt_sigreturn. The 64-bit ABIs do not have + sigreturn. */ long sp; - struct sigcontext sc; + struct ucontext uc; if(entering(tcp)) { - tcp->u_arg[0] = 0; - if (upeek(tcp->pid, REG_SP, &sp) < 0) - return 0; - if (umove(tcp, sp, &sc) < 0) - return 0; + 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; + long_to_sigset(tcp->u_arg[1], &sigm); + tcp->u_rval = tcp->u_error = 0; + if(tcp->u_arg[0] == 0) + return 0; + tcp->auxstr = sprintsigmask("mask now ", &sigm, 0); + return RVAL_NONE | RVAL_STR; + } + return 0; +#elif defined(MIPS) + long sp; + struct pt_regs regs; + m_siginfo_t si; + + if(ptrace(PTRACE_GETREGS, tcp->pid, (char *)®s, 0) < 0) { + perror("sigreturn: PTRACE_GETREGS "); + return 0; + } + if(entering(tcp)) { + tcp->u_arg[0] = 0; + sp = regs.regs[29]; + if (umove(tcp, sp, &si) < 0) tcp->u_arg[0] = 1; - tcp->u_arg[1] = sc.sc_sigset; + tcp->u_arg[1] = si.si_mask; } else { - tcp->u_rval = tcp->u_error = 0; + sigset_t sigm; + long_to_sigset(tcp->u_arg[1], &sigm); + tcp->u_rval = tcp->u_error = 0; if(tcp->u_arg[0] == 0) - return 0; - tcp->auxstr = sprintsigmask("mask now ", tcp->u_arg[1]); + return 0; + tcp->auxstr = sprintsigmask("mask now ", &sigm, 0); + return RVAL_NONE | RVAL_STR; + } + return 0; +#elif defined(CRISV10) || defined(CRISV32) + struct sigcontext sc; + + if (entering(tcp)) { + 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; + long_to_sigset(tcp->u_arg[1], &sigm); + tcp->u_rval = tcp->u_error = 0; + + if (tcp->u_arg[0] == 0) + return 0; + tcp->auxstr = sprintsigmask("mask now ", &sigm, 0); + return RVAL_NONE | RVAL_STR; + } + return 0; +#elif defined(TILE) + 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) + + if (entering(tcp)) { + 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, sizeof(uc.uc_sigmask)); + } + else { + sigset_t sigm; + + memcpy(&sigm, tcp->u_arg + 1, sizeof (sigm)); + tcp->u_rval = tcp->u_error = 0; + if (tcp->u_arg[0] == 0) + return 0; + tcp->auxstr = sprintsigmask("mask now ", &sigm, 0); + return RVAL_NONE | RVAL_STR; + } + return 0; +#elif defined(MICROBLAZE) + struct sigcontext sc; + + /* TODO: Verify that this is correct... */ + if (entering(tcp)) { + 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; + long_to_sigset(tcp->u_arg[1], &sigm); + tcp->u_rval = tcp->u_error = 0; + if (tcp->u_arg[0] == 0) + return 0; + tcp->auxstr = sprintsigmask("mask now ", &sigm, 0); return RVAL_NONE | RVAL_STR; } return 0; @@ -1360,14 +1563,7 @@ struct tcb *tcp; #warning No sys_sigreturn() for this architecture #warning (no problem, just a reminder :-) return 0; -#endif /* MIPS */ -#endif /* SPARC */ -#endif /* ALPHA */ -#endif /* !M68K */ -#endif /* !POWERPC */ -#endif /* !IA64 */ -#endif /* !I386 */ -#endif /* S390 */ +#endif } int @@ -1383,17 +1579,11 @@ struct tcb *tcp; } int -sys_sigsuspend(tcp) -struct tcb *tcp; +sys_sigsuspend(struct tcb *tcp) { if (entering(tcp)) { sigset_t sigm; long_to_sigset(tcp->u_arg[2], &sigm); -#if 0 - /* first two are not really arguments, but print them anyway */ - /* nevermind, they are an anachronism now, too bad... */ - tprintf("%d, %#x, ", tcp->u_arg[0], tcp->u_arg[1]); -#endif printsigmask(&sigm, 0); } return 0; @@ -1418,7 +1608,7 @@ struct tcb *tcp; return 0; } #ifndef FREEBSD -static struct xlat ucontext_flags[] = { +static const struct xlat ucontext_flags[] = { { UC_SIGMASK, "UC_SIGMASK" }, { UC_STACK, "UC_STACK" }, { UC_CPU, "UC_CPU" }, @@ -1450,7 +1640,7 @@ typedef struct #define stack_t struct sigaltstack #endif -static struct xlat sigaltstack_flags[] = { +static const struct xlat sigaltstack_flags[] = { { SS_ONSTACK, "SS_ONSTACK" }, { SS_DISABLE, "SS_DISABLE" }, { 0, NULL }, @@ -1466,8 +1656,7 @@ ucontext_t *ucp; tprintf("{"); if (!abbrev(tcp)) { tprintf("uc_flags="); - if (!printflags(ucontext_flags, ucp->uc_flags)) - tprintf("0"); + printflags(ucontext_flags, ucp->uc_flags, "UC_???"); tprintf(", uc_link=%#lx, ", (unsigned long) ucp->uc_link); } tprintf("uc_sigmask="); @@ -1476,8 +1665,7 @@ ucontext_t *ucp; tprintf(", uc_stack={ss_sp=%#lx, ss_size=%d, ss_flags=", (unsigned long) ucp->uc_stack.ss_sp, ucp->uc_stack.ss_size); - if (!printflags(sigaltstack_flags, ucp->uc_stack.ss_flags)) - tprintf("0"); + printflags(sigaltstack_flags, ucp->uc_stack.ss_flags, "SS_???"); tprintf("}"); } tprintf(", ...}"); @@ -1538,8 +1726,7 @@ unsigned long addr; if (umove(tcp, addr, &ss) < 0) return -1; tprintf("{ss_sp=%#lx, ss_flags=", (unsigned long) ss.ss_sp); - if (!printflags(sigaltstack_flags, ss.ss_flags)) - tprintf("0"); + printflags(sigaltstack_flags, ss.ss_flags, "SS_???"); tprintf(", ss_size=%lu}", (unsigned long) ss.ss_size); return 0; } @@ -1582,8 +1769,6 @@ struct tcb *tcp; return RVAL_HEX | RVAL_STR; } #else /* !ALPHA */ - sigset_t sigset; - if (entering(tcp)) { #ifdef SVR4 if (tcp->u_arg[0] == 0) @@ -1592,24 +1777,16 @@ struct tcb *tcp; #endif /* SVR4 */ printxval(sigprocmaskcmds, tcp->u_arg[0], "SIG_???"); tprintf(", "); - if (!tcp->u_arg[1]) - tprintf("NULL, "); - else if (copy_sigset(tcp, tcp->u_arg[1], &sigset) < 0) - tprintf("%#lx, ", tcp->u_arg[1]); - else { - printsigmask(&sigset, 0); - tprintf(", "); - } + print_sigset(tcp, tcp->u_arg[1], 0); + tprintf(", "); } else { if (!tcp->u_arg[2]) tprintf("NULL"); else if (syserror(tcp)) tprintf("%#lx", tcp->u_arg[2]); - else if (copy_sigset(tcp, tcp->u_arg[2], &sigset) < 0) - tprintf("[?]"); else - printsigmask(&sigset, 0); + print_sigset(tcp, tcp->u_arg[2], 0); } #endif /* !ALPHA */ return 0; @@ -1622,17 +1799,38 @@ sys_kill(tcp) struct tcb *tcp; { if (entering(tcp)) { - tprintf("%ld, %s", tcp->u_arg[0], signame(tcp->u_arg[1])); + /* + * Sign-extend a 32-bit value when that's what it is. + */ + long pid = tcp->u_arg[0]; + if (personality_wordsize[current_personality] < sizeof pid) + pid = (long) (int) pid; + tprintf("%ld, %s", pid, signame(tcp->u_arg[1])); } return 0; } +#if defined(FREEBSD) || defined(SUNOS4) int sys_killpg(tcp) struct tcb *tcp; { return sys_kill(tcp); } +#endif /* FREEBSD || SUNOS4 */ + +#ifdef LINUX +int +sys_tgkill(tcp) + 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(tcp) @@ -1651,6 +1849,7 @@ struct tcb *tcp; return 0; } +#ifdef SVR4 int sys_sigwait(tcp) struct tcb *tcp; { @@ -1670,6 +1869,7 @@ struct tcb *tcp; } return 0; } +#endif /* SVR4 */ #ifdef LINUX @@ -1711,25 +1911,29 @@ sys_rt_sigprocmask(tcp) /* Structure describing the action to be taken when a signal arrives. */ struct new_sigaction { - union - { - __sighandler_t __sa_handler; - void (*__sa_sigaction) (int, siginfo_t *, void *); - } - __sigaction_handler; + __sighandler_t __sa_handler; unsigned long sa_flags; void (*sa_restorer) (void); - unsigned long int sa_mask[2]; + /* 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(tcp) - struct tcb *tcp; +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]); @@ -1737,43 +1941,86 @@ sys_rt_sigaction(tcp) addr = tcp->u_arg[1]; } else addr = tcp->u_arg[2]; - if (addr == 0) + + if (addr == 0) { tprintf("NULL"); - else if (!verbose(tcp)) + goto after_sa; + } + if (!verbose(tcp)) { tprintf("%#lx", addr); - else if (umove(tcp, addr, &sa) < 0) + 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) { tprintf("{...}"); - else { - switch ((long) sa.__sigaction_handler.__sa_handler) { - case (long) SIG_ERR: - tprintf("{SIG_ERR}"); - break; - case (long) SIG_DFL: - tprintf("{SIG_DFL}"); - break; - case (long) SIG_IGN: - tprintf("{SIG_IGN}"); - break; - default: - tprintf("{%#lx, ", - (long) sa.__sigaction_handler.__sa_handler); - sigemptyset(&sigset); + 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) + tprintf("{SIG_ERR, "); + else if ((long)sa.__sa_handler == (long)SIG_DFL) + tprintf("{SIG_DFL, "); + else if ((long)sa.__sa_handler == (long)SIG_IGN) + tprintf("{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]); + 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]); + 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); - tprintf(", "); - if (!printflags(sigact_flags, sa.sa_flags)) - tprintf("0"); - tprintf("}"); - } - } + else + memcpy(&sigset, &sa.sa_mask, sizeof(sigset)); + printsigmask(&sigset, 1); + tprintf(", "); + printflags(sigact_flags, sa.sa_flags, "SA_???"); +#ifdef SA_RESTORER + if (sa.sa_flags & SA_RESTORER) + tprintf(", %p", sa.sa_restorer); +#endif + tprintf("}"); + + after_sa: if (entering(tcp)) tprintf(", "); else @@ -1782,14 +2029,13 @@ sys_rt_sigaction(tcp) #elif defined(ALPHA) tprintf(", %lu, %#lx", tcp->u_arg[3], tcp->u_arg[4]); #else - tprintf(", %lu", addr = tcp->u_arg[3]); + tprintf(", %lu", tcp->u_arg[3]); #endif return 0; } - int -sys_rt_sigpending(tcp) - struct tcb *tcp; +int +sys_rt_sigpending(struct tcb *tcp) { sigset_t sigset; @@ -1804,9 +2050,9 @@ sys_rt_sigpending(tcp) } return 0; } - int -sys_rt_sigsuspend(tcp) - struct tcb *tcp; + +int +sys_rt_sigsuspend(struct tcb *tcp) { if (entering(tcp)) { sigset_t sigm; @@ -1817,9 +2063,9 @@ sys_rt_sigsuspend(tcp) } return 0; } - int -sys_rt_sigqueueinfo(tcp) - struct tcb *tcp; + +int +sys_rt_sigqueueinfo(struct tcb *tcp) { if (entering(tcp)) { siginfo_t si; @@ -1829,39 +2075,84 @@ sys_rt_sigqueueinfo(tcp) if (umove(tcp, tcp->u_arg[2], &si) < 0) tprintf("%#lx", tcp->u_arg[2]); else - printsiginfo(&si, verbose (tcp)); + printsiginfo(&si, verbose(tcp)); } return 0; } -int sys_rt_sigtimedwait(tcp) - struct tcb *tcp; +int sys_rt_sigtimedwait(struct tcb *tcp) { if (entering(tcp)) { sigset_t sigset; - if (copy_sigset_len(tcp, tcp->u_arg[0], + if (copy_sigset_len(tcp, tcp->u_arg[0], &sigset, tcp->u_arg[3]) < 0) tprintf("[?]"); else printsigmask(&sigset, 1); tprintf(", "); + /* This is the only "return" parameter, */ + if (tcp->u_arg[1] != 0) + return 0; + /* ... if it's NULL, can decode all on entry */ + tprintf("NULL, "); } - else { + else if (tcp->u_arg[1] != 0) { + /* syscall exit, and u_arg[1] wasn't NULL */ if (syserror(tcp)) - tprintf("%#lx", tcp->u_arg[0]); + 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)); - /* XXX For now */ - tprintf(", %#lx", tcp->u_arg[2]); - tprintf(", %d", (int) tcp->u_arg[3]); + tprintf("%#lx, ", tcp->u_arg[1]); + else { + printsiginfo(&si, verbose(tcp)); + tprintf(", "); + } } } + 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)) + tprintf("<... resuming interrupted call ...>"); + return 0; +} + +static int +do_signalfd(struct tcb *tcp, int flags_arg) +{ + if (entering(tcp)) { + printfd(tcp, tcp->u_arg[0]); + tprintf(", "); + print_sigset(tcp, tcp->u_arg[1], 1); + tprintf(", %lu", tcp->u_arg[2]); + if (flags_arg >= 0) { + tprintf(", "); + 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 */