1 /*
2  * Copyright (c) 1993, 1994, 1995, 1996 Rick Sladkey <jrs@world.std.com>
3  * Copyright (c) 1996-1999 Wichert Akkerman <wichert@cistron.nl>
4  * All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  * 1. Redistributions of source code must retain the above copyright
10  *    notice, this list of conditions and the following disclaimer.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  *    notice, this list of conditions and the following disclaimer in the
13  *    documentation and/or other materials provided with the distribution.
14  * 3. The name of the author may not be used to endorse or promote products
15  *    derived from this software without specific prior written permission.
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27  */
28 
29 #include "defs.h"
30 #include <poll.h>
31 
32 #include "xlat/pollflags.h"
33 
34 static void
print_pollfd(struct tcb * tcp,const struct pollfd * fds)35 print_pollfd(struct tcb *tcp, const struct pollfd *fds)
36 {
37 	tprints("{fd=");
38 	printfd(tcp, fds->fd);
39 	if (fds->fd >= 0) {
40 		tprints(", events=");
41 		printflags(pollflags, fds->events, "POLL???");
42 	}
43 	tprints("}");
44 }
45 
46 static int
decode_poll_entering(struct tcb * tcp)47 decode_poll_entering(struct tcb *tcp)
48 {
49 	struct pollfd fds;
50 	const unsigned int nfds = tcp->u_arg[1];
51 	const unsigned long size = sizeof(fds) * nfds;
52 	const unsigned long start = tcp->u_arg[0];
53 	const unsigned long end = start + size;
54 	unsigned long cur, abbrev_end;
55 
56 	if (!verbose(tcp) || !start || !nfds ||
57 	    size / sizeof(fds) != nfds || end < start) {
58 		printaddr(start);
59 		tprintf(", %u, ", nfds);
60 		return 0;
61 	}
62 
63 	if (abbrev(tcp)) {
64 		abbrev_end = start + max_strlen * sizeof(fds);
65 		if (abbrev_end < start)
66 			abbrev_end = end;
67 	} else {
68 		abbrev_end = end;
69 	}
70 
71 	if (start >= abbrev_end || umove(tcp, start, &fds) < 0) {
72 		printaddr(start);
73 		tprintf(", %u, ", nfds);
74 		return 0;
75 	}
76 
77 	tprints("[");
78 	print_pollfd(tcp, &fds);
79 	for (cur = start + sizeof(fds); cur < end; cur += sizeof(fds)) {
80 		tprints(", ");
81 		if (cur >= abbrev_end) {
82 			tprints("...");
83 			break;
84 		}
85 		if (umove(tcp, cur, &fds) < 0) {
86 			tprints("???");
87 			break;
88 		}
89 		print_pollfd(tcp, &fds);
90 
91 	}
92 	tprintf("], %u, ", nfds);
93 
94 	return 0;
95 }
96 
97 static int
decode_poll_exiting(struct tcb * tcp,const long pts)98 decode_poll_exiting(struct tcb *tcp, const long pts)
99 {
100 	struct pollfd fds;
101 	const unsigned int nfds = tcp->u_arg[1];
102 	const unsigned long size = sizeof(fds) * nfds;
103 	const unsigned long start = tcp->u_arg[0];
104 	const unsigned long end = start + size;
105 	unsigned long cur, abbrev_end;
106 
107 	static char outstr[1024];
108 	char *outptr;
109 #define end_outstr (outstr + sizeof(outstr))
110 
111 	if (syserror(tcp))
112 		return 0;
113 	if (tcp->u_rval == 0) {
114 		tcp->auxstr = "Timeout";
115 		return RVAL_STR;
116 	}
117 
118 	if (!verbose(tcp) || !start || !nfds ||
119 	    size / sizeof(fds) != nfds || end < start)
120 		return 0;
121 	if (abbrev(tcp)) {
122 		abbrev_end = start + max_strlen * sizeof(fds);
123 		if (abbrev_end < start)
124 			abbrev_end = end;
125 	} else {
126 		abbrev_end = end;
127 	}
128 
129 	outptr = outstr;
130 
131 	for (cur = start; cur < end; cur += sizeof(fds)) {
132 		if (umove(tcp, cur, &fds) < 0) {
133 			if (outptr == outstr)
134 				*outptr++ = '[';
135 			else
136 				outptr = stpcpy(outptr, ", ");
137 			outptr = stpcpy(outptr, "???");
138 			break;
139 		}
140 		if (!fds.revents)
141 			continue;
142 		if (outptr == outstr)
143 			*outptr++ = '[';
144 		else
145 			outptr = stpcpy(outptr, ", ");
146 		if (cur >= abbrev_end) {
147 			outptr = stpcpy(outptr, "...");
148 			break;
149 		}
150 
151 		static const char fmt[] = "{fd=%d, revents=";
152 		char fdstr[sizeof(fmt) + sizeof(int) * 3];
153 		sprintf(fdstr, fmt, fds.fd);
154 
155 		const char *flagstr = sprintflags("", pollflags, fds.revents);
156 
157 		if (outptr + strlen(fdstr) + strlen(flagstr) + 1
158 		    >= end_outstr - sizeof(", ...], ...")) {
159 			outptr = stpcpy(outptr, "...");
160 			break;
161 		}
162 		outptr = stpcpy(outptr, fdstr);
163 		outptr = stpcpy(outptr, flagstr);
164 		*outptr++ = '}';
165 	}
166 
167 	if (outptr != outstr)
168 		*outptr++ = ']';
169 
170 	*outptr = '\0';
171 	if (pts) {
172 		const char *str = sprint_timespec(tcp, pts);
173 
174 		if (outptr + sizeof(", left ") + strlen(str) < end_outstr) {
175 			outptr = stpcpy(outptr, outptr == outstr ? "left " : ", left ");
176 			outptr = stpcpy(outptr, str);
177 		} else {
178 			outptr = stpcpy(outptr, ", ...");
179 		}
180 	}
181 
182 	if (outptr == outstr)
183 		return 0;
184 
185 	tcp->auxstr = outstr;
186 	return RVAL_STR;
187 #undef end_outstr
188 }
189 
SYS_FUNC(poll)190 SYS_FUNC(poll)
191 {
192 	if (entering(tcp)) {
193 		int rc = decode_poll_entering(tcp);
194 
195 #ifdef INFTIM
196 		if (INFTIM == (int) tcp->u_arg[2])
197 			tprints("INFTIM");
198 		else
199 #endif
200 			tprintf("%d", (int) tcp->u_arg[2]);
201 
202 		return rc;
203 	} else {
204 		return decode_poll_exiting(tcp, 0);
205 	}
206 }
207 
SYS_FUNC(ppoll)208 SYS_FUNC(ppoll)
209 {
210 	if (entering(tcp)) {
211 		int rc = decode_poll_entering(tcp);
212 
213 		print_timespec(tcp, tcp->u_arg[2]);
214 		tprints(", ");
215 		/* NB: kernel requires arg[4] == NSIG / 8 */
216 		print_sigset_addr_len(tcp, tcp->u_arg[3], tcp->u_arg[4]);
217 		tprintf(", %lu", tcp->u_arg[4]);
218 
219 		return rc;
220 	} else {
221 		return decode_poll_exiting(tcp, tcp->u_arg[2]);
222 	}
223 }
224