strace/signal.c

1436 lines
34 KiB
C
Raw Normal View History

1999-02-19 03:21:36 +03:00
/*
* Copyright (c) 1991, 1992 Paul Kranenburg <pk@cs.few.eur.nl>
* Copyright (c) 1993 Branko Lankester <branko@hacktic.nl>
* Copyright (c) 1993, 1994, 1995, 1996 Rick Sladkey <jrs@world.std.com>
1999-12-23 17:20:14 +03:00
* Copyright (c) 1996-1999 Wichert Akkerman <wichert@cistron.nl>
* Copyright (c) 1999 IBM Deutschland Entwicklung GmbH, IBM Corporation
* Linux for s390 port by D.J. Barrow
* <barrow_dj@mail.yahoo.com,djbarrow@de.ibm.com>
1999-02-19 03:21:36 +03:00
* 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 <sys/user.h>
#include <fcntl.h>
#ifdef HAVE_SYS_REG_H
# include <sys/reg.h>
# 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 <linux/ptrace.h>
# undef ia64_fpreg
# undef pt_all_user_regs
1999-10-06 17:06:34 +04:00
#endif
2000-02-04 00:58:30 +03:00
#ifdef IA64
# include <asm/ptrace_offsets.h>
#endif
2000-02-04 00:58:30 +03:00
#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
Add x32 support to strace X32 support is added to Linux kernel 3.4. In a nutshell, x32 is x86-64 with 32bit pointers. At system call level, x32 is also identical to x86-64, as shown by many changes like "defined(X86_64) || defined(X32)". The main differerence bewteen x32 and x86-64 is off_t in x32 is long long instead of long. This patch adds x32 support to strace. Tested on Linux/x32. * configure.ac: Support X32. * defs.h: Set SUPPORTED_PERSONALITIES to 3 for X86_64, Set PERSONALITY2_WORDSIZE to 4 for X86_64. Add tcb::ext_arg for X32. * file.c (stat): New for X32. (sys_lseek): Use 64-bit version for X32. (printstat64): Check current_personality != 1 for X86_64. * ipc.c (indirect_ipccall): Check current_personality == 1 for X86_64. * mem.c (sys_mmap64): Also use tcp->u_arg for X32. Print NULL for zero address. Call printllval for offset for X32. * pathtrace.c (pathtrace_match): Don't check sys_old_mmap for X32. * process.c (ARG_FLAGS): Defined for X32. (ARG_STACK): Likewise. (ARG_PTID): Likewise. (change_syscall): Handle X32. (struct_user_offsets): Support X32. (sys_arch_prctl): Likewise. * signal.c: Include <asm/sigcontext.h> for X32. (SA_RESTORER): Also define for X32. * syscall.c (update_personality): Support X32 for X86_64. (is_restart_error): Likewise. (syscall_fixup_on_sysenter): Likewise. (get_syscall_args): Likewise. (get_syscall_result): Likewise. (get_error): Likewise. (__X32_SYSCALL_BIT): Define if not defined. (__X32_SYSCALL_MASK): Likewise. (get_scno): Check DS register value for X32. Use __X32_SYSCALL_MASK on X32 system calls. * util.c (printllval): Use ext_arg for X32. (printcall): Support X32. (change_syscall): Likewise. (arg0_offset): Likewise. (arg1_offset): Likewise. * Makefile.am (EXTRA_DIST): Add linux/x32/errnoent.h, linux/x32/ioctlent.h.in, linux/x32/signalent.h, linux/x32/syscallent.h, linux/x86_64/errnoent2.h, linux/x86_64/ioctlent2.h, linux/x86_64/signalent2.h and linux/x86_64/syscallent2.h. * linux/x32/errnoent.h: New. * linux/x32/ioctlent.h.in: Likewise. * linux/x32/signalent.h: Likewise. * linux/x32/syscallent.h: Likewise. * linux/x86_64/errnoent2.h: Likewise. * linux/x86_64/ioctlent2.h: Likewise. * linux/x86_64/signalent2.h: Likewise. * linux/x86_64/syscallent2.h: Likewise. Signed-off-by: H.J. Lu <hongjiu.lu@intel.com> Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
2012-04-16 15:00:01 +04:00
# if !defined(IA64) && !defined(X86_64) && !defined(X32)
# include <asm/sigcontext.h>
# endif
1999-02-19 03:21:36 +03:00
#else /* !HAVE_ASM_SIGCONTEXT_H */
# if defined I386 && !defined HAVE_STRUCT_SIGCONTEXT_STRUCT
1999-02-19 03:21:36 +03:00
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
1999-02-19 03:21:36 +03:00
{
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 */
1999-02-19 03:21:36 +03:00
#endif /* !HAVE_ASM_SIGCONTEXT_H */
1999-02-19 03:21:36 +03:00
#ifndef NSIG
# warning: NSIG is not defined, using 32
# define NSIG 32
1999-02-19 03:21:36 +03:00
#endif
#ifdef ARM
/* Ugh. Is this really correct? ARM has no RT signals?! */
# undef NSIG
# define NSIG 32
1999-02-19 03:21:36 +03:00
#endif
1999-02-19 03:21:36 +03:00
#ifdef HAVE_SIGACTION
Add x32 support to strace X32 support is added to Linux kernel 3.4. In a nutshell, x32 is x86-64 with 32bit pointers. At system call level, x32 is also identical to x86-64, as shown by many changes like "defined(X86_64) || defined(X32)". The main differerence bewteen x32 and x86-64 is off_t in x32 is long long instead of long. This patch adds x32 support to strace. Tested on Linux/x32. * configure.ac: Support X32. * defs.h: Set SUPPORTED_PERSONALITIES to 3 for X86_64, Set PERSONALITY2_WORDSIZE to 4 for X86_64. Add tcb::ext_arg for X32. * file.c (stat): New for X32. (sys_lseek): Use 64-bit version for X32. (printstat64): Check current_personality != 1 for X86_64. * ipc.c (indirect_ipccall): Check current_personality == 1 for X86_64. * mem.c (sys_mmap64): Also use tcp->u_arg for X32. Print NULL for zero address. Call printllval for offset for X32. * pathtrace.c (pathtrace_match): Don't check sys_old_mmap for X32. * process.c (ARG_FLAGS): Defined for X32. (ARG_STACK): Likewise. (ARG_PTID): Likewise. (change_syscall): Handle X32. (struct_user_offsets): Support X32. (sys_arch_prctl): Likewise. * signal.c: Include <asm/sigcontext.h> for X32. (SA_RESTORER): Also define for X32. * syscall.c (update_personality): Support X32 for X86_64. (is_restart_error): Likewise. (syscall_fixup_on_sysenter): Likewise. (get_syscall_args): Likewise. (get_syscall_result): Likewise. (get_error): Likewise. (__X32_SYSCALL_BIT): Define if not defined. (__X32_SYSCALL_MASK): Likewise. (get_scno): Check DS register value for X32. Use __X32_SYSCALL_MASK on X32 system calls. * util.c (printllval): Use ext_arg for X32. (printcall): Support X32. (change_syscall): Likewise. (arg0_offset): Likewise. (arg1_offset): Likewise. * Makefile.am (EXTRA_DIST): Add linux/x32/errnoent.h, linux/x32/ioctlent.h.in, linux/x32/signalent.h, linux/x32/syscallent.h, linux/x86_64/errnoent2.h, linux/x86_64/ioctlent2.h, linux/x86_64/signalent2.h and linux/x86_64/syscallent2.h. * linux/x32/errnoent.h: New. * linux/x32/ioctlent.h.in: Likewise. * linux/x32/signalent.h: Likewise. * linux/x32/syscallent.h: Likewise. * linux/x86_64/errnoent2.h: Likewise. * linux/x86_64/ioctlent2.h: Likewise. * linux/x86_64/signalent2.h: Likewise. * linux/x86_64/syscallent2.h: Likewise. Signed-off-by: H.J. Lu <hongjiu.lu@intel.com> Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
2012-04-16 15:00:01 +04:00
#if defined I386 || defined X86_64 || defined X32
/* 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
1999-02-19 03:21:36 +03:00
#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
1999-02-19 03:21:36 +03:00
{ SA_NOMASK, "SA_NOMASK" },
#endif
#ifdef SA_RESETHAND
{ SA_RESETHAND, "SA_RESETHAND" },
#endif
#if defined SA_ONESHOT && SA_ONESHOT != SA_RESETHAND
1999-02-19 03:21:36 +03:00
{ 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" },
1999-02-19 03:21:36 +03:00
#endif
{ 0, NULL },
};
static const struct xlat sigprocmaskcmds[] = {
1999-02-19 03:21:36 +03:00
{ 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
Set saner MAX_ARGS (6 or 8) for X86_64 and I386 I noticed that tcp->u_args[MAX_ARGS] array is way larger than I'd expect: for all arches except HPPA it has 32 (!) elements. I looked at the code and so far I spotted only one abuser of this fact: sys_sigreturn. On several arches, it saves sigset_t into tcp->u_args[1...N] on entry and prints it on exit, a-la memcpy(&tcp->u_arg[1], &sc.oldmask[0], sizeof(sigset_t)) The problem here is that in glibc sigset_t is insanely large: 128 bytes, and using sizeof(sigset_t) in memcpy will overrun &tcp->u_args[1] even with MAX_ARGS == 32: On 32 bits, sizeof(tcp->u_args) == 32*4 == 128 bytes! We may already have a bug there! This commit changes the code to save NSIG / 8 bytes only. NSIG can't ever be > 256, and in practice is <= 129, thus NSIG / 8 is <= 16 bytes == 4 32-bit words, and even MAX_ARGS == 5 should be enough for saving signal masks. * defs.h: Reduce MAX_ARGS for X86_64 and I386 from 32 to 8 for FreeBSD and to 6 for everyone else. Add comment about current state of needed MAX_ARGS. * signal.c: Add comment about size of sigset_t. (sprintsigmask): Reduce static string buffer from 8k to 2k. (sys_sigreturn): Fix sigset saving to save only NSIG / 8 bytes, not sizeof(sigset_t) bytes. * linux/mips/syscallent.h: Reduce nargs of printargs-type syscall to 7. * linux/arm/syscallent.h: Reduce nargs of printargs-type syscall to 6. * linux/i386/syscallent.h: Likewise. * linux/m68k/syscallent.h: Likewise. * linux/powerpc/syscallent.h: Likewise. * linux/s390/syscallent.h: Likewise. * linux/s390x/syscallent.h: Likewise. * linux/sh/syscallent.h: Likewise. * linux/sh64/syscallent.h: Likewise. * linux/sparc/syscallent.h: Likewise. Signed-off-by: Denys Vlasenko <dvlasenk@redhat.com>
2011-08-19 19:41:28 +04:00
/* 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 <something>.
* 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;
}
1999-02-19 03:21:36 +03:00
static void
long_to_sigset(long l, sigset_t *s)
{
sigemptyset(s);
*(long *)s = l;
}
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;
}
/* Original sigset is unsigned long */
#define copy_sigset(tcp, addr, s) copy_sigset_len(tcp, addr, s, sizeof(long))
static const char *
sprintsigmask(const char *str, sigset_t *mask, int rt)
/* set might include realtime sigs */
1999-02-19 03:21:36 +03:00
{
Set saner MAX_ARGS (6 or 8) for X86_64 and I386 I noticed that tcp->u_args[MAX_ARGS] array is way larger than I'd expect: for all arches except HPPA it has 32 (!) elements. I looked at the code and so far I spotted only one abuser of this fact: sys_sigreturn. On several arches, it saves sigset_t into tcp->u_args[1...N] on entry and prints it on exit, a-la memcpy(&tcp->u_arg[1], &sc.oldmask[0], sizeof(sigset_t)) The problem here is that in glibc sigset_t is insanely large: 128 bytes, and using sizeof(sigset_t) in memcpy will overrun &tcp->u_args[1] even with MAX_ARGS == 32: On 32 bits, sizeof(tcp->u_args) == 32*4 == 128 bytes! We may already have a bug there! This commit changes the code to save NSIG / 8 bytes only. NSIG can't ever be > 256, and in practice is <= 129, thus NSIG / 8 is <= 16 bytes == 4 32-bit words, and even MAX_ARGS == 5 should be enough for saving signal masks. * defs.h: Reduce MAX_ARGS for X86_64 and I386 from 32 to 8 for FreeBSD and to 6 for everyone else. Add comment about current state of needed MAX_ARGS. * signal.c: Add comment about size of sigset_t. (sprintsigmask): Reduce static string buffer from 8k to 2k. (sys_sigreturn): Fix sigset saving to save only NSIG / 8 bytes, not sizeof(sigset_t) bytes. * linux/mips/syscallent.h: Reduce nargs of printargs-type syscall to 7. * linux/arm/syscallent.h: Reduce nargs of printargs-type syscall to 6. * linux/i386/syscallent.h: Likewise. * linux/m68k/syscallent.h: Likewise. * linux/powerpc/syscallent.h: Likewise. * linux/s390/syscallent.h: Likewise. * linux/s390x/syscallent.h: Likewise. * linux/sh/syscallent.h: Likewise. * linux/sh64/syscallent.h: Likewise. * linux/sparc/syscallent.h: Likewise. Signed-off-by: Denys Vlasenko <dvlasenk@redhat.com>
2011-08-19 19:41:28 +04:00
/* 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 * 2 / 3)];
Set saner MAX_ARGS (6 or 8) for X86_64 and I386 I noticed that tcp->u_args[MAX_ARGS] array is way larger than I'd expect: for all arches except HPPA it has 32 (!) elements. I looked at the code and so far I spotted only one abuser of this fact: sys_sigreturn. On several arches, it saves sigset_t into tcp->u_args[1...N] on entry and prints it on exit, a-la memcpy(&tcp->u_arg[1], &sc.oldmask[0], sizeof(sigset_t)) The problem here is that in glibc sigset_t is insanely large: 128 bytes, and using sizeof(sigset_t) in memcpy will overrun &tcp->u_args[1] even with MAX_ARGS == 32: On 32 bits, sizeof(tcp->u_args) == 32*4 == 128 bytes! We may already have a bug there! This commit changes the code to save NSIG / 8 bytes only. NSIG can't ever be > 256, and in practice is <= 129, thus NSIG / 8 is <= 16 bytes == 4 32-bit words, and even MAX_ARGS == 5 should be enough for saving signal masks. * defs.h: Reduce MAX_ARGS for X86_64 and I386 from 32 to 8 for FreeBSD and to 6 for everyone else. Add comment about current state of needed MAX_ARGS. * signal.c: Add comment about size of sigset_t. (sprintsigmask): Reduce static string buffer from 8k to 2k. (sys_sigreturn): Fix sigset saving to save only NSIG / 8 bytes, not sizeof(sigset_t) bytes. * linux/mips/syscallent.h: Reduce nargs of printargs-type syscall to 7. * linux/arm/syscallent.h: Reduce nargs of printargs-type syscall to 6. * linux/i386/syscallent.h: Likewise. * linux/m68k/syscallent.h: Likewise. * linux/powerpc/syscallent.h: Likewise. * linux/s390/syscallent.h: Likewise. * linux/s390x/syscallent.h: Likewise. * linux/sh/syscallent.h: Likewise. * linux/sh64/syscallent.h: Likewise. * linux/sparc/syscallent.h: Likewise. Signed-off-by: Denys Vlasenko <dvlasenk@redhat.com>
2011-08-19 19:41:28 +04:00
1999-02-19 03:21:36 +03:00
int i, nsigs;
int maxsigs;
int show_members;
char sep;
char *s;
1999-02-19 03:21:36 +03:00
maxsigs = nsignals;
#ifdef __SIGRTMAX
if (rt)
maxsigs = __SIGRTMAX; /* instead */
#endif
s = stpcpy(outstr, str);
nsigs = 0;
for (i = 1; i < maxsigs; i++) {
1999-02-19 03:21:36 +03:00
if (sigismember(mask, i) == 1)
nsigs++;
}
/* 1: show mask members, 0: show those which are NOT in mask */
show_members = (nsigs < nsignals * 2 / 3);
if (!show_members)
1999-02-19 03:21:36 +03:00
*s++ = '~';
sep = '[';
for (i = 1; i < maxsigs; i++) {
if (sigismember(mask, i) == show_members) {
2001-03-06 18:08:09 +03:00
/* real-time signals on solaris don't have
* signalent entries
*/
char tsig[40];
*s++ = sep;
2001-03-06 18:08:09 +03:00
if (i < nsignals) {
s = stpcpy(s, signalent[i] + 3);
2001-03-06 18:08:09 +03:00
}
#ifdef SIGRTMIN
else if (i >= __SIGRTMIN && i <= __SIGRTMAX) {
sprintf(tsig, "RT_%u", i - __SIGRTMIN);
s = stpcpy(s, tsig);
}
#endif /* SIGRTMIN */
2001-03-06 18:08:09 +03:00
else {
sprintf(tsig, "%u", i);
s = stpcpy(s, tsig);
2001-03-06 18:08:09 +03:00
}
sep = ' ';
1999-02-19 03:21:36 +03:00
}
}
if (sep == '[')
*s++ = sep;
1999-02-19 03:21:36 +03:00
*s++ = ']';
*s = '\0';
return outstr;
}
static void
printsigmask(sigset_t *mask, int rt)
1999-02-19 03:21:36 +03:00
{
tprints(sprintsigmask("", mask, rt));
1999-02-19 03:21:36 +03:00
}
void
printsignal(int nr)
1999-02-19 03:21:36 +03:00
{
tprints(signame(nr));
1999-02-19 03:21:36 +03:00
}
2006-10-13 Ulrich Drepper <drepper@redhat.com> Bernhard Kaindl <bk@suse.de> Dmitry V. Levin <ldv@altlinux.org> Michael Holzheu <holzheu@de.ibm.com> Add hooks for new syscalls. Add decoders for *at, inotify*, pselect6, ppoll and unshare syscalls. * defs.h: Declare print_sigset. * desc.c (sys_pselect6): New function. * file.c (decode_open, decode_access, decode_mkdir, decode_readlink, decode_chmod, decode_utimes, decode_mknod): New functions. (sys_open, sys_access, sys_mkdir, sys_readlink, sys_chmod, sys_utimes, sys_mknod): Use them. [LINUX] (fstatatflags, unlinkatflags, inotify_modes): New variables. [LINUX] (print_dirfd, sys_openat, sys_faccessat, sys_newfstatat, sys_mkdirat, sys_linkat, sys_unlinkat, sys_symlinkat, sys_readlinkat, sys_renameat, sys_fchownat, sys_fchmodat, sys_futimesat, sys_mknodat, sys_inotify_add_watch, sys_inotify_rm_watch): New functions. * process.c [LINUX] (sys_unshare): New function. * signal.c (print_sigset): New function. (sys_sigprocmask): Use it. * stream.c (decode_poll): New function. (sys_poll): Use it. [LINUX] (sys_ppoll): New function. * linux/syscall.h: Delcare new syscall handlers. * linux/syscallent.h: Hook up new syscalls. * linux/alpha/syscallent.h: Likewise. * linux/hppa/syscallent.h: Likewise. * linux/ia64/syscallent.h: Likewise. * linux/mips/syscallent.h: Likewise. * linux/powerpc/syscallent.h: Likewise. * linux/s390/syscallent.h: Likewise. * linux/s390x/syscallent.h: Likewise. * linux/sparc/syscallent.h: Likewise. * linux/sparc64/syscallent.h: Likewise. * linux/x86_64/syscallent.h: Likewise. Fixes RH#178633.
2006-10-14 00:25:12 +04:00
void
print_sigset(struct tcb *tcp, long addr, int rt)
{
sigset_t ss;
if (!addr)
tprints("NULL");
2006-10-13 Ulrich Drepper <drepper@redhat.com> Bernhard Kaindl <bk@suse.de> Dmitry V. Levin <ldv@altlinux.org> Michael Holzheu <holzheu@de.ibm.com> Add hooks for new syscalls. Add decoders for *at, inotify*, pselect6, ppoll and unshare syscalls. * defs.h: Declare print_sigset. * desc.c (sys_pselect6): New function. * file.c (decode_open, decode_access, decode_mkdir, decode_readlink, decode_chmod, decode_utimes, decode_mknod): New functions. (sys_open, sys_access, sys_mkdir, sys_readlink, sys_chmod, sys_utimes, sys_mknod): Use them. [LINUX] (fstatatflags, unlinkatflags, inotify_modes): New variables. [LINUX] (print_dirfd, sys_openat, sys_faccessat, sys_newfstatat, sys_mkdirat, sys_linkat, sys_unlinkat, sys_symlinkat, sys_readlinkat, sys_renameat, sys_fchownat, sys_fchmodat, sys_futimesat, sys_mknodat, sys_inotify_add_watch, sys_inotify_rm_watch): New functions. * process.c [LINUX] (sys_unshare): New function. * signal.c (print_sigset): New function. (sys_sigprocmask): Use it. * stream.c (decode_poll): New function. (sys_poll): Use it. [LINUX] (sys_ppoll): New function. * linux/syscall.h: Delcare new syscall handlers. * linux/syscallent.h: Hook up new syscalls. * linux/alpha/syscallent.h: Likewise. * linux/hppa/syscallent.h: Likewise. * linux/ia64/syscallent.h: Likewise. * linux/mips/syscallent.h: Likewise. * linux/powerpc/syscallent.h: Likewise. * linux/s390/syscallent.h: Likewise. * linux/s390x/syscallent.h: Likewise. * linux/sparc/syscallent.h: Likewise. * linux/sparc64/syscallent.h: Likewise. * linux/x86_64/syscallent.h: Likewise. Fixes RH#178633.
2006-10-14 00:25:12 +04:00
else if (copy_sigset(tcp, addr, &ss) < 0)
tprintf("%#lx", addr);
else
printsigmask(&ss, rt);
}
2001-10-18 19:13:53 +04:00
#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 */
2001-10-18 19:13:53 +04:00
#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 */
#endif
#ifndef SI_FROMUSER
# define SI_FROMUSER(sip) ((sip)->si_code <= 0)
#endif
2001-10-18 19:13:53 +04:00
static const struct xlat siginfo_codes[] = {
#ifdef SI_KERNEL
{ SI_KERNEL, "SI_KERNEL" },
2001-10-18 19:13:53 +04:00
#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" },
2001-10-18 19:13:53 +04:00
#endif
{ 0, NULL },
};
static const struct xlat sigill_codes[] = {
2001-10-18 19:13:53 +04:00
{ 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[] = {
2001-10-18 19:13:53 +04:00
{ 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[] = {
2001-10-18 19:13:53 +04:00
{ TRAP_BRKPT, "TRAP_BRKPT" },
{ TRAP_TRACE, "TRAP_TRACE" },
{ 0, NULL },
};
static const struct xlat sigchld_codes[] = {
2001-10-18 19:13:53 +04:00
{ 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[] = {
2001-10-18 19:13:53 +04:00
{ 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[] = {
2001-10-18 19:13:53 +04:00
#ifdef PROF_SIG
{ PROF_SIG, "PROF_SIG" },
#endif
{ 0, NULL },
};
#ifdef SIGEMT
static const struct xlat sigemt_codes[] = {
2001-10-18 19:13:53 +04:00
#ifdef EMT_TAGOVF
{ EMT_TAGOVF, "EMT_TAGOVF" },
#endif
{ 0, NULL },
};
#endif
static const struct xlat sigsegv_codes[] = {
2001-10-18 19:13:53 +04:00
{ SEGV_MAPERR, "SEGV_MAPERR" },
{ SEGV_ACCERR, "SEGV_ACCERR" },
{ 0, NULL },
};
static const struct xlat sigbus_codes[] = {
2001-10-18 19:13:53 +04:00
{ BUS_ADRALN, "BUS_ADRALN" },
{ BUS_ADRERR, "BUS_ADRERR" },
{ BUS_OBJERR, "BUS_OBJERR" },
{ 0, NULL },
};
void
printsiginfo(siginfo_t *sip, int verbose)
2001-10-18 19:13:53 +04:00
{
const char *code;
2001-10-18 19:13:53 +04:00
if (sip->si_signo == 0) {
tprints("{}");
2001-10-18 19:13:53 +04:00
return;
}
tprints("{si_signo=");
2001-10-18 19:13:53 +04:00
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);
2001-10-18 19:13:53 +04:00
switch (sip->si_code) {
#ifdef SI_USER
case SI_USER:
break;
#endif
#ifdef SI_TKILL
case SI_TKILL:
break;
#endif
2001-10-18 19:13:53 +04:00
#ifdef SI_TIMER
case SI_TIMER:
tprintf(", si_value=%d", sip->si_int);
2001-10-18 19:13:53 +04:00
break;
#endif
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;
2001-10-18 19:13:53 +04:00
}
}
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 (!verbose)
tprints(", ...");
2001-10-18 19:13:53 +04:00
else
tprintf(", si_utime=%llu, si_stime=%llu",
(unsigned long long) sip->si_utime,
(unsigned long long) sip->si_stime);
2001-10-18 19:13:53 +04:00
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;
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;
2001-10-18 19:13:53 +04:00
if (!verbose)
tprints(", ...");
2001-10-18 19:13:53 +04:00
else {
tprintf(", si_value={int=%u, ptr=%#lx}",
2001-10-18 19:13:53 +04:00
sip->si_int,
(unsigned long) sip->si_ptr);
}
2001-10-18 19:13:53 +04:00
}
}
}
tprints("}");
2001-10-18 19:13:53 +04:00
}
1999-02-19 03:21:36 +03:00
int
sys_sigsetmask(struct tcb *tcp)
1999-02-19 03:21:36 +03:00
{
if (entering(tcp)) {
sigset_t sigm;
long_to_sigset(tcp->u_arg[0], &sigm);
printsigmask(&sigm, 0);
1999-02-19 03:21:36 +03:00
}
else if (!syserror(tcp)) {
sigset_t sigm;
long_to_sigset(tcp->u_rval, &sigm);
tcp->auxstr = sprintsigmask("old mask ", &sigm, 0);
1999-02-19 03:21:36 +03:00
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: */
void (*__sa_handler)(int);
1999-02-19 03:21:36 +03:00
unsigned long sa_mask;
unsigned long sa_flags;
void (*sa_restorer)(void);
};
int
sys_sigaction(struct tcb *tcp)
1999-02-19 03:21:36 +03:00
{
long addr;
2001-03-06 12:25:46 +03:00
sigset_t sigset;
1999-02-19 03:21:36 +03:00
struct old_sigaction sa;
if (entering(tcp)) {
printsignal(tcp->u_arg[0]);
tprints(", ");
1999-02-19 03:21:36 +03:00
addr = tcp->u_arg[1];
} else
addr = tcp->u_arg[2];
if (addr == 0)
tprints("NULL");
1999-02-19 03:21:36 +03:00
else if (!verbose(tcp))
tprintf("%#lx", addr);
else if (umove(tcp, addr, &sa) < 0)
tprints("{...}");
1999-02-19 03:21:36 +03:00
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)
tprints("{SIG_IGN, ");
else
tprintf("{%#lx, ", (long) sa.__sa_handler);
long_to_sigset(sa.sa_mask, &sigset);
printsigmask(&sigset, 0);
tprints(", ");
printflags(sigact_flags, sa.sa_flags, "SA_???");
#ifdef SA_RESTORER
if (sa.sa_flags & SA_RESTORER)
tprintf(", %p", sa.sa_restorer);
#endif
tprints("}");
1999-02-19 03:21:36 +03:00
}
if (entering(tcp))
tprints(", ");
1999-02-19 03:21:36 +03:00
else
tprintf(", %#lx", (unsigned long) sa.sa_restorer);
return 0;
}
int
sys_signal(struct tcb *tcp)
1999-02-19 03:21:36 +03:00
{
if (entering(tcp)) {
printsignal(tcp->u_arg[0]);
tprints(", ");
1999-02-19 03:21:36 +03:00
switch (tcp->u_arg[1]) {
case (long) SIG_ERR:
tprints("SIG_ERR");
1999-02-19 03:21:36 +03:00
break;
case (long) SIG_DFL:
tprints("SIG_DFL");
1999-02-19 03:21:36 +03:00
break;
case (long) SIG_IGN:
tprints("SIG_IGN");
1999-02-19 03:21:36 +03:00
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;
}
1999-02-19 03:21:36 +03:00
#endif /* HAVE_SIGACTION */
int
sys_sigreturn(struct tcb *tcp)
1999-02-19 03:21:36 +03:00
{
#if defined(ARM)
if (entering(tcp)) {
struct sigcontext_struct sc;
2012-01-10 19:40:35 +04:00
sigset_t sigm;
if (umove(tcp, arm_regs.ARM_sp, &sc) < 0)
return 0;
2012-01-10 19:40:35 +04:00
long_to_sigset(sc.oldmask, &sigm);
tprints(sprintsigmask(") (mask ", &sigm, 0));
}
#elif defined(S390) || defined(S390X)
if (entering(tcp)) {
long usp;
struct sigcontext_struct sc;
2011-06-07 14:13:24 +04:00
if (upeek(tcp, PT_GPR15, &usp) < 0)
return 0;
2012-01-10 19:40:35 +04:00
if (umove(tcp, usp + __SIGNAL_FRAMESIZE, &sc) < 0)
return 0;
tprints(sprintsigmask(") (mask ", (sigset_t *)&sc.oldmask[0], 0));
}
#elif defined(I386)
1999-02-19 03:21:36 +03:00
if (entering(tcp)) {
struct sigcontext_struct sc;
2012-01-10 19:40:35 +04:00
/* Note: 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. We can fetch it there
* if/when we'd want to display the full mask...
*/
1999-02-19 03:21:36 +03:00
sigset_t sigm;
2012-01-10 19:40:35 +04:00
if (umove(tcp, i386_regs.esp, &sc) < 0)
1999-02-19 03:21:36 +03:00
return 0;
2012-01-10 19:40:35 +04:00
long_to_sigset(sc.oldmask, &sigm);
tprints(sprintsigmask(") (mask ", &sigm, 0));
1999-02-19 03:21:36 +03:00
}
#elif defined(IA64)
2000-02-04 00:58:30 +03:00
if (entering(tcp)) {
struct sigcontext sc;
long sp;
2012-01-10 19:40:35 +04:00
sigset_t sigm;
/* offset of sigcontext in the kernel's sigframe structure: */
# define SIGFRAME_SC_OFFSET 0x90
if (upeek(tcp, PT_R12, &sp) < 0)
2000-02-04 00:58:30 +03:00
return 0;
if (umove(tcp, sp + 16 + SIGFRAME_SC_OFFSET, &sc) < 0)
2000-02-04 00:58:30 +03:00
return 0;
Set saner MAX_ARGS (6 or 8) for X86_64 and I386 I noticed that tcp->u_args[MAX_ARGS] array is way larger than I'd expect: for all arches except HPPA it has 32 (!) elements. I looked at the code and so far I spotted only one abuser of this fact: sys_sigreturn. On several arches, it saves sigset_t into tcp->u_args[1...N] on entry and prints it on exit, a-la memcpy(&tcp->u_arg[1], &sc.oldmask[0], sizeof(sigset_t)) The problem here is that in glibc sigset_t is insanely large: 128 bytes, and using sizeof(sigset_t) in memcpy will overrun &tcp->u_args[1] even with MAX_ARGS == 32: On 32 bits, sizeof(tcp->u_args) == 32*4 == 128 bytes! We may already have a bug there! This commit changes the code to save NSIG / 8 bytes only. NSIG can't ever be > 256, and in practice is <= 129, thus NSIG / 8 is <= 16 bytes == 4 32-bit words, and even MAX_ARGS == 5 should be enough for saving signal masks. * defs.h: Reduce MAX_ARGS for X86_64 and I386 from 32 to 8 for FreeBSD and to 6 for everyone else. Add comment about current state of needed MAX_ARGS. * signal.c: Add comment about size of sigset_t. (sprintsigmask): Reduce static string buffer from 8k to 2k. (sys_sigreturn): Fix sigset saving to save only NSIG / 8 bytes, not sizeof(sigset_t) bytes. * linux/mips/syscallent.h: Reduce nargs of printargs-type syscall to 7. * linux/arm/syscallent.h: Reduce nargs of printargs-type syscall to 6. * linux/i386/syscallent.h: Likewise. * linux/m68k/syscallent.h: Likewise. * linux/powerpc/syscallent.h: Likewise. * linux/s390/syscallent.h: Likewise. * linux/s390x/syscallent.h: Likewise. * linux/sh/syscallent.h: Likewise. * linux/sh64/syscallent.h: Likewise. * linux/sparc/syscallent.h: Likewise. Signed-off-by: Denys Vlasenko <dvlasenk@redhat.com>
2011-08-19 19:41:28 +04:00
sigemptyset(&sigm);
2012-01-10 19:40:35 +04:00
memcpy(&sigm, &sc.sc_mask, NSIG / 8);
tprints(sprintsigmask(") (mask ", &sigm, 0));
2000-02-04 00:58:30 +03:00
}
#elif defined(POWERPC)
if (entering(tcp)) {
long esp;
struct sigcontext_struct sc;
2012-01-10 19:40:35 +04:00
sigset_t sigm;
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;
2012-01-10 19:40:35 +04:00
long_to_sigset(sc.oldmask, &sigm);
tprints(sprintsigmask(") (mask ", &sigm, 0));
}
#elif defined(M68K)
1999-02-19 03:21:36 +03:00
if (entering(tcp)) {
long usp;
struct sigcontext sc;
2012-01-10 19:40:35 +04:00
sigset_t sigm;
if (upeek(tcp, 4*PT_USP, &usp) < 0)
1999-02-19 03:21:36 +03:00
return 0;
if (umove(tcp, usp, &sc) < 0)
1999-02-19 03:21:36 +03:00
return 0;
2012-01-10 19:40:35 +04:00
long_to_sigset(sc.sc_mask, &sigm);
tprints(sprintsigmask(") (mask ", &sigm, 0));
1999-02-19 03:21:36 +03:00
}
#elif defined(ALPHA)
1999-02-19 03:21:36 +03:00
if (entering(tcp)) {
long fp;
struct sigcontext_struct sc;
2012-01-10 19:40:35 +04:00
sigset_t sigm;
if (upeek(tcp, REG_FP, &fp) < 0)
1999-02-19 03:21:36 +03:00
return 0;
if (umove(tcp, fp, &sc) < 0)
1999-02-19 03:21:36 +03:00
return 0;
2012-01-10 19:40:35 +04:00
long_to_sigset(sc.sc_mask, &sigm);
tprints(sprintsigmask(") (mask ", &sigm, 0));
1999-02-19 03:21:36 +03:00
}
#elif defined(SPARC) || defined(SPARC64)
2011-06-07 14:13:24 +04:00
if (entering(tcp)) {
long i1;
m_siginfo_t si;
2012-01-10 19:40:35 +04:00
sigset_t sigm;
i1 = regs.u_regs[U_REG_O1];
2011-06-07 14:13:24 +04:00
if (umove(tcp, i1, &si) < 0) {
perror_msg("%s", "sigreturn: umove");
1999-02-19 03:21:36 +03:00
return 0;
}
2012-01-10 19:40:35 +04:00
long_to_sigset(si.si_mask, &sigm);
tprints(sprintsigmask(") (mask ", &sigm, 0));
1999-02-19 03:21:36 +03:00
}
#elif defined(LINUX_MIPSN32) || defined(LINUX_MIPSN64)
/* This decodes rt_sigreturn. The 64-bit ABIs do not have
sigreturn. */
2011-06-07 14:13:24 +04:00
if (entering(tcp)) {
long sp;
struct ucontext uc;
2012-01-10 19:40:35 +04:00
sigset_t sigm;
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;
2012-01-10 19:40:35 +04:00
long_to_sigset(*(long *) &uc.uc_sigmask, &sigm);
tprints(sprintsigmask(") (mask ", &sigm, 0));
}
#elif defined(MIPS)
2011-06-07 14:13:24 +04:00
if (entering(tcp)) {
long sp;
struct pt_regs regs;
m_siginfo_t si;
2012-01-10 19:40:35 +04:00
sigset_t sigm;
if (ptrace(PTRACE_GETREGS, tcp->pid, (char *)&regs, 0) < 0) {
perror_msg("%s", "sigreturn: PTRACE_GETREGS");
return 0;
}
sp = regs.regs[29];
if (umove(tcp, sp, &si) < 0)
return 0;
2012-01-10 19:40:35 +04:00
long_to_sigset(si.si_mask, &sigm);
tprints(sprintsigmask(") (mask ", &sigm, 0));
1999-11-01 00:15:38 +03:00
}
#elif defined(CRISV10) || defined(CRISV32)
if (entering(tcp)) {
struct sigcontext sc;
long regs[PT_MAX+1];
2012-01-10 19:40:35 +04:00
sigset_t sigm;
if (ptrace(PTRACE_GETREGS, tcp->pid, NULL, (long)regs) < 0) {
perror_msg("%s", "sigreturn: PTRACE_GETREGS");
return 0;
}
if (umove(tcp, regs[PT_USP], &sc) < 0)
return 0;
2012-01-10 19:40:35 +04:00
long_to_sigset(sc.oldmask, &sigm);
tprints(sprintsigmask(") (mask ", &sigm, 0));
}
#elif defined(TILE)
if (entering(tcp)) {
struct ucontext uc;
2012-01-10 19:40:35 +04:00
sigset_t sigm;
/* offset of ucontext in the kernel's sigframe structure */
# define SIGFRAME_UC_OFFSET C_ABI_SAVE_AREA_SIZE + sizeof(struct siginfo)
Add tilegx support to strace tilegx support has been in the kernel since 3.0. In addition, fix some issues with the tilepro support already present in strace, primarily the decision to use the <asm/unistd.h> numbering space for system calls. * defs.h [TILE]: Include <asm/ptrace.h> and provide an extern struct pt_regs tile_regs for efficiency. Provide compat 32-bit personality via SUPPORTED_PERSONALITIES, PERSONALITY0_WORDSIZE, PERSONALITY1_WORDSIZE, and DEFAULT_PERSONALITY. * linux/tile/errnoent1.h: New file, includes linux/errnoent.h. * linux/tile/ioctlent1.h: New file, includes linux/ioctlent.h. * linux/tile/signalent1.h: New file, includes linux/signalent.h. * linux/tile/syscallent.h: Update with new asm-generic syscalls. The version previously committed was the from the first tile patch to LKML, which subsequently was changed to use <asm-generic/unistd.h>. * linux/tile/syscallent1.h: Copy from linux/tile/syscallent.h. * mem.c (addtileflags) [TILE]: use %ld properly for a "long" variable. * process.c [TILE]: Choose clone arguments correctly and properly suppress all "struct user" related offsets in user_struct_offsets. * signal.c [TILE]: Use tile_regs not upeek. * syscall.c (update_personality) [TILE]: Print mode. (PT_FLAGS_COMPAT) [TILE]: Provide if not in system headers. (tile_regs) [TILE]: Define 'struct pt_regs' variable to hold state. (get_regs) [TILE]: use PTRACE_GETREGS to set tile_regs rather than using upeek. (get_scno) [TILE]: Set personality. (get_syscall_args) [TILE]: Use tile_regs. (get_syscall_result) [TILE]: Update tile_regs. (get_error) [TILE]: Use tile_regs. (printcall) [TILE]: Print pc. (arg0_offset, arg1_offset, restore_arg0, restore_arg1) [TILE]: Properly handle tile call semantics and support tilegx. Signed-off-by: Chris Metcalf <cmetcalf@tilera.com> Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
2013-02-05 20:48:33 +04:00
if (umove(tcp, tile_regs.sp + SIGFRAME_UC_OFFSET, &uc) < 0)
return 0;
Set saner MAX_ARGS (6 or 8) for X86_64 and I386 I noticed that tcp->u_args[MAX_ARGS] array is way larger than I'd expect: for all arches except HPPA it has 32 (!) elements. I looked at the code and so far I spotted only one abuser of this fact: sys_sigreturn. On several arches, it saves sigset_t into tcp->u_args[1...N] on entry and prints it on exit, a-la memcpy(&tcp->u_arg[1], &sc.oldmask[0], sizeof(sigset_t)) The problem here is that in glibc sigset_t is insanely large: 128 bytes, and using sizeof(sigset_t) in memcpy will overrun &tcp->u_args[1] even with MAX_ARGS == 32: On 32 bits, sizeof(tcp->u_args) == 32*4 == 128 bytes! We may already have a bug there! This commit changes the code to save NSIG / 8 bytes only. NSIG can't ever be > 256, and in practice is <= 129, thus NSIG / 8 is <= 16 bytes == 4 32-bit words, and even MAX_ARGS == 5 should be enough for saving signal masks. * defs.h: Reduce MAX_ARGS for X86_64 and I386 from 32 to 8 for FreeBSD and to 6 for everyone else. Add comment about current state of needed MAX_ARGS. * signal.c: Add comment about size of sigset_t. (sprintsigmask): Reduce static string buffer from 8k to 2k. (sys_sigreturn): Fix sigset saving to save only NSIG / 8 bytes, not sizeof(sigset_t) bytes. * linux/mips/syscallent.h: Reduce nargs of printargs-type syscall to 7. * linux/arm/syscallent.h: Reduce nargs of printargs-type syscall to 6. * linux/i386/syscallent.h: Likewise. * linux/m68k/syscallent.h: Likewise. * linux/powerpc/syscallent.h: Likewise. * linux/s390/syscallent.h: Likewise. * linux/s390x/syscallent.h: Likewise. * linux/sh/syscallent.h: Likewise. * linux/sh64/syscallent.h: Likewise. * linux/sparc/syscallent.h: Likewise. Signed-off-by: Denys Vlasenko <dvlasenk@redhat.com>
2011-08-19 19:41:28 +04:00
sigemptyset(&sigm);
2012-01-10 19:40:35 +04:00
memcpy(&sigm, &uc.uc_sigmask, NSIG / 8);
tprints(sprintsigmask(") (mask ", &sigm, 0));
}
#elif defined(MICROBLAZE)
/* TODO: Verify that this is correct... */
if (entering(tcp)) {
struct sigcontext sc;
long sp;
2012-01-10 19:40:35 +04:00
sigset_t sigm;
/* Read r1, the stack pointer. */
if (upeek(tcp, 1 * 4, &sp) < 0)
return 0;
if (umove(tcp, sp, &sc) < 0)
return 0;
2012-01-10 19:40:35 +04:00
long_to_sigset(sc.oldmask, &sigm);
tprints(sprintsigmask(") (mask ", &sigm, 0));
}
#elif defined(X86_64)
/* no need to remind */
#else
# warning No sys_sigreturn() for this architecture
# warning (no problem, just a reminder :-)
#endif
return 0;
1999-02-19 03:21:36 +03:00
}
int
sys_siggetmask(struct tcb *tcp)
1999-02-19 03:21:36 +03:00
{
if (exiting(tcp)) {
sigset_t sigm;
long_to_sigset(tcp->u_rval, &sigm);
tcp->auxstr = sprintsigmask("mask ", &sigm, 0);
1999-02-19 03:21:36 +03:00
}
return RVAL_HEX | RVAL_STR;
}
int
sys_sigsuspend(struct tcb *tcp)
1999-02-19 03:21:36 +03:00
{
if (entering(tcp)) {
sigset_t sigm;
long_to_sigset(tcp->u_arg[2], &sigm);
printsigmask(&sigm, 0);
1999-02-19 03:21:36 +03:00
}
return 0;
}
#if !defined SS_ONSTACK
1999-02-19 03:21:36 +03:00
#define SS_ONSTACK 1
#define SS_DISABLE 2
#endif
static const struct xlat sigaltstack_flags[] = {
1999-02-19 03:21:36 +03:00
{ SS_ONSTACK, "SS_ONSTACK" },
{ SS_DISABLE, "SS_DISABLE" },
{ 0, NULL },
};
static int
print_stack_t(struct tcb *tcp, unsigned long addr)
1999-02-19 03:21:36 +03:00
{
stack_t ss;
if (umove(tcp, addr, &ss) < 0)
return -1;
tprintf("{ss_sp=%#lx, ss_flags=", (unsigned long) ss.ss_sp);
2005-05-31 Dmitry V. Levin <ldv@altlinux.org> * util.c (printxval): Change third argument from "char *" to "const char *". (printflags): Add third argument, "const char *", with similar meaning to the third argument of printxval(). * defs.h (printxval): Change third argument from "char *" to "const char *". (printflags): Add third argument. * bjm.c (sys_query_module) [LINUX]: Pass third argument to printflags(). * desc.c (sys_fcntl): Likewise. (sys_flock) [LOCK_SH]: Likewise. (print_epoll_event) [HAVE_SYS_EPOLL_H]: Likewise. * file.c (sys_open): Likewise. (solaris_open) [LINUXSPARC]: Likewise. (sys_access): Likewise. (sys_chflags, sys_fchflags) [FREEBSD]: Likewise. (realprintstat) [HAVE_LONG_LONG_OFF_T && HAVE_STRUCT_STAT_ST_FLAGS]: Likewise. (printstat64) [HAVE_STAT64 && HAVE_STRUCT_STAT_ST_FLAGS]: Likewise. (sys_setxattr, sys_fsetxattr): Likewise. * ipc.c (sys_msgget, sys_msgsnd, sys_msgrcv, sys_semget, sys_shmget, sys_shmat) [LINUX || SUNOS4 || FREEBSD]: Likewise. (sys_mq_open) [LINUX]: Likewise. (printmqattr) [HAVE_MQUEUE_H]: Likewise. * mem.c (print_mmap) [!HAVE_LONG_LONG_OFF_T]: Likewise. (sys_mmap64) [_LFS64_LARGEFILE || HAVE_LONG_LONG_OFF_T]: Likewise. (sys_mprotect): Likewise. (sys_mremap, sys_madvise, sys_mlockall) [LINUX]: Likewise. (sys_msync) [MS_ASYNC]: Likewise. (sys_mctl) [MC_SYNC]: Likewise. (sys_remap_file_pages, sys_mbind, sys_get_mempolicy) [LINUX]: Likewise. * net.c (printmsghdr) [HAVE_STRUCT_MSGHDR_MSG_CONTROL]: Likewise. (sys_send, sys_sendto): Likewise. (sys_sendmsg) [HAVE_SENDMSG]: Likewise. (sys_recv, sys_recvfrom): Likewise. (sys_recvmsg) [HAVE_SENDMSG]: Likewise. (printicmpfilter) [ICMP_FILTER]: Likewise. * proc.c (proc_ioctl) [SVR4 && !HAVE_MP_PROCFS || FREEBSD]: Likewise. * process.c (sys_clone) [LINUX]: Likewise. (printwaitn): Likewise. (sys_waitid) [SVR4 || LINUX]: Likewise. * signal.c (sys_sigvec) [SUNOS4 || FREEBSD]: Likewise. (sys_sigaction): Likewise. (printcontext) [SVR4]: Likewise. (print_stack_t) [LINUX) || FREEBSD]: Likewise. (sys_rt_sigaction) [LINUX]: Likewise. * sock.c (sock_ioctl) [LINUX]: Likewise. * stream.c (sys_putmsg, sys_getmsg): Likewise. (sys_putpmsg) [SYS_putpmsg]: Likewise. (sys_getpmsg) [SYS_getpmsg]: Likewise. (sys_poll): Likewise. (print_transport_message) [TI_BIND]: Likewise. (stream_ioctl): Likewise. * system.c (sys_mount, sys_reboot): Likewise. (sys_cacheflush) [LINUX && M68K]: Likewise. (sys_capget, sys_capset) [SYS_capget]: Likewise. * term.c (term_ioctl) [TIOCMGET]: Likewise. * time.c (sys_clock_nanosleep, sys_timer_settime) [LINUX]: Likewise. Fixes RH#159310.
2005-06-01 23:02:36 +04:00
printflags(sigaltstack_flags, ss.ss_flags, "SS_???");
1999-02-19 03:21:36 +03:00
tprintf(", ss_size=%lu}", (unsigned long) ss.ss_size);
return 0;
}
int
sys_sigaltstack(struct tcb *tcp)
1999-02-19 03:21:36 +03:00
{
if (entering(tcp)) {
if (tcp->u_arg[0] == 0)
tprints("NULL");
1999-02-19 03:21:36 +03:00
else if (print_stack_t(tcp, tcp->u_arg[0]) < 0)
return -1;
}
else {
tprints(", ");
1999-02-19 03:21:36 +03:00
if (tcp->u_arg[1] == 0)
tprints("NULL");
1999-02-19 03:21:36 +03:00
else if (print_stack_t(tcp, tcp->u_arg[1]) < 0)
return -1;
}
return 0;
}
#ifdef HAVE_SIGACTION
int
sys_sigprocmask(struct tcb *tcp)
1999-02-19 03:21:36 +03:00
{
#ifdef ALPHA
sigset_t ss;
1999-02-19 03:21:36 +03:00
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, ...);
*/
memcpy(&ss, &tcp->u_arg[1], sizeof(long));
1999-02-19 03:21:36 +03:00
printxval(sigprocmaskcmds, tcp->u_arg[0], "SIG_???");
tprints(", ");
printsigmask(&ss, 0);
1999-02-19 03:21:36 +03:00
}
else if (!syserror(tcp)) {
memcpy(&ss, &tcp->u_rval, sizeof(long));
tcp->auxstr = sprintsigmask("old mask ", &ss, 0);
1999-02-19 03:21:36 +03:00
return RVAL_HEX | RVAL_STR;
}
#else /* !ALPHA */
if (entering(tcp)) {
printxval(sigprocmaskcmds, tcp->u_arg[0], "SIG_???");
tprints(", ");
2006-10-13 Ulrich Drepper <drepper@redhat.com> Bernhard Kaindl <bk@suse.de> Dmitry V. Levin <ldv@altlinux.org> Michael Holzheu <holzheu@de.ibm.com> Add hooks for new syscalls. Add decoders for *at, inotify*, pselect6, ppoll and unshare syscalls. * defs.h: Declare print_sigset. * desc.c (sys_pselect6): New function. * file.c (decode_open, decode_access, decode_mkdir, decode_readlink, decode_chmod, decode_utimes, decode_mknod): New functions. (sys_open, sys_access, sys_mkdir, sys_readlink, sys_chmod, sys_utimes, sys_mknod): Use them. [LINUX] (fstatatflags, unlinkatflags, inotify_modes): New variables. [LINUX] (print_dirfd, sys_openat, sys_faccessat, sys_newfstatat, sys_mkdirat, sys_linkat, sys_unlinkat, sys_symlinkat, sys_readlinkat, sys_renameat, sys_fchownat, sys_fchmodat, sys_futimesat, sys_mknodat, sys_inotify_add_watch, sys_inotify_rm_watch): New functions. * process.c [LINUX] (sys_unshare): New function. * signal.c (print_sigset): New function. (sys_sigprocmask): Use it. * stream.c (decode_poll): New function. (sys_poll): Use it. [LINUX] (sys_ppoll): New function. * linux/syscall.h: Delcare new syscall handlers. * linux/syscallent.h: Hook up new syscalls. * linux/alpha/syscallent.h: Likewise. * linux/hppa/syscallent.h: Likewise. * linux/ia64/syscallent.h: Likewise. * linux/mips/syscallent.h: Likewise. * linux/powerpc/syscallent.h: Likewise. * linux/s390/syscallent.h: Likewise. * linux/s390x/syscallent.h: Likewise. * linux/sparc/syscallent.h: Likewise. * linux/sparc64/syscallent.h: Likewise. * linux/x86_64/syscallent.h: Likewise. Fixes RH#178633.
2006-10-14 00:25:12 +04:00
print_sigset(tcp, tcp->u_arg[1], 0);
tprints(", ");
1999-02-19 03:21:36 +03:00
}
else {
if (!tcp->u_arg[2])
tprints("NULL");
1999-02-19 03:21:36 +03:00
else if (syserror(tcp))
tprintf("%#lx", tcp->u_arg[2]);
else
2006-10-13 Ulrich Drepper <drepper@redhat.com> Bernhard Kaindl <bk@suse.de> Dmitry V. Levin <ldv@altlinux.org> Michael Holzheu <holzheu@de.ibm.com> Add hooks for new syscalls. Add decoders for *at, inotify*, pselect6, ppoll and unshare syscalls. * defs.h: Declare print_sigset. * desc.c (sys_pselect6): New function. * file.c (decode_open, decode_access, decode_mkdir, decode_readlink, decode_chmod, decode_utimes, decode_mknod): New functions. (sys_open, sys_access, sys_mkdir, sys_readlink, sys_chmod, sys_utimes, sys_mknod): Use them. [LINUX] (fstatatflags, unlinkatflags, inotify_modes): New variables. [LINUX] (print_dirfd, sys_openat, sys_faccessat, sys_newfstatat, sys_mkdirat, sys_linkat, sys_unlinkat, sys_symlinkat, sys_readlinkat, sys_renameat, sys_fchownat, sys_fchmodat, sys_futimesat, sys_mknodat, sys_inotify_add_watch, sys_inotify_rm_watch): New functions. * process.c [LINUX] (sys_unshare): New function. * signal.c (print_sigset): New function. (sys_sigprocmask): Use it. * stream.c (decode_poll): New function. (sys_poll): Use it. [LINUX] (sys_ppoll): New function. * linux/syscall.h: Delcare new syscall handlers. * linux/syscallent.h: Hook up new syscalls. * linux/alpha/syscallent.h: Likewise. * linux/hppa/syscallent.h: Likewise. * linux/ia64/syscallent.h: Likewise. * linux/mips/syscallent.h: Likewise. * linux/powerpc/syscallent.h: Likewise. * linux/s390/syscallent.h: Likewise. * linux/s390x/syscallent.h: Likewise. * linux/sparc/syscallent.h: Likewise. * linux/sparc64/syscallent.h: Likewise. * linux/x86_64/syscallent.h: Likewise. Fixes RH#178633.
2006-10-14 00:25:12 +04:00
print_sigset(tcp, tcp->u_arg[2], 0);
1999-02-19 03:21:36 +03:00
}
#endif /* !ALPHA */
return 0;
}
#endif /* HAVE_SIGACTION */
int
sys_kill(struct tcb *tcp)
1999-02-19 03:21:36 +03:00
{
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 (current_wordsize < sizeof pid)
pid = (long) (int) pid;
#endif
tprintf("%ld, %s", pid, signame(tcp->u_arg[1]));
1999-02-19 03:21:36 +03:00
}
return 0;
}
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;
}
1999-02-19 03:21:36 +03:00
int
sys_sigpending(struct tcb *tcp)
1999-02-19 03:21:36 +03:00
{
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("[?]");
1999-02-19 03:21:36 +03:00
else
printsigmask(&sigset, 0);
1999-02-19 03:21:36 +03:00
}
return 0;
}
int
sys_rt_sigprocmask(struct tcb *tcp)
1999-02-19 03:21:36 +03:00
{
sigset_t sigset;
/* Note: arg[3] is the length of the sigset. */
1999-02-19 03:21:36 +03:00
if (entering(tcp)) {
printxval(sigprocmaskcmds, tcp->u_arg[0], "SIG_???");
tprints(", ");
1999-02-19 03:21:36 +03:00
if (!tcp->u_arg[1])
tprints("NULL, ");
else if (copy_sigset_len(tcp, tcp->u_arg[1], &sigset, tcp->u_arg[3]) < 0)
1999-02-19 03:21:36 +03:00
tprintf("%#lx, ", tcp->u_arg[1]);
else {
printsigmask(&sigset, 1);
tprints(", ");
1999-02-19 03:21:36 +03:00
}
}
else {
if (!tcp->u_arg[2])
tprints("NULL");
1999-02-19 03:21:36 +03:00
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("[?]");
1999-02-19 03:21:36 +03:00
else
printsigmask(&sigset, 1);
tprintf(", %lu", tcp->u_arg[3]);
1999-02-19 03:21:36 +03:00
}
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: */
void (*__sa_handler)(int);
1999-02-19 03:21:36 +03:00
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)];
1999-02-19 03:21:36 +03:00
};
int
sys_rt_sigaction(struct tcb *tcp)
1999-02-19 03:21:36 +03:00
{
struct new_sigaction sa;
sigset_t sigset;
long addr;
int r;
1999-02-19 03:21:36 +03:00
if (entering(tcp)) {
printsignal(tcp->u_arg[0]);
tprints(", ");
1999-02-19 03:21:36 +03:00
addr = tcp->u_arg[1];
} else
addr = tcp->u_arg[2];
if (addr == 0) {
tprints("NULL");
goto after_sa;
}
if (!verbose(tcp)) {
1999-02-19 03:21:36 +03:00
tprintf("%#lx", addr);
goto after_sa;
}
#if SUPPORTED_PERSONALITIES > 1
#if 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;
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
#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);
1999-06-03 18:21:07 +04:00
#ifdef LINUXSPARC
if (tcp->u_arg[4] <= sizeof(sigset))
memcpy(&sigset, &sa.sa_mask, tcp->u_arg[4]);
1999-06-03 18:21:07 +04:00
#else
if (tcp->u_arg[3] <= sizeof(sigset))
memcpy(&sigset, &sa.sa_mask, tcp->u_arg[3]);
1999-06-03 18:21:07 +04:00
#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:
1999-02-19 03:21:36 +03:00
if (entering(tcp))
tprints(", ");
1999-02-19 03:21:36 +03:00
else
1999-06-03 18:21:07 +04:00
#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]);
1999-06-03 18:21:07 +04:00
#endif
1999-02-19 03:21:36 +03:00
return 0;
}
int
sys_rt_sigpending(struct tcb *tcp)
1999-02-19 03:21:36 +03:00
{
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("[?]");
1999-02-19 03:21:36 +03:00
else
printsigmask(&sigset, 1);
1999-02-19 03:21:36 +03:00
}
return 0;
}
int
sys_rt_sigsuspend(struct tcb *tcp)
1999-02-19 03:21:36 +03:00
{
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);
1999-02-19 03:21:36 +03:00
}
return 0;
}
static void
print_sigqueueinfo(struct tcb *tcp, int sig, unsigned long uinfo)
{
siginfo_t si;
printsignal(sig);
tprints(", ");
if (umove(tcp, uinfo, &si) < 0)
tprintf("%#lx", uinfo);
else
printsiginfo(&si, verbose(tcp));
}
int
sys_rt_sigqueueinfo(struct tcb *tcp)
1999-02-19 03:21:36 +03:00
{
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]);
1999-02-19 03:21:36 +03:00
}
return 0;
}
int sys_rt_sigtimedwait(struct tcb *tcp)
1999-02-19 03:21:36 +03:00
{
if (entering(tcp)) {
sigset_t sigset;
if (copy_sigset_len(tcp, tcp->u_arg[0],
&sigset, tcp->u_arg[3]) < 0)
tprints("[?]");
1999-02-19 03:21:36 +03:00
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, ");
1999-02-19 03:21:36 +03:00
}
else if (tcp->u_arg[1] != 0) {
/* syscall exit, and u_arg[1] wasn't NULL */
1999-02-19 03:21:36 +03:00
if (syserror(tcp))
tprintf("%#lx, ", tcp->u_arg[1]);
1999-02-19 03:21:36 +03:00
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(", ");
}
1999-02-19 03:21:36 +03:00
}
}
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]);
1999-02-19 03:21:36 +03:00
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);
}