]> granicus.if.org Git - strace/commitdiff
Fix sigset printing via print_sigset().
authorDenys Vlasenko <dvlasenk@redhat.com>
Thu, 18 Jul 2013 15:02:21 +0000 (17:02 +0200)
committerDenys Vlasenko <dvlasenk@redhat.com>
Thu, 18 Jul 2013 15:31:42 +0000 (17:31 +0200)
Replace print_sigset() with print_sigset_addr_len(),
which takes not only addr, but also len parameter.
This allows us to drop "do we need to print RT signals?" parameter,
and this fixes RT signals printing in many syscalls.

sys_epoll_pwait: print RT signals too, print sigmask size argument.

sys_sigprocmask: print_sigset -> print_sigset_addr_len(current_wordsize),
no change in functionality.

sys_sigpending: use print_sigset_addr_len(current_wordsize)
instead of open-coding it.

sys_rt_sigprocmask: use print_sigset_addr_len instead of open-coding it.
sys_rt_sigpending: ditto.
sys_rt_sigsuspend: ditto.
sys_rt_sigtimedwait: ditto.

do_signalfd: print_sigset -> print_sigset_addr_len. This fixes
RT signals printing (wasn't showing them before).

sys_ppoll: ditto.

copy_sigset_len() is folded into its only user, print_sigset_addr_len(),
and copy_sigset() is gone.

While at it, checked kernel sources and noted where kernel enforces
sigset_size == NSIG / 8 (== sizeof(kernel_sigset_t)),
and where it allows word-sized sigset_size ([rt_]sigpending).

Signed-off-by: Denys Vlasenko <dvlasenk@redhat.com>
defs.h
desc.c
signal.c
stream.c

diff --git a/defs.h b/defs.h
index 3c7e2cf9e240eca4d179378788aad2f044c0cf1f..964636bab2e68419c64dd0278696e63919ac7448 100644 (file)
--- a/defs.h
+++ b/defs.h
@@ -695,7 +695,7 @@ extern void printrusage(struct tcb *, long);
 extern void printrusage32(struct tcb *, long);
 #endif
 extern void printuid(const char *, unsigned long);
-extern void print_sigset(struct tcb *, long, int);
+extern void print_sigset_addr_len(struct tcb *, long, long);
 extern void printsignal(int);
 extern void tprint_iov(struct tcb *, unsigned long, unsigned long, int decode_iov);
 extern void tprint_iov_upto(struct tcb *, unsigned long, unsigned long, int decode_iov, unsigned long);
diff --git a/desc.c b/desc.c
index a420febcdc01e766a6487908815686fb804b6e2d..ac07ca7234f7f7b809c8fbd521890264bbdf2672 100644 (file)
--- a/desc.c
+++ b/desc.c
@@ -790,7 +790,9 @@ sys_epoll_pwait(struct tcb *tcp)
        epoll_wait_common(tcp);
        if (exiting(tcp)) {
                tprints(", ");
-               print_sigset(tcp, tcp->u_arg[4], 0);
+               /* NB: kernel requires arg[5] == NSIG / 8 */
+               print_sigset_addr_len(tcp, tcp->u_arg[4], tcp->u_arg[5]);
+               tprintf(", %lu", tcp->u_arg[5]);
        }
        return 0;
 }
@@ -1054,10 +1056,8 @@ sys_pselect6(struct tcb *tcp)
                        tprintf(", %#lx", tcp->u_arg[5]);
                else {
                        tprints(", {");
-                       if (data.len < sizeof(long))
-                               tprintf("%#lx", (long)data.ss);
-                       else
-                               print_sigset(tcp, (long)data.ss, 0);
+                       /* NB: kernel requires data.len == NSIG / 8 */
+                       print_sigset_addr_len(tcp, (long)data.ss, data.len);
                        tprintf(", %lu}", data.len);
                }
        }
index 66ce61362293a35acb60667802377d6b1383fd43..d863e502cbbe1cf4117aace7a9d19b0f9679d894 100644 (file)
--- a/signal.c
+++ b/signal.c
@@ -220,20 +220,6 @@ long_to_sigset(long l, sigset_t *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 */
@@ -313,16 +299,28 @@ printsignal(int nr)
 }
 
 void
-print_sigset(struct tcb *tcp, long addr, int rt)
+print_sigset_addr_len(struct tcb *tcp, long addr, long len)
 {
        sigset_t ss;
 
-       if (!addr)
+       if (!addr) {
                tprints("NULL");
-       else if (copy_sigset(tcp, addr, &ss) < 0)
+               return;
+       }
+       /* Here len is usually equals NSIG / 8 or current_wordsize.
+        * But we code this defensively:
+        */
+       if (len < 0) {
+ bad:
                tprintf("%#lx", addr);
-       else
-               printsigmask(&ss, rt);
+               return;
+       }
+       if (len > NSIG / 8)
+               len = NSIG / 8;
+       sigemptyset(&ss);
+       if (umoven(tcp, addr, len, (char *)&ss) < 0)
+               goto bad;
+       printsigmask(&ss, /*rt:*/ 1);
 }
 
 #ifndef ILL_ILLOPC
@@ -1124,10 +1122,11 @@ sys_sigaltstack(struct tcb *tcp)
 
 #ifdef HAVE_SIGACTION
 
+/* "Old" sigprocmask, which operates with word-sized signal masks */
 int
 sys_sigprocmask(struct tcb *tcp)
 {
-#ifdef ALPHA
+# ifdef ALPHA
        sigset_t ss;
        if (entering(tcp)) {
                /*
@@ -1151,22 +1150,20 @@ sys_sigprocmask(struct tcb *tcp)
                tcp->auxstr = sprintsigmask("old mask ", &ss, 0);
                return RVAL_HEX | RVAL_STR;
        }
-#else /* !ALPHA */
+# else /* !ALPHA */
        if (entering(tcp)) {
                printxval(sigprocmaskcmds, tcp->u_arg[0], "SIG_???");
                tprints(", ");
-               print_sigset(tcp, tcp->u_arg[1], 0);
+               print_sigset_addr_len(tcp, tcp->u_arg[1], current_wordsize);
                tprints(", ");
        }
        else {
-               if (!tcp->u_arg[2])
-                       tprints("NULL");
-               else if (syserror(tcp))
+               if (syserror(tcp))
                        tprintf("%#lx", tcp->u_arg[2]);
                else
-                       print_sigset(tcp, tcp->u_arg[2], 0);
+                       print_sigset_addr_len(tcp, tcp->u_arg[2], current_wordsize);
        }
-#endif /* !ALPHA */
+# endif /* !ALPHA */
        return 0;
 }
 
@@ -1200,15 +1197,11 @@ sys_tgkill(struct tcb *tcp)
 int
 sys_sigpending(struct tcb *tcp)
 {
-       sigset_t sigset;
-
        if (exiting(tcp)) {
                if (syserror(tcp))
                        tprintf("%#lx", tcp->u_arg[0]);
-               else if (copy_sigset(tcp, tcp->u_arg[0], &sigset) < 0)
-                       tprints("[?]");
                else
-                       printsigmask(&sigset, 0);
+                       print_sigset_addr_len(tcp, tcp->u_arg[0], current_wordsize);
        }
        return 0;
 }
@@ -1216,30 +1209,18 @@ sys_sigpending(struct tcb *tcp)
 int
 sys_rt_sigprocmask(struct tcb *tcp)
 {
-       sigset_t sigset;
-
-       /* Note: arg[3] is the length of the sigset. */
+       /* Note: arg[3] is the length of the sigset. Kernel requires NSIG / 8 */
        if (entering(tcp)) {
                printxval(sigprocmaskcmds, tcp->u_arg[0], "SIG_???");
                tprints(", ");
-               if (!tcp->u_arg[1])
-                       tprints("NULL, ");
-               else if (copy_sigset_len(tcp, tcp->u_arg[1], &sigset, tcp->u_arg[3]) < 0)
-                       tprintf("%#lx, ", tcp->u_arg[1]);
-               else {
-                       printsigmask(&sigset, 1);
-                       tprints(", ");
-               }
+               print_sigset_addr_len(tcp, tcp->u_arg[1], tcp->u_arg[3]);
+               tprints(", ");
        }
        else {
-               if (!tcp->u_arg[2])
-                       tprints("NULL");
-               else if (syserror(tcp))
+               if (syserror(tcp))
                        tprintf("%#lx", tcp->u_arg[2]);
-               else if (copy_sigset_len(tcp, tcp->u_arg[2], &sigset, tcp->u_arg[3]) < 0)
-                       tprints("[?]");
                else
-                       printsigmask(&sigset, 1);
+                       print_sigset_addr_len(tcp, tcp->u_arg[2], tcp->u_arg[3]);
                tprintf(", %lu", tcp->u_arg[3]);
        }
        return 0;
@@ -1367,16 +1348,18 @@ sys_rt_sigaction(struct tcb *tcp)
 int
 sys_rt_sigpending(struct tcb *tcp)
 {
-       sigset_t sigset;
-
        if (exiting(tcp)) {
+               /*
+                * One of the few syscalls where sigset size (arg[1])
+                * is allowed to be <= NSIG / 8, not strictly ==.
+                * This allows non-rt sigpending() syscall
+                * to reuse rt_sigpending() code in kernel.
+                */
                if (syserror(tcp))
                        tprintf("%#lx", tcp->u_arg[0]);
-               else if (copy_sigset_len(tcp, tcp->u_arg[0],
-                                        &sigset, tcp->u_arg[1]) < 0)
-                       tprints("[?]");
                else
-                       printsigmask(&sigset, 1);
+                       print_sigset_addr_len(tcp, tcp->u_arg[0], tcp->u_arg[1]);
+               tprintf(", %lu", tcp->u_arg[1]);
        }
        return 0;
 }
@@ -1385,11 +1368,9 @@ int
 sys_rt_sigsuspend(struct tcb *tcp)
 {
        if (entering(tcp)) {
-               sigset_t sigm;
-               if (copy_sigset_len(tcp, tcp->u_arg[0], &sigm, tcp->u_arg[1]) < 0)
-                       tprints("[?]");
-               else
-                       printsigmask(&sigm, 1);
+               /* NB: kernel requires arg[1] == NSIG / 8 */
+               print_sigset_addr_len(tcp, tcp->u_arg[0], tcp->u_arg[1]);
+               tprintf(", %lu", tcp->u_arg[1]);
        }
        return 0;
 }
@@ -1424,14 +1405,9 @@ sys_rt_tgsigqueueinfo(struct tcb *tcp)
 
 int sys_rt_sigtimedwait(struct tcb *tcp)
 {
+       /* NB: kernel requires arg[3] == NSIG / 8 */
        if (entering(tcp)) {
-               sigset_t sigset;
-
-               if (copy_sigset_len(tcp, tcp->u_arg[0],
-                                   &sigset, tcp->u_arg[3]) < 0)
-                       tprints("[?]");
-               else
-                       printsigmask(&sigset, 1);
+               print_sigset_addr_len(tcp, tcp->u_arg[0], tcp->u_arg[3]);
                tprints(", ");
                /* This is the only "return" parameter, */
                if (tcp->u_arg[1] != 0)
@@ -1449,7 +1425,7 @@ int sys_rt_sigtimedwait(struct tcb *tcp)
                return 0;
        }
        print_timespec(tcp, tcp->u_arg[2]);
-       tprintf(", %d", (int) tcp->u_arg[3]);
+       tprintf(", %lu", tcp->u_arg[3]);
        return 0;
 };
 
@@ -1464,10 +1440,11 @@ sys_restart_syscall(struct tcb *tcp)
 static int
 do_signalfd(struct tcb *tcp, int flags_arg)
 {
+       /* NB: kernel requires arg[2] == NSIG / 8 */
        if (entering(tcp)) {
                printfd(tcp, tcp->u_arg[0]);
                tprints(", ");
-               print_sigset(tcp, tcp->u_arg[1], 1);
+               print_sigset_addr_len(tcp, tcp->u_arg[1], tcp->u_arg[2]);
                tprintf(", %lu", tcp->u_arg[2]);
                if (flags_arg >= 0) {
                        tprints(", ");
index 8c908382ccca4d4cd2821213a7ca06cd57d45c76..18a8ca94c7959e697ce159b604da6c43eb49d88d 100644 (file)
--- a/stream.c
+++ b/stream.c
@@ -422,7 +422,8 @@ sys_ppoll(struct tcb *tcp)
        if (entering(tcp)) {
                print_timespec(tcp, tcp->u_arg[2]);
                tprints(", ");
-               print_sigset(tcp, tcp->u_arg[3], 0);
+               /* NB: kernel requires arg[4] == NSIG / 8 */
+               print_sigset_addr_len(tcp, tcp->u_arg[3], tcp->u_arg[4]);
                tprintf(", %lu", tcp->u_arg[4]);
        }
        return rc;