desc.c revision 594527353359d9a6aad516992e09c393e11f3bd2
1/*
2 * Copyright (c) 1991, 1992 Paul Kranenburg <pk@cs.few.eur.nl>
3 * Copyright (c) 1993 Branko Lankester <branko@hacktic.nl>
4 * Copyright (c) 1993, 1994, 1995, 1996 Rick Sladkey <jrs@world.std.com>
5 * Copyright (c) 1996-1999 Wichert Akkerman <wichert@cistron.nl>
6 * All rights reserved.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 *    notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 *    notice, this list of conditions and the following disclaimer in the
15 *    documentation and/or other materials provided with the distribution.
16 * 3. The name of the author may not be used to endorse or promote products
17 *    derived from this software without specific prior written permission.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
20 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
21 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
22 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
23 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
24 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
28 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 */
30
31#include "defs.h"
32#include <fcntl.h>
33#include <sys/file.h>
34#ifdef HAVE_SYS_EPOLL_H
35# include <sys/epoll.h>
36#endif
37#ifdef HAVE_LINUX_PERF_EVENT_H
38# include  <linux/perf_event.h>
39#endif
40
41static const struct xlat fcntlcmds[] = {
42	XLAT(F_DUPFD),
43	XLAT(F_GETFD),
44	XLAT(F_SETFD),
45	XLAT(F_GETFL),
46	XLAT(F_SETFL),
47	XLAT(F_GETLK),
48	XLAT(F_SETLK),
49	XLAT(F_SETLKW),
50	XLAT(F_GETOWN),
51	XLAT(F_SETOWN),
52#ifdef F_RSETLK
53	XLAT(F_RSETLK),
54#endif
55#ifdef F_RSETLKW
56	XLAT(F_RSETLKW),
57#endif
58#ifdef F_RGETLK
59	XLAT(F_RGETLK),
60#endif
61#ifdef F_CNVT
62	XLAT(F_CNVT),
63#endif
64#ifdef F_SETSIG
65	XLAT(F_SETSIG),
66#endif
67#ifdef F_GETSIG
68	XLAT(F_GETSIG),
69#endif
70#ifdef F_CHKFL
71	XLAT(F_CHKFL),
72#endif
73#ifdef F_DUP2FD
74	XLAT(F_DUP2FD),
75#endif
76#ifdef F_ALLOCSP
77	XLAT(F_ALLOCSP),
78#endif
79#ifdef F_ISSTREAM
80	XLAT(F_ISSTREAM),
81#endif
82#ifdef F_PRIV
83	XLAT(F_PRIV),
84#endif
85#ifdef F_NPRIV
86	XLAT(F_NPRIV),
87#endif
88#ifdef F_QUOTACL
89	XLAT(F_QUOTACL),
90#endif
91#ifdef F_BLOCKS
92	XLAT(F_BLOCKS),
93#endif
94#ifdef F_BLKSIZE
95	XLAT(F_BLKSIZE),
96#endif
97#ifdef F_GETOWN
98	XLAT(F_GETOWN),
99#endif
100#ifdef F_SETOWN
101	XLAT(F_SETOWN),
102#endif
103#ifdef F_REVOKE
104	XLAT(F_REVOKE),
105#endif
106#ifdef F_SETLK
107	XLAT(F_SETLK),
108#endif
109#ifdef F_SETLKW
110	XLAT(F_SETLKW),
111#endif
112#ifdef F_FREESP
113	XLAT(F_FREESP),
114#endif
115#ifdef F_GETLK
116	XLAT(F_GETLK),
117#endif
118#ifdef F_SETLK64
119	XLAT(F_SETLK64),
120#endif
121#ifdef F_SETLKW64
122	XLAT(F_SETLKW64),
123#endif
124#ifdef F_FREESP64
125	XLAT(F_FREESP64),
126#endif
127#ifdef F_GETLK64
128	XLAT(F_GETLK64),
129#endif
130#ifdef F_SHARE
131	XLAT(F_SHARE),
132#endif
133#ifdef F_UNSHARE
134	XLAT(F_UNSHARE),
135#endif
136#ifdef F_SETLEASE
137	XLAT(F_SETLEASE),
138#endif
139#ifdef F_GETLEASE
140	XLAT(F_GETLEASE),
141#endif
142#ifdef F_NOTIFY
143	XLAT(F_NOTIFY),
144#endif
145#ifdef F_DUPFD_CLOEXEC
146	XLAT(F_DUPFD_CLOEXEC),
147#endif
148	XLAT_END
149};
150
151static const struct xlat fdflags[] = {
152#ifdef FD_CLOEXEC
153	XLAT(FD_CLOEXEC),
154#endif
155	XLAT_END
156};
157
158#ifdef LOCK_SH
159
160static const struct xlat flockcmds[] = {
161	XLAT(LOCK_SH),
162	XLAT(LOCK_EX),
163	XLAT(LOCK_NB),
164	XLAT(LOCK_UN),
165	XLAT_END
166};
167
168#endif /* LOCK_SH */
169
170static const struct xlat lockfcmds[] = {
171	XLAT(F_RDLCK),
172	XLAT(F_WRLCK),
173	XLAT(F_UNLCK),
174#ifdef F_EXLCK
175	XLAT(F_EXLCK),
176#endif
177#ifdef F_SHLCK
178	XLAT(F_SHLCK),
179#endif
180	XLAT_END
181};
182
183#ifdef F_NOTIFY
184static const struct xlat notifyflags[] = {
185#ifdef DN_ACCESS
186	XLAT(DN_ACCESS),
187#endif
188#ifdef DN_MODIFY
189	XLAT(DN_MODIFY),
190#endif
191#ifdef DN_CREATE
192	XLAT(DN_CREATE),
193#endif
194#ifdef DN_DELETE
195	XLAT(DN_DELETE),
196#endif
197#ifdef DN_RENAME
198	XLAT(DN_RENAME),
199#endif
200#ifdef DN_ATTRIB
201	XLAT(DN_ATTRIB),
202#endif
203#ifdef DN_MULTISHOT
204	XLAT(DN_MULTISHOT),
205#endif
206	XLAT_END
207};
208#endif
209
210static const struct xlat perf_event_open_flags[] = {
211#ifdef PERF_FLAG_FD_NO_GROUP
212	XLAT(PERF_FLAG_FD_NO_GROUP),
213#endif
214#ifdef PERF_FLAG_FD_OUTPUT
215	XLAT(PERF_FLAG_FD_OUTPUT),
216#endif
217#ifdef PERF_FLAG_PID_CGROUP
218	XLAT(PERF_FLAG_PID_CGROUP),
219#endif
220	XLAT_END
221};
222
223#if defined(F_SETLK64) && F_SETLK64 + 0 != F_SETLK
224# define HAVE_F_SETLK64 1
225#else
226# define HAVE_F_SETLK64 0
227#endif
228
229#if defined(F_SETLKW64) && F_SETLKW64 + 0 != F_SETLKW
230# define HAVE_F_SETLKW64 1
231#else
232# define HAVE_F_SETLKW64 0
233#endif
234
235#if defined(F_GETLK64) && F_GETLK64+0 != F_GETLK
236# define HAVE_F_GETLK64 1
237#else
238# define HAVE_F_GETLK64 0
239#endif
240
241#if defined(X32) || defined(F_FREESP64) || \
242    HAVE_F_SETLK64 || HAVE_F_SETLKW64 || HAVE_F_GETLK64
243
244#ifndef HAVE_STRUCT_FLOCK64
245struct flock64 {
246	short int l_type, l_whence;
247	int64_t l_start, l_len;
248	int l_pid;
249};
250#endif
251
252/* fcntl/lockf */
253static void
254printflock64(struct tcb *tcp, long addr, int getlk)
255{
256	struct flock64 fl;
257
258	if (umove(tcp, addr, &fl) < 0) {
259		tprints("{...}");
260		return;
261	}
262	tprints("{type=");
263	printxval(lockfcmds, fl.l_type, "F_???");
264	tprints(", whence=");
265	printxval(whence_codes, fl.l_whence, "SEEK_???");
266	tprintf(", start=%lld, len=%lld", (long long) fl.l_start, (long long) fl.l_len);
267	if (getlk)
268		tprintf(", pid=%lu}", (unsigned long) fl.l_pid);
269	else
270		tprints("}");
271}
272#endif
273
274/* fcntl/lockf */
275static void
276printflock(struct tcb *tcp, long addr, int getlk)
277{
278	struct flock fl;
279
280#if SUPPORTED_PERSONALITIES > 1
281# ifdef X32
282	if (current_personality == 0) {
283		printflock64(tcp, addr, getlk);
284		return;
285	}
286# endif
287	if (current_wordsize != sizeof(fl.l_start)) {
288		if (current_wordsize == 4) {
289			/* 32-bit x86 app on x86_64 and similar cases */
290			struct {
291				short int l_type;
292				short int l_whence;
293				int32_t l_start; /* off_t */
294				int32_t l_len; /* off_t */
295				int32_t l_pid; /* pid_t */
296			} fl32;
297			if (umove(tcp, addr, &fl32) < 0) {
298				tprints("{...}");
299				return;
300			}
301			fl.l_type = fl32.l_type;
302			fl.l_whence = fl32.l_whence;
303			fl.l_start = fl32.l_start;
304			fl.l_len = fl32.l_len;
305			fl.l_pid = fl32.l_pid;
306		} else {
307			/* let people know we have a problem here */
308			tprintf("<decode error: unsupported wordsize %d>",
309				current_wordsize);
310			return;
311		}
312	} else
313#endif
314	{
315		if (umove(tcp, addr, &fl) < 0) {
316			tprints("{...}");
317			return;
318		}
319	}
320	tprints("{type=");
321	printxval(lockfcmds, fl.l_type, "F_???");
322	tprints(", whence=");
323	printxval(whence_codes, fl.l_whence, "SEEK_???");
324#ifdef X32
325	tprintf(", start=%lld, len=%lld", fl.l_start, fl.l_len);
326#else
327	tprintf(", start=%ld, len=%ld", fl.l_start, fl.l_len);
328#endif
329	if (getlk)
330		tprintf(", pid=%lu}", (unsigned long) fl.l_pid);
331	else
332		tprints("}");
333}
334
335int
336sys_fcntl(struct tcb *tcp)
337{
338	if (entering(tcp)) {
339		printfd(tcp, tcp->u_arg[0]);
340		tprints(", ");
341		printxval(fcntlcmds, tcp->u_arg[1], "F_???");
342		switch (tcp->u_arg[1]) {
343		case F_SETFD:
344			tprints(", ");
345			printflags(fdflags, tcp->u_arg[2], "FD_???");
346			break;
347		case F_SETOWN: case F_DUPFD:
348#ifdef F_DUPFD_CLOEXEC
349		case F_DUPFD_CLOEXEC:
350#endif
351			tprintf(", %ld", tcp->u_arg[2]);
352			break;
353		case F_SETFL:
354			tprints(", ");
355			tprint_open_modes(tcp->u_arg[2]);
356			break;
357		case F_SETLK: case F_SETLKW:
358#ifdef F_FREESP
359		case F_FREESP:
360#endif
361			tprints(", ");
362			printflock(tcp, tcp->u_arg[2], 0);
363			break;
364#if defined(F_FREESP64) || HAVE_F_SETLK64 || HAVE_F_SETLKW64
365#ifdef F_FREESP64
366		case F_FREESP64:
367#endif
368		/* Linux glibc defines SETLK64 as SETLK,
369		   even though the kernel has different values - as does Solaris. */
370#if HAVE_F_SETLK64
371		case F_SETLK64:
372#endif
373#if HAVE_F_SETLKW64
374		case F_SETLKW64:
375#endif
376			tprints(", ");
377			printflock64(tcp, tcp->u_arg[2], 0);
378			break;
379#endif /* defined(F_FREESP64) || HAVE_F_SETLK64 || HAVE_F_SETLKW64 */
380#ifdef F_NOTIFY
381		case F_NOTIFY:
382			tprints(", ");
383			printflags(notifyflags, tcp->u_arg[2], "DN_???");
384			break;
385#endif
386#ifdef F_SETLEASE
387		case F_SETLEASE:
388			tprints(", ");
389			printxval(lockfcmds, tcp->u_arg[2], "F_???");
390			break;
391#endif
392		}
393	}
394	else {
395		switch (tcp->u_arg[1]) {
396		case F_DUPFD:
397#ifdef F_DUPFD_CLOEXEC
398		case F_DUPFD_CLOEXEC:
399#endif
400		case F_SETFD: case F_SETFL:
401		case F_SETLK: case F_SETLKW:
402		case F_SETOWN: case F_GETOWN:
403#ifdef F_NOTIFY
404		case F_NOTIFY:
405#endif
406#ifdef F_SETLEASE
407		case F_SETLEASE:
408#endif
409			break;
410		case F_GETFD:
411			if (syserror(tcp) || tcp->u_rval == 0)
412				return 0;
413			tcp->auxstr = sprintflags("flags ", fdflags, tcp->u_rval);
414			return RVAL_HEX|RVAL_STR;
415		case F_GETFL:
416			if (syserror(tcp))
417				return 0;
418			tcp->auxstr = sprint_open_modes(tcp->u_rval);
419			return RVAL_HEX|RVAL_STR;
420		case F_GETLK:
421			tprints(", ");
422			printflock(tcp, tcp->u_arg[2], 1);
423			break;
424#if HAVE_F_GETLK64
425		case F_GETLK64:
426			tprints(", ");
427			printflock64(tcp, tcp->u_arg[2], 1);
428			break;
429#endif
430#ifdef F_GETLEASE
431		case F_GETLEASE:
432			if (syserror(tcp))
433				return 0;
434			tcp->auxstr = xlookup(lockfcmds, tcp->u_rval);
435			return RVAL_HEX|RVAL_STR;
436#endif
437		default:
438			tprintf(", %#lx", tcp->u_arg[2]);
439			break;
440		}
441	}
442	return 0;
443}
444
445#ifdef LOCK_SH
446
447int
448sys_flock(struct tcb *tcp)
449{
450	if (entering(tcp)) {
451		printfd(tcp, tcp->u_arg[0]);
452		tprints(", ");
453		printflags(flockcmds, tcp->u_arg[1], "LOCK_???");
454	}
455	return 0;
456}
457#endif /* LOCK_SH */
458
459int
460sys_close(struct tcb *tcp)
461{
462	if (entering(tcp)) {
463		printfd(tcp, tcp->u_arg[0]);
464	}
465	return 0;
466}
467
468static int
469do_dup2(struct tcb *tcp, int flags_arg)
470{
471	if (entering(tcp)) {
472		printfd(tcp, tcp->u_arg[0]);
473		tprints(", ");
474		printfd(tcp, tcp->u_arg[1]);
475		if (flags_arg >= 0) {
476			tprints(", ");
477			printflags(open_mode_flags, tcp->u_arg[flags_arg], "O_???");
478		}
479	}
480	return 0;
481}
482
483int
484sys_dup2(struct tcb *tcp)
485{
486	return do_dup2(tcp, -1);
487}
488
489int
490sys_dup3(struct tcb *tcp)
491{
492	return do_dup2(tcp, 2);
493}
494
495#if defined(ALPHA)
496int
497sys_getdtablesize(struct tcb *tcp)
498{
499	return 0;
500}
501#endif
502
503static int
504decode_select(struct tcb *tcp, long *args, enum bitness_t bitness)
505{
506	int i, j;
507	int nfds, fdsize;
508	fd_set *fds;
509	const char *sep;
510	long arg;
511
512	/* Kernel truncates arg[0] to int, we do the same. */
513	nfds = (int) args[0];
514
515	/* Kernel rejects negative nfds, so we don't parse it either. */
516	if (nfds < 0) {
517		nfds = 0;
518		fds = NULL;
519	}
520	/* Beware of select(2^31-1, NULL, NULL, NULL) and similar... */
521	if (nfds > 1024*1024)
522		nfds = 1024*1024;
523
524	/*
525	 * We had bugs a-la "while (j < args[0])" and "umoven(args[0])" below.
526	 * Instead of args[0], use nfds for fd count, fdsize for array lengths.
527	 */
528	fdsize = (((nfds + 7) / 8) + current_wordsize-1) & -current_wordsize;
529
530	if (entering(tcp)) {
531		tprintf("%d", (int) args[0]);
532
533		if (fdsize > 0) {
534			fds = malloc(fdsize);
535			if (!fds)
536				die_out_of_memory();
537		}
538		for (i = 0; i < 3; i++) {
539			arg = args[i+1];
540			if (arg == 0) {
541				tprints(", NULL");
542				continue;
543			}
544			if (!verbose(tcp) || !fds) {
545				tprintf(", %#lx", arg);
546				continue;
547			}
548			if (umoven(tcp, arg, fdsize, (char *) fds) < 0) {
549				tprints(", [?]");
550				continue;
551			}
552			tprints(", [");
553			for (j = 0, sep = "";; j++) {
554				j = next_set_bit(fds, j, nfds);
555				if (j < 0)
556					break;
557				tprints(sep);
558				printfd(tcp, j);
559				sep = " ";
560			}
561			tprints("]");
562		}
563		free(fds);
564		tprints(", ");
565		printtv_bitness(tcp, args[4], bitness, 0);
566	}
567	else {
568		static char outstr[1024];
569		char *outptr;
570#define end_outstr (outstr + sizeof(outstr))
571		int ready_fds;
572
573		if (syserror(tcp))
574			return 0;
575
576		ready_fds = tcp->u_rval;
577		if (ready_fds == 0) {
578			tcp->auxstr = "Timeout";
579			return RVAL_STR;
580		}
581
582		fds = malloc(fdsize);
583		if (!fds)
584			die_out_of_memory();
585
586		outptr = outstr;
587		sep = "";
588		for (i = 0; i < 3 && ready_fds > 0; i++) {
589			int first = 1;
590
591			arg = args[i+1];
592			if (!arg || umoven(tcp, arg, fdsize, (char *) fds) < 0)
593				continue;
594			for (j = 0;; j++) {
595				j = next_set_bit(fds, j, nfds);
596				if (j < 0)
597					break;
598				/* +2 chars needed at the end: ']',NUL */
599				if (outptr < end_outstr - (sizeof(", except [") + sizeof(int)*3 + 2)) {
600					if (first) {
601						outptr += sprintf(outptr, "%s%s [%u",
602							sep,
603							i == 0 ? "in" : i == 1 ? "out" : "except",
604							j
605						);
606						first = 0;
607						sep = ", ";
608					}
609					else {
610						outptr += sprintf(outptr, " %u", j);
611					}
612				}
613				if (--ready_fds == 0)
614					break;
615			}
616			if (outptr != outstr)
617				*outptr++ = ']';
618		}
619		free(fds);
620		/* This contains no useful information on SunOS.  */
621		if (args[4]) {
622			if (outptr < end_outstr - (10 + TIMEVAL_TEXT_BUFSIZE)) {
623				outptr += sprintf(outptr, "%sleft ", sep);
624				outptr = sprinttv(outptr, tcp, args[4], bitness, /*special:*/ 0);
625			}
626		}
627		*outptr = '\0';
628		tcp->auxstr = outstr;
629		return RVAL_STR;
630#undef end_outstr
631	}
632	return 0;
633}
634
635int
636sys_oldselect(struct tcb *tcp)
637{
638	long args[5];
639
640	if (umoven(tcp, tcp->u_arg[0], sizeof args, (char *) args) < 0) {
641		tprints("[...]");
642		return 0;
643	}
644	return decode_select(tcp, args, BITNESS_CURRENT);
645}
646
647#ifdef ALPHA
648int
649sys_osf_select(struct tcb *tcp)
650{
651	long *args = tcp->u_arg;
652	return decode_select(tcp, args, BITNESS_32);
653}
654#endif
655
656static const struct xlat epollctls[] = {
657#ifdef EPOLL_CTL_ADD
658	XLAT(EPOLL_CTL_ADD),
659#endif
660#ifdef EPOLL_CTL_MOD
661	XLAT(EPOLL_CTL_MOD),
662#endif
663#ifdef EPOLL_CTL_DEL
664	XLAT(EPOLL_CTL_DEL),
665#endif
666	XLAT_END
667};
668
669static const struct xlat epollevents[] = {
670#ifdef EPOLLIN
671	XLAT(EPOLLIN),
672#endif
673#ifdef EPOLLPRI
674	XLAT(EPOLLPRI),
675#endif
676#ifdef EPOLLOUT
677	XLAT(EPOLLOUT),
678#endif
679#ifdef EPOLLRDNORM
680	XLAT(EPOLLRDNORM),
681#endif
682#ifdef EPOLLRDBAND
683	XLAT(EPOLLRDBAND),
684#endif
685#ifdef EPOLLWRNORM
686	XLAT(EPOLLWRNORM),
687#endif
688#ifdef EPOLLWRBAND
689	XLAT(EPOLLWRBAND),
690#endif
691#ifdef EPOLLMSG
692	XLAT(EPOLLMSG),
693#endif
694#ifdef EPOLLERR
695	XLAT(EPOLLERR),
696#endif
697#ifdef EPOLLHUP
698	XLAT(EPOLLHUP),
699#endif
700#ifdef EPOLLRDHUP
701	XLAT(EPOLLRDHUP),
702#endif
703#ifdef EPOLLONESHOT
704	XLAT(EPOLLONESHOT),
705#endif
706#ifdef EPOLLET
707	XLAT(EPOLLET),
708#endif
709	XLAT_END
710};
711
712/* Not aliased to printargs_ld: we want it to have a distinct address */
713int
714sys_epoll_create(struct tcb *tcp)
715{
716	return printargs_ld(tcp);
717}
718
719static const struct xlat epollflags[] = {
720#ifdef EPOLL_CLOEXEC
721	XLAT(EPOLL_CLOEXEC),
722#endif
723#ifdef EPOLL_NONBLOCK
724	XLAT(EPOLL_NONBLOCK),
725#endif
726	XLAT_END
727};
728
729int
730sys_epoll_create1(struct tcb *tcp)
731{
732	if (entering(tcp))
733		printflags(epollflags, tcp->u_arg[0], "EPOLL_???");
734	return 0;
735}
736
737#ifdef HAVE_SYS_EPOLL_H
738static void
739print_epoll_event(struct epoll_event *ev)
740{
741	tprints("{");
742	printflags(epollevents, ev->events, "EPOLL???");
743	/* We cannot know what format the program uses, so print u32 and u64
744	   which will cover every value.  */
745	tprintf(", {u32=%" PRIu32 ", u64=%" PRIu64 "}}",
746		ev->data.u32, ev->data.u64);
747}
748#endif
749
750int
751sys_epoll_ctl(struct tcb *tcp)
752{
753	if (entering(tcp)) {
754		printfd(tcp, tcp->u_arg[0]);
755		tprints(", ");
756		printxval(epollctls, tcp->u_arg[1], "EPOLL_CTL_???");
757		tprints(", ");
758		printfd(tcp, tcp->u_arg[2]);
759		tprints(", ");
760		if (tcp->u_arg[3] == 0)
761			tprints("NULL");
762		else {
763#ifdef HAVE_SYS_EPOLL_H
764			struct epoll_event ev;
765			if (umove(tcp, tcp->u_arg[3], &ev) == 0)
766				print_epoll_event(&ev);
767			else
768#endif
769				tprints("{...}");
770		}
771	}
772	return 0;
773}
774
775static void
776epoll_wait_common(struct tcb *tcp)
777{
778	if (entering(tcp)) {
779		printfd(tcp, tcp->u_arg[0]);
780		tprints(", ");
781	} else {
782		if (syserror(tcp))
783			tprintf("%lx", tcp->u_arg[1]);
784		else if (tcp->u_rval == 0)
785			tprints("{}");
786		else {
787#ifdef HAVE_SYS_EPOLL_H
788			struct epoll_event ev, *start, *cur, *end;
789			int failed = 0;
790
791			tprints("{");
792			start = (struct epoll_event *) tcp->u_arg[1];
793			end = start + tcp->u_rval;
794			for (cur = start; cur < end; ++cur) {
795				if (cur > start)
796					tprints(", ");
797				if (umove(tcp, (long) cur, &ev) == 0)
798					print_epoll_event(&ev);
799				else {
800					tprints("?");
801					failed = 1;
802					break;
803				}
804			}
805			tprints("}");
806			if (failed)
807				tprintf(" %#lx", (long) start);
808#else
809			tprints("{...}");
810#endif
811		}
812		tprintf(", %d, %d", (int) tcp->u_arg[2], (int) tcp->u_arg[3]);
813	}
814}
815
816int
817sys_epoll_wait(struct tcb *tcp)
818{
819	epoll_wait_common(tcp);
820	return 0;
821}
822
823int
824sys_epoll_pwait(struct tcb *tcp)
825{
826	epoll_wait_common(tcp);
827	if (exiting(tcp)) {
828		tprints(", ");
829		/* NB: kernel requires arg[5] == NSIG / 8 */
830		print_sigset_addr_len(tcp, tcp->u_arg[4], tcp->u_arg[5]);
831		tprintf(", %lu", tcp->u_arg[5]);
832	}
833	return 0;
834}
835
836int
837sys_select(struct tcb *tcp)
838{
839	return decode_select(tcp, tcp->u_arg, BITNESS_CURRENT);
840}
841
842int
843sys_pselect6(struct tcb *tcp)
844{
845	int rc = decode_select(tcp, tcp->u_arg, BITNESS_CURRENT);
846	if (entering(tcp)) {
847		long r;
848		struct {
849			unsigned long ptr;
850			unsigned long len;
851		} data;
852#if SUPPORTED_PERSONALITIES > 1 && SIZEOF_LONG > 4
853		if (current_wordsize == 4) {
854			struct {
855				uint32_t ptr;
856				uint32_t len;
857			} data32;
858			r = umove(tcp, tcp->u_arg[5], &data32);
859			data.ptr = data32.ptr;
860			data.len = data32.len;
861		} else
862#endif
863			r = umove(tcp, tcp->u_arg[5], &data);
864		if (r < 0)
865			tprintf(", %#lx", tcp->u_arg[5]);
866		else {
867			tprints(", {");
868			/* NB: kernel requires data.len == NSIG / 8 */
869			print_sigset_addr_len(tcp, data.ptr, data.len);
870			tprintf(", %lu}", data.len);
871		}
872	}
873	return rc;
874}
875
876static int
877do_eventfd(struct tcb *tcp, int flags_arg)
878{
879	if (entering(tcp)) {
880		tprintf("%lu", tcp->u_arg[0]);
881		if (flags_arg >= 0) {
882			tprints(", ");
883			printflags(open_mode_flags, tcp->u_arg[flags_arg], "O_???");
884		}
885	}
886	return 0;
887}
888
889int
890sys_eventfd(struct tcb *tcp)
891{
892	return do_eventfd(tcp, -1);
893}
894
895int
896sys_eventfd2(struct tcb *tcp)
897{
898	return do_eventfd(tcp, 1);
899}
900
901int
902sys_perf_event_open(struct tcb *tcp)
903{
904	if (entering(tcp)) {
905		tprintf("%#lx, %d, %d, %d, ",
906			tcp->u_arg[0],
907			(int) tcp->u_arg[1],
908			(int) tcp->u_arg[2],
909			(int) tcp->u_arg[3]);
910		printflags(perf_event_open_flags, tcp->u_arg[4],
911			   "PERF_FLAG_???");
912	}
913	return 0;
914}
915