From: Dmitry V. Levin Date: Thu, 30 Jul 2015 19:46:11 +0000 (+0000) Subject: Cleanup poll/ppoll decoders X-Git-Tag: v4.11~309 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=d9fb450748bcb413be09f705958c6335f22fca62;p=strace Cleanup poll/ppoll decoders * 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. --- diff --git a/poll.c b/poll.c index f11ad9d4..4d31944d 100644 --- a/poll.c +++ b/poll.c @@ -31,162 +31,194 @@ #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; } diff --git a/tests/.gitignore b/tests/.gitignore index 801acee6..f9512460 100644 --- a/tests/.gitignore +++ b/tests/.gitignore @@ -21,6 +21,7 @@ netlink_unix_diag oldselect pc pipe +ppoll sched_xetattr scm_rights seccomp diff --git a/tests/Makefile.am b/tests/Makefile.am index 4a51a4d4..a94881c0 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -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 index 00000000..4813ecf8 --- /dev/null +++ b/tests/ppoll-v.expected @@ -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 index 00000000..978bbb8a --- /dev/null +++ b/tests/ppoll.c @@ -0,0 +1,67 @@ +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include +#include +#include + +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 index 00000000..8dc518f3 --- /dev/null +++ b/tests/ppoll.expected @@ -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 index 00000000..38fec235 --- /dev/null +++ b/tests/ppoll.test @@ -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