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 * Copyright (c) 1999-2021 The strace developers.
5 * All rights reserved.
6 *
7 * SPDX-License-Identifier: LGPL-2.1-or-later
8 */
9
10 #include "defs.h"
11 #include <poll.h>
12 #include "xstring.h"
13
14 #include "xlat/pollflags.h"
15
16 static bool
17 print_pollfd(struct tcb *tcp, void *elem_buf, size_t elem_size, void *data)
18 {
19 const struct pollfd *fds = elem_buf;
20
21 tprint_struct_begin();
22 PRINT_FIELD_FD(*fds, fd, tcp);
23 if (fds->fd >= 0) {
24 tprint_struct_next();
25 PRINT_FIELD_FLAGS(*fds, events, pollflags, "POLL???");
26 }
27 tprint_struct_end();
28
29 return true;
30 }
31
32 static void
33 decode_poll_entering(struct tcb *tcp)
34 {
35 const kernel_ulong_t addr = tcp->u_arg[0];
36 const unsigned int nfds = tcp->u_arg[1];
37 struct pollfd fds;
38
39 /* fds */
40 print_array(tcp, addr, nfds, &fds, sizeof(fds),
41 tfetch_mem, print_pollfd, 0);
42 tprint_arg_next();
43
44 /* nfds */
45 PRINT_VAL_U(nfds);
46 tprint_arg_next();
47 }
48
49 static int
50 decode_poll_exiting(struct tcb *const tcp, const sprint_obj_by_addr_fn sprint_ts,
51 const kernel_ulong_t pts)
52 {
53 struct pollfd fds;
54 const unsigned int nfds = tcp->u_arg[1];
55 const unsigned long size = sizeof(fds) * nfds;
56 const kernel_ulong_t start = tcp->u_arg[0];
57 const kernel_ulong_t end = start + size;
58 const unsigned int max_printed =
59 abbrev(tcp) ? max_strlen : -1U;
60 unsigned int printed = 0;
61
62 static char outstr[1024];
63 char *outptr;
64 #define end_outstr (outstr + sizeof(outstr))
65
66 if (syserror(tcp))
67 return 0;
68 if (tcp->u_rval == 0) {
69 tcp->auxstr = "Timeout";
70 return RVAL_STR;
71 }
72
73 if (!verbose(tcp) || !start || !nfds ||
74 size / sizeof(fds) != nfds || end < start)
75 return 0;
76
77 outptr = outstr;
78
79 for (kernel_ulong_t cur = start; cur < end; cur += sizeof(fds)) {
80 if (umove(tcp, cur, &fds) < 0) {
81 if (outptr == outstr)
82 *outptr++ = '[';
83 else
84 outptr = stpcpy(outptr, ", ");
85 outptr = xappendstr(outstr, outptr, "%#" PRI_klx, cur);
86 break;
87 }
88 if (!fds.revents)
89 continue;
90 if (outptr == outstr)
91 *outptr++ = '[';
92 else
93 outptr = stpcpy(outptr, ", ");
94 if (printed >= max_printed) {
95 outptr = stpcpy(outptr, "...");
96 break;
97 }
98
99 static const char fmt[] = "{fd=%d, revents=";
100 char fdstr[sizeof(fmt) + sizeof(int) * 3];
101 xsprintf(fdstr, fmt, fds.fd);
102
103 const char *flagstr = sprintflags("", pollflags,
104 (unsigned short) fds.revents);
105
106 if (outptr + strlen(fdstr) + strlen(flagstr) + 1 >=
107 end_outstr - (2 + 2 * sizeof(long) + sizeof(", ], ..."))) {
108 outptr = stpcpy(outptr, "...");
109 break;
110 }
111 outptr = stpcpy(outptr, fdstr);
112 outptr = stpcpy(outptr, flagstr);
113 *outptr++ = '}';
114 ++printed;
115 }
116
117 if (outptr != outstr)
118 *outptr++ = ']';
119
120 *outptr = '\0';
121 if (pts) {
122 const char *str = sprint_ts(tcp, pts);
123
124 if (outptr + sizeof(", left ") + strlen(str) < end_outstr) {
125 outptr = stpcpy(outptr, outptr == outstr ? "left " : ", left ");
126 outptr = stpcpy(outptr, str);
127 } else {
128 outptr = stpcpy(outptr, ", ...");
129 }
130 }
131
132 if (outptr == outstr)
133 return 0;
134
135 tcp->auxstr = outstr;
136 return RVAL_STR;
137 #undef end_outstr
138 }
139
140 #if HAVE_ARCH_TIME32_SYSCALLS || HAVE_ARCH_OLD_TIME64_SYSCALLS
141 static int
142 do_poll(struct tcb *const tcp, const sprint_obj_by_addr_fn sprint_ts)
143 {
144 if (entering(tcp)) {
145 decode_poll_entering(tcp);
146
147 /* timeout */
148 PRINT_VAL_D((int) tcp->u_arg[2]);
149
150 return 0;
151 } else {
152 return decode_poll_exiting(tcp, sprint_ts, 0);
153 }
154 }
155 #endif /* HAVE_ARCH_TIME32_SYSCALLS || HAVE_ARCH_OLD_TIME64_SYSCALLS */
156
157 #if HAVE_ARCH_TIME32_SYSCALLS
158 SYS_FUNC(poll_time32)
159 {
160 return do_poll(tcp, sprint_timespec32);
161 }
162 #endif
163
164 #if HAVE_ARCH_OLD_TIME64_SYSCALLS
165 SYS_FUNC(poll_time64)
166 {
167 return do_poll(tcp, sprint_timespec64);
168 }
169 #endif
170
171 static int
172 do_ppoll(struct tcb *const tcp, const print_obj_by_addr_fn print_ts,
173 const sprint_obj_by_addr_fn sprint_ts)
174 {
175 if (entering(tcp)) {
176 decode_poll_entering(tcp);
177
178 /* tmo_p */
179 print_ts(tcp, tcp->u_arg[2]);
180 tprint_arg_next();
181
182 /* sigmask */
183 /* NB: kernel requires arg[4] == NSIG_BYTES */
184 print_sigset_addr_len(tcp, tcp->u_arg[3], tcp->u_arg[4]);
185 tprint_arg_next();
186
187 /* sigsetsize */
188 PRINT_VAL_U(tcp->u_arg[4]);
189
190 return 0;
191 } else {
192 return decode_poll_exiting(tcp, sprint_ts, tcp->u_arg[2]);
193 }
194 }
195
196 #if HAVE_ARCH_TIME32_SYSCALLS
197 SYS_FUNC(ppoll_time32)
198 {
199 return do_ppoll(tcp, print_timespec32, sprint_timespec32);
200 }
201 #endif
202
203 SYS_FUNC(ppoll_time64)
204 {
205 return do_ppoll(tcp, print_timespec64, sprint_timespec64);
206 }