]> granicus.if.org Git - strace/commitdiff
Cleanup poll/ppoll decoders
authorDmitry V. Levin <ldv@altlinux.org>
Thu, 30 Jul 2015 19:46:11 +0000 (19:46 +0000)
committerDmitry V. Levin <ldv@altlinux.org>
Thu, 30 Jul 2015 22:03:07 +0000 (22:03 +0000)
* poll.c (decode_poll): Split into print_pollfd, decode_poll_entering,
and decode_poll_exiting.
(sys_poll, sys_ppoll): Update callers.
* tests/ppoll.c: New file.
* tests/ppoll.expected: Likewise.
* tests/ppoll-v.expected: Likewise.
* tests/ppoll.test: New test.
* tests/Makefile.am (check_PROGRAMS): Add ppoll.
(TESTS): Add ppoll.test.
(EXTRA_DIST): Add ppoll.expected and ppoll-v.expected.
* tests/.gitignore: Add ppoll.

poll.c
tests/.gitignore
tests/Makefile.am
tests/ppoll-v.expected [new file with mode: 0644]
tests/ppoll.c [new file with mode: 0644]
tests/ppoll.expected [new file with mode: 0644]
tests/ppoll.test [new file with mode: 0755]

diff --git a/poll.c b/poll.c
index f11ad9d42c7aed8af0b1b64f0fdb3b4d62bce77d..4d31944d073d28cb5fe9acd164d69a1becf22043 100644 (file)
--- a/poll.c
+++ b/poll.c
 
 #include "xlat/pollflags.h"
 
+static void
+print_pollfd(struct tcb *tcp, const struct pollfd *fds)
+{
+       tprints("{fd=");
+       printfd(tcp, fds->fd);
+       if (fds->fd >= 0) {
+               tprints(", events=");
+               printflags(pollflags, fds->events, "POLL???");
+       }
+       tprints("}");
+}
+
 static int
-decode_poll(struct tcb *tcp, long pts)
+decode_poll_entering(struct tcb *tcp)
 {
        struct pollfd fds;
-       unsigned nfds;
-       unsigned long size, start, cur, end, abbrev_end;
-       int failed = 0;
+       const unsigned int nfds = tcp->u_arg[1];
+       const unsigned long size = sizeof(fds) * nfds;
+       const unsigned long start = tcp->u_arg[0];
+       const unsigned long end = start + size;
+       unsigned long cur, abbrev_end;
 
-       if (entering(tcp)) {
-               nfds = tcp->u_arg[1];
-               size = sizeof(fds) * nfds;
-               start = tcp->u_arg[0];
-               end = start + size;
-               if (nfds == 0 || size / sizeof(fds) != nfds || end < start) {
-                       tprintf("%#lx, %d, ",
-                               tcp->u_arg[0], nfds);
-                       return 0;
-               }
-               if (abbrev(tcp)) {
-                       abbrev_end = start + max_strlen * sizeof(fds);
-                       if (abbrev_end < start)
-                               abbrev_end = end;
-               } else {
+       if (!verbose(tcp) || !start || !nfds ||
+           size / sizeof(fds) != nfds || end < start) {
+               printaddr(start);
+               tprintf(", %u, ", nfds);
+               return 0;
+       }
+
+       if (abbrev(tcp)) {
+               abbrev_end = start + max_strlen * sizeof(fds);
+               if (abbrev_end < start)
                        abbrev_end = end;
+       } else {
+               abbrev_end = end;
+       }
+
+       if (start >= abbrev_end || umove(tcp, start, &fds) < 0) {
+               printaddr(start);
+               tprintf(", %u, ", nfds);
+               return 0;
+       }
+
+       tprints("[");
+       print_pollfd(tcp, &fds);
+       for (cur = start + sizeof(fds); cur < end; cur += sizeof(fds)) {
+               tprints(", ");
+               if (cur >= abbrev_end) {
+                       tprints("...");
+                       break;
                }
-               tprints("[");
-               for (cur = start; cur < end; cur += sizeof(fds)) {
-                       if (cur > start)
-                               tprints(", ");
-                       if (cur >= abbrev_end) {
-                               tprints("...");
-                               break;
-                       }
-                       if (umoven(tcp, cur, sizeof fds, &fds) < 0) {
-                               tprints("?");
-                               failed = 1;
-                               break;
-                       }
-                       if (fds.fd < 0) {
-                               tprintf("{fd=%d}", fds.fd);
-                               continue;
-                       }
-                       tprints("{fd=");
-                       printfd(tcp, fds.fd);
-                       tprints(", events=");
-                       printflags(pollflags, fds.events, "POLL???");
-                       tprints("}");
+               if (umove(tcp, cur, &fds) < 0) {
+                       tprints("???");
+                       break;
                }
-               tprints("]");
-               if (failed)
-                       tprintf(" %#lx", start);
-               tprintf(", %d, ", nfds);
-               return 0;
-       } else {
-               static char outstr[1024];
-               char *outptr;
+               print_pollfd(tcp, &fds);
+
+       }
+       tprintf("], %u, ", nfds);
+
+       return 0;
+}
+
+static int
+decode_poll_exiting(struct tcb *tcp, const long pts)
+{
+       struct pollfd fds;
+       const unsigned int nfds = tcp->u_arg[1];
+       const unsigned long size = sizeof(fds) * nfds;
+       const unsigned long start = tcp->u_arg[0];
+       const unsigned long end = start + size;
+       unsigned long cur, abbrev_end;
+
+       static char outstr[1024];
+       char *outptr;
 #define end_outstr (outstr + sizeof(outstr))
-               const char *flagstr;
 
-               if (syserror(tcp))
-                       return 0;
-               if (tcp->u_rval == 0) {
-                       tcp->auxstr = "Timeout";
-                       return RVAL_STR;
-               }
+       if (syserror(tcp))
+               return 0;
+       if (tcp->u_rval == 0) {
+               tcp->auxstr = "Timeout";
+               return RVAL_STR;
+       }
 
-               nfds = tcp->u_arg[1];
-               size = sizeof(fds) * nfds;
-               start = tcp->u_arg[0];
-               end = start + size;
-               if (nfds == 0 || size / sizeof(fds) != nfds || end < start)
-                       return 0;
-               if (abbrev(tcp)) {
-                       abbrev_end = start + max_strlen * sizeof(fds);
-                       if (abbrev_end < start)
-                               abbrev_end = end;
-               } else {
+       if (!verbose(tcp) || !start || !nfds ||
+           size / sizeof(fds) != nfds || end < start)
+               return 0;
+       if (abbrev(tcp)) {
+               abbrev_end = start + max_strlen * sizeof(fds);
+               if (abbrev_end < start)
                        abbrev_end = end;
-               }
+       } else {
+               abbrev_end = end;
+       }
 
-               outptr = outstr;
-
-               for (cur = start; cur < end; cur += sizeof(fds)) {
-                       if (umoven(tcp, cur, sizeof fds, &fds) < 0) {
-                               if (outptr < end_outstr - 2)
-                                       *outptr++ = '?';
-                               failed = 1;
-                               break;
-                       }
-                       if (!fds.revents)
-                               continue;
-                       if (outptr == outstr) {
+       outptr = outstr;
+
+       for (cur = start; cur < end; cur += sizeof(fds)) {
+               if (umove(tcp, cur, &fds) < 0) {
+                       if (outptr == outstr)
                                *outptr++ = '[';
-                       } else {
-                               if (outptr < end_outstr - 3)
-                                       outptr = stpcpy(outptr, ", ");
-                       }
-                       if (cur >= abbrev_end) {
-                               if (outptr < end_outstr - 4)
-                                       outptr = stpcpy(outptr, "...");
-                               break;
-                       }
-                       if (outptr < end_outstr - (sizeof("{fd=%d, revents=") + sizeof(int)*3) + 1)
-                               outptr += sprintf(outptr, "{fd=%d, revents=", fds.fd);
-                       flagstr = sprintflags("", pollflags, fds.revents);
-                       if (outptr < end_outstr - (strlen(flagstr) + 2)) {
-                               outptr = stpcpy(outptr, flagstr);
-                               *outptr++ = '}';
-                       }
+                       else
+                               outptr = stpcpy(outptr, ", ");
+                       outptr = stpcpy(outptr, "???");
+                       break;
                }
-               if (failed)
-                       return 0;
-
-               if (outptr != outstr /* && outptr < end_outstr - 1 (always true)*/)
-                       *outptr++ = ']';
-
-               *outptr = '\0';
-               if (pts) {
-                       if (outptr < end_outstr - (10 + TIMESPEC_TEXT_BUFSIZE)) {
-                               outptr = stpcpy(outptr, outptr == outstr ? "left " : ", left ");
-                               sprint_timespec(outptr, tcp, pts);
-                       }
+               if (!fds.revents)
+                       continue;
+               if (outptr == outstr)
+                       *outptr++ = '[';
+               else
+                       outptr = stpcpy(outptr, ", ");
+               if (cur >= abbrev_end) {
+                       outptr = stpcpy(outptr, "...");
+                       break;
                }
 
-               if (outptr == outstr)
-                       return 0;
+               static const char fmt[] = "{fd=%d, revents=";
+               char fdstr[sizeof(fmt) + sizeof(int) * 3];
+               sprintf(fdstr, fmt, fds.fd);
 
-               tcp->auxstr = outstr;
-               return RVAL_STR;
-#undef end_outstr
+               const char *flagstr = sprintflags("", pollflags, fds.revents);
+
+               if (outptr + strlen(fdstr) + strlen(flagstr) + 1
+                   >= end_outstr - sizeof(", ...]")) {
+                       outptr = stpcpy(outptr, "...");
+                       break;
+               }
+               outptr = stpcpy(outptr, fdstr);
+               outptr = stpcpy(outptr, flagstr);
+               *outptr++ = '}';
+       }
+
+       if (outptr != outstr)
+               *outptr++ = ']';
+
+       *outptr = '\0';
+       if (pts) {
+               char tmbuf[TIMESPEC_TEXT_BUFSIZE];
+
+               sprint_timespec(tmbuf, tcp, pts);
+               if (outptr + sizeof(", left ") + strlen(tmbuf) < end_outstr) {
+                       outptr = stpcpy(outptr, outptr == outstr ? "left " : ", left ");
+                       outptr = stpcpy(outptr, tmbuf);
+               } else {
+                       outptr = stpcpy(outptr, ", ...");
+               }
        }
+
+       if (outptr == outstr)
+               return 0;
+
+       tcp->auxstr = outstr;
+       return RVAL_STR;
+#undef end_outstr
 }
 
 SYS_FUNC(poll)
 {
-       int rc = decode_poll(tcp, 0);
        if (entering(tcp)) {
+               int rc = decode_poll_entering(tcp);
+
 #ifdef INFTIM
                if (INFTIM == (int) tcp->u_arg[2])
                        tprints("INFTIM");
                else
 #endif
                        tprintf("%d", (int) tcp->u_arg[2]);
+
+               return rc;
+       } else {
+               return decode_poll_exiting(tcp, 0);
        }
-       return rc;
 }
 
 SYS_FUNC(ppoll)
 {
-       int rc = decode_poll(tcp, tcp->u_arg[2]);
        if (entering(tcp)) {
+               int rc = decode_poll_entering(tcp);
+
                print_timespec(tcp, tcp->u_arg[2]);
                tprints(", ");
                /* 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;
+       } else {
+               return decode_poll_exiting(tcp, tcp->u_arg[2]);
        }
-       return rc;
 }
index 801acee6f93ef45348e6cb349199640194289f4e..f951246092a2937e3ecc5a634925a019f6d5b53a 100644 (file)
@@ -21,6 +21,7 @@ netlink_unix_diag
 oldselect
 pc
 pipe
+ppoll
 sched_xetattr
 scm_rights
 seccomp
index 4a51a4d4dce3a7b95d8029f373a6061c58267737..a94881c0e5ac66ffe918c61c3bc8a17fe9f9da94 100644 (file)
@@ -32,6 +32,7 @@ check_PROGRAMS = \
        oldselect \
        pc \
        pipe \
+       ppoll \
        sched_xetattr \
        scm_rights \
        seccomp \
@@ -102,6 +103,7 @@ TESTS = \
        oldselect.test \
        pipe.test \
        pc.test \
+       ppoll.test \
        sun_path.test \
        umovestr.test \
        umovestr2.test \
@@ -147,6 +149,8 @@ EXTRA_DIST = init.sh run.sh match.awk \
             net-yy-connect.awk \
             oldselect.expected \
             pipe.expected \
+            ppoll.expected \
+            ppoll-v.expected \
             restart_syscall.expected \
             restart_syscall_unknown.expected \
             select.awk \
diff --git a/tests/ppoll-v.expected b/tests/ppoll-v.expected
new file mode 100644 (file)
index 0000000..4813ecf
--- /dev/null
@@ -0,0 +1,3 @@
+ppoll\(\[\{fd=0, events=POLLIN\|POLLPRI\|POLLRDNORM\|POLLRDBAND\}, \{fd=1, events=POLLOUT(\|POLLWRNORM)?\|POLLWRBAND\}, \{fd=3, events=POLLIN\|POLLPRI\}, \{fd=4, events=POLLOUT\}\], 4, \{42, 999999999\}, \[(USR2 CHLD|CHLD USR2)\], (4|8|16)\) += 2 \(\[\{fd=1, revents=POLLOUT(\|POLLWRNORM)?\}, \{fd=4, revents=POLLOUT\}\], left \{42, 9[0-9]{8}\}\)
+ppoll\(\[\{fd=1, events=POLLIN\|POLLPRI\|POLLRDNORM\|POLLRDBAND\}, \{fd=0, events=POLLOUT(\|POLLWRNORM)?\|POLLWRBAND\}\], 2, \{0, 999\}, ~\[ABRT KILL STOP[^]]*\], (4|8|16)\) += 0 \(Timeout\)
+ppoll\(NULL, 42, NULL, NULL, (4|8|16)\) += -1 EFAULT .*
diff --git a/tests/ppoll.c b/tests/ppoll.c
new file mode 100644 (file)
index 0000000..978bbb8
--- /dev/null
@@ -0,0 +1,67 @@
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include <poll.h>
+#include <signal.h>
+#include <unistd.h>
+
+static int
+test1(void)
+{
+       sigset_t mask;
+       const struct timespec timeout = { .tv_sec = 42, .tv_nsec = 999999999 };
+       struct pollfd fds[] = {
+               { .fd = 0, .events = POLLIN | POLLPRI | POLLRDNORM | POLLRDBAND },
+               { .fd = 1, .events = POLLOUT | POLLWRNORM | POLLWRBAND },
+               { .fd = 3, .events = POLLIN | POLLPRI },
+               { .fd = 4, .events = POLLOUT }
+       };
+
+       sigemptyset(&mask);
+       sigaddset(&mask, SIGUSR2);
+       sigaddset(&mask, SIGCHLD);
+
+       return ppoll(fds, sizeof(fds) / sizeof(*fds), &timeout, &mask) == 2 ? 0 : 77;
+}
+
+static int
+test2(void)
+{
+       sigset_t mask;
+       const struct timespec timeout = { .tv_sec = 0, .tv_nsec = 999 };
+       struct pollfd fds[] = {
+               { .fd = 1, .events = POLLIN | POLLPRI | POLLRDNORM | POLLRDBAND },
+               { .fd = 0, .events = POLLOUT | POLLWRNORM | POLLWRBAND }
+       };
+
+       sigfillset(&mask);
+       sigdelset(&mask, SIGABRT);
+       sigdelset(&mask, SIGKILL);
+       sigdelset(&mask, SIGSTOP);
+
+       return ppoll(fds, sizeof(fds) / sizeof(*fds), &timeout, &mask) == 0 ? 0 : 77;
+}
+
+int
+main(void)
+{
+       int rc;
+       int fds[2];
+
+       (void) close(0);
+       (void) close(1);
+       (void) close(3);
+       (void) close(4);
+       if (pipe(fds) || pipe(fds))
+               return 77;
+
+
+       if ((rc = test1()))
+               return rc;
+
+       if ((rc = test2()))
+               return rc;
+
+       return ppoll(NULL, 42, NULL, NULL) < 0 ? 0 : 77;
+}
diff --git a/tests/ppoll.expected b/tests/ppoll.expected
new file mode 100644 (file)
index 0000000..8dc518f
--- /dev/null
@@ -0,0 +1,3 @@
+ppoll\(\[\{fd=0, events=POLLIN\|POLLPRI\|POLLRDNORM\|POLLRDBAND\}, \{fd=1, events=POLLOUT(\|POLLWRNORM)?\|POLLWRBAND\}, \.\.\.\], 4, \{42, 999999999\}, \[(USR2 CHLD|CHLD USR2)\], (4|8|16)\) += 2 \(\[\{fd=1, revents=POLLOUT(\|POLLWRNORM)?\}, \.\.\.\], left \{42, 9[0-9]{8}\}\)
+ppoll\(\[\{fd=1, events=POLLIN\|POLLPRI\|POLLRDNORM\|POLLRDBAND\}, \{fd=0, events=POLLOUT(\|POLLWRNORM)?\|POLLWRBAND\}\], 2, \{0, 999\}, ~\[ABRT KILL STOP[^]]*\], (4|8|16)\) += 0 \(Timeout\)
+ppoll\(NULL, 42, NULL, NULL, (4|8|16)\) += -1 EFAULT .*
diff --git a/tests/ppoll.test b/tests/ppoll.test
new file mode 100755 (executable)
index 0000000..38fec23
--- /dev/null
@@ -0,0 +1,13 @@
+#!/bin/sh
+
+# Check ppoll syscall decoding.
+
+. "${srcdir=.}/init.sh"
+
+run_prog
+run_strace -s2 -e ppoll $args
+match_grep
+run_strace -v -s2 -e ppoll $args
+match_grep "$LOG" "$srcdir/${ME_%.test}-v.expected"
+
+exit 0