]> granicus.if.org Git - strace/blob - stream.c
tests: add a test for pread/pwrite and preadv/pwritev offset decoding
[strace] / stream.c
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 #if defined HAVE_POLL_H
31 # include <poll.h>
32 #elif defined HAVE_SYS_POLL_H
33 # include <sys/poll.h>
34 #endif
35 #ifdef HAVE_SYS_CONF_H
36 # include <sys/conf.h>
37 #endif
38
39 /* Who has STREAMS syscalls?
40  * Linux hasn't. Solaris has (had?).
41  * Just in case I miss something, retain in for Sparc...
42  */
43 #if defined(SPARC) || defined(SPARC64)
44
45 # ifdef HAVE_STROPTS_H
46 #  include <stropts.h>
47 # else
48 #  define RS_HIPRI 1
49 struct strbuf {
50         int     maxlen;                 /* no. of bytes in buffer */
51         int     len;                    /* no. of bytes returned */
52         const char *buf;                /* pointer to data */
53 };
54 #  define MORECTL 1
55 #  define MOREDATA 2
56 # endif
57
58 static const struct xlat msgflags[] = {
59         XLAT(RS_HIPRI),
60         XLAT_END
61 };
62
63 static void
64 printstrbuf(struct tcb *tcp, struct strbuf *sbp, int getting)
65 {
66         if (sbp->maxlen == -1 && getting)
67                 tprints("{maxlen=-1}");
68         else {
69                 tprints("{");
70                 if (getting)
71                         tprintf("maxlen=%d, ", sbp->maxlen);
72                 tprintf("len=%d, buf=", sbp->len);
73                 printstr(tcp, (unsigned long) sbp->buf, sbp->len);
74                 tprints("}");
75         }
76 }
77
78 static void
79 printstrbufarg(struct tcb *tcp, long arg, int getting)
80 {
81         struct strbuf buf;
82
83         if (arg == 0)
84                 tprints("NULL");
85         else if (umove(tcp, arg, &buf) < 0)
86                 tprints("{...}");
87         else
88                 printstrbuf(tcp, &buf, getting);
89         tprints(", ");
90 }
91
92 int
93 sys_putmsg(struct tcb *tcp)
94 {
95         int i;
96
97         if (entering(tcp)) {
98                 /* fd */
99                 tprintf("%ld, ", tcp->u_arg[0]);
100                 /* control and data */
101                 for (i = 1; i < 3; i++)
102                         printstrbufarg(tcp, tcp->u_arg[i], 0);
103                 /* flags */
104                 printflags(msgflags, tcp->u_arg[3], "RS_???");
105         }
106         return 0;
107 }
108
109 int
110 sys_getmsg(struct tcb *tcp)
111 {
112         int i, flags;
113
114         if (entering(tcp)) {
115                 /* fd */
116                 tprintf("%lu, ", tcp->u_arg[0]);
117         } else {
118                 if (syserror(tcp)) {
119                         tprintf("%#lx, %#lx, %#lx",
120                                 tcp->u_arg[1], tcp->u_arg[2], tcp->u_arg[3]);
121                         return 0;
122                 }
123                 /* control and data */
124                 for (i = 1; i < 3; i++)
125                         printstrbufarg(tcp, tcp->u_arg[i], 1);
126                 /* pointer to flags */
127                 if (tcp->u_arg[3] == 0)
128                         tprints("NULL");
129                 else if (umove(tcp, tcp->u_arg[3], &flags) < 0)
130                         tprints("[?]");
131                 else {
132                         tprints("[");
133                         printflags(msgflags, flags, "RS_???");
134                         tprints("]");
135                 }
136                 /* decode return value */
137                 switch (tcp->u_rval) {
138                 case MORECTL:
139                         tcp->auxstr = "MORECTL";
140                         break;
141                 case MORECTL|MOREDATA:
142                         tcp->auxstr = "MORECTL|MOREDATA";
143                         break;
144                 case MOREDATA:
145                         tcp->auxstr = "MORECTL";
146                         break;
147                 default:
148                         tcp->auxstr = NULL;
149                         break;
150                 }
151         }
152         return RVAL_HEX | RVAL_STR;
153 }
154
155 # if defined SYS_putpmsg || defined SYS_getpmsg
156 static const struct xlat pmsgflags[] = {
157 #  ifdef MSG_HIPRI
158         XLAT(MSG_HIPRI),
159 #  endif
160 #  ifdef MSG_AND
161         XLAT(MSG_ANY),
162 #  endif
163 #  ifdef MSG_BAND
164         XLAT(MSG_BAND),
165 #  endif
166         XLAT_END
167 };
168 #  ifdef SYS_putpmsg
169 int
170 sys_putpmsg(struct tcb *tcp)
171 {
172         int i;
173
174         if (entering(tcp)) {
175                 /* fd */
176                 tprintf("%ld, ", tcp->u_arg[0]);
177                 /* control and data */
178                 for (i = 1; i < 3; i++)
179                         printstrbufarg(tcp, tcp->u_arg[i], 0);
180                 /* band */
181                 tprintf("%ld, ", tcp->u_arg[3]);
182                 /* flags */
183                 printflags(pmsgflags, tcp->u_arg[4], "MSG_???");
184         }
185         return 0;
186 }
187 #  endif
188 #  ifdef SYS_getpmsg
189 int
190 sys_getpmsg(struct tcb *tcp)
191 {
192         int i, flags;
193
194         if (entering(tcp)) {
195                 /* fd */
196                 tprintf("%lu, ", tcp->u_arg[0]);
197         } else {
198                 if (syserror(tcp)) {
199                         tprintf("%#lx, %#lx, %#lx, %#lx", tcp->u_arg[1],
200                                 tcp->u_arg[2], tcp->u_arg[3], tcp->u_arg[4]);
201                         return 0;
202                 }
203                 /* control and data */
204                 for (i = 1; i < 3; i++)
205                         printstrbufarg(tcp, tcp->u_arg[i], 1);
206                 /* pointer to band */
207                 printnum(tcp, tcp->u_arg[3], "%d");
208                 tprints(", ");
209                 /* pointer to flags */
210                 if (tcp->u_arg[4] == 0)
211                         tprints("NULL");
212                 else if (umove(tcp, tcp->u_arg[4], &flags) < 0)
213                         tprints("[?]");
214                 else {
215                         tprints("[");
216                         printflags(pmsgflags, flags, "MSG_???");
217                         tprints("]");
218                 }
219                 /* decode return value */
220                 switch (tcp->u_rval) {
221                 case MORECTL:
222                         tcp->auxstr = "MORECTL";
223                         break;
224                 case MORECTL|MOREDATA:
225                         tcp->auxstr = "MORECTL|MOREDATA";
226                         break;
227                 case MOREDATA:
228                         tcp->auxstr = "MORECTL";
229                         break;
230                 default:
231                         tcp->auxstr = NULL;
232                         break;
233                 }
234         }
235         return RVAL_HEX | RVAL_STR;
236 }
237 #  endif
238 # endif /* getpmsg/putpmsg */
239
240 #endif /* STREAMS syscalls support */
241
242
243 #ifdef HAVE_SYS_POLL_H
244
245 static const struct xlat pollflags[] = {
246 # ifdef POLLIN
247         XLAT(POLLIN),
248         XLAT(POLLPRI),
249         XLAT(POLLOUT),
250 #  ifdef POLLRDNORM
251         XLAT(POLLRDNORM),
252 #  endif
253 #  ifdef POLLWRNORM
254         XLAT(POLLWRNORM),
255 #  endif
256 #  ifdef POLLRDBAND
257         XLAT(POLLRDBAND),
258 #  endif
259 #  ifdef POLLWRBAND
260         XLAT(POLLWRBAND),
261 #  endif
262         XLAT(POLLERR),
263         XLAT(POLLHUP),
264         XLAT(POLLNVAL),
265 # endif
266         XLAT_END
267 };
268
269 static int
270 decode_poll(struct tcb *tcp, long pts)
271 {
272         struct pollfd fds;
273         unsigned nfds;
274         unsigned long size, start, cur, end, abbrev_end;
275         int failed = 0;
276
277         if (entering(tcp)) {
278                 nfds = tcp->u_arg[1];
279                 size = sizeof(fds) * nfds;
280                 start = tcp->u_arg[0];
281                 end = start + size;
282                 if (nfds == 0 || size / sizeof(fds) != nfds || end < start) {
283                         tprintf("%#lx, %d, ",
284                                 tcp->u_arg[0], nfds);
285                         return 0;
286                 }
287                 if (abbrev(tcp)) {
288                         abbrev_end = start + max_strlen * sizeof(fds);
289                         if (abbrev_end < start)
290                                 abbrev_end = end;
291                 } else {
292                         abbrev_end = end;
293                 }
294                 tprints("[");
295                 for (cur = start; cur < end; cur += sizeof(fds)) {
296                         if (cur > start)
297                                 tprints(", ");
298                         if (cur >= abbrev_end) {
299                                 tprints("...");
300                                 break;
301                         }
302                         if (umoven(tcp, cur, sizeof fds, (char *) &fds) < 0) {
303                                 tprints("?");
304                                 failed = 1;
305                                 break;
306                         }
307                         if (fds.fd < 0) {
308                                 tprintf("{fd=%d}", fds.fd);
309                                 continue;
310                         }
311                         tprints("{fd=");
312                         printfd(tcp, fds.fd);
313                         tprints(", events=");
314                         printflags(pollflags, fds.events, "POLL???");
315                         tprints("}");
316                 }
317                 tprints("]");
318                 if (failed)
319                         tprintf(" %#lx", start);
320                 tprintf(", %d, ", nfds);
321                 return 0;
322         } else {
323                 static char outstr[1024];
324                 char *outptr;
325 #define end_outstr (outstr + sizeof(outstr))
326                 const char *flagstr;
327
328                 if (syserror(tcp))
329                         return 0;
330                 if (tcp->u_rval == 0) {
331                         tcp->auxstr = "Timeout";
332                         return RVAL_STR;
333                 }
334
335                 nfds = tcp->u_arg[1];
336                 size = sizeof(fds) * nfds;
337                 start = tcp->u_arg[0];
338                 end = start + size;
339                 if (nfds == 0 || size / sizeof(fds) != nfds || end < start)
340                         return 0;
341                 if (abbrev(tcp)) {
342                         abbrev_end = start + max_strlen * sizeof(fds);
343                         if (abbrev_end < start)
344                                 abbrev_end = end;
345                 } else {
346                         abbrev_end = end;
347                 }
348
349                 outptr = outstr;
350
351                 for (cur = start; cur < end; cur += sizeof(fds)) {
352                         if (umoven(tcp, cur, sizeof fds, (char *) &fds) < 0) {
353                                 if (outptr < end_outstr - 2)
354                                         *outptr++ = '?';
355                                 failed = 1;
356                                 break;
357                         }
358                         if (!fds.revents)
359                                 continue;
360                         if (outptr == outstr) {
361                                 *outptr++ = '[';
362                         } else {
363                                 if (outptr < end_outstr - 3)
364                                         outptr = stpcpy(outptr, ", ");
365                         }
366                         if (cur >= abbrev_end) {
367                                 if (outptr < end_outstr - 4)
368                                         outptr = stpcpy(outptr, "...");
369                                 break;
370                         }
371                         if (outptr < end_outstr - (sizeof("{fd=%d, revents=") + sizeof(int)*3) + 1)
372                                 outptr += sprintf(outptr, "{fd=%d, revents=", fds.fd);
373                         flagstr = sprintflags("", pollflags, fds.revents);
374                         if (outptr < end_outstr - (strlen(flagstr) + 2)) {
375                                 outptr = stpcpy(outptr, flagstr);
376                                 *outptr++ = '}';
377                         }
378                 }
379                 if (failed)
380                         return 0;
381
382                 if (outptr != outstr /* && outptr < end_outstr - 1 (always true)*/)
383                         *outptr++ = ']';
384
385                 *outptr = '\0';
386                 if (pts) {
387                         if (outptr < end_outstr - (10 + TIMESPEC_TEXT_BUFSIZE)) {
388                                 outptr = stpcpy(outptr, outptr == outstr ? "left " : ", left ");
389                                 sprint_timespec(outptr, tcp, pts);
390                         }
391                 }
392
393                 if (outptr == outstr)
394                         return 0;
395
396                 tcp->auxstr = outstr;
397                 return RVAL_STR;
398 #undef end_outstr
399         }
400 }
401
402 int
403 sys_poll(struct tcb *tcp)
404 {
405         int rc = decode_poll(tcp, 0);
406         if (entering(tcp)) {
407 # ifdef INFTIM
408                 if (tcp->u_arg[2] == INFTIM)
409                         tprints("INFTIM");
410                 else
411 # endif
412                         tprintf("%ld", tcp->u_arg[2]);
413         }
414         return rc;
415 }
416
417 int
418 sys_ppoll(struct tcb *tcp)
419 {
420         int rc = decode_poll(tcp, tcp->u_arg[2]);
421         if (entering(tcp)) {
422                 print_timespec(tcp, tcp->u_arg[2]);
423                 tprints(", ");
424                 /* NB: kernel requires arg[4] == NSIG / 8 */
425                 print_sigset_addr_len(tcp, tcp->u_arg[3], tcp->u_arg[4]);
426                 tprintf(", %lu", tcp->u_arg[4]);
427         }
428         return rc;
429 }
430
431 #else /* !HAVE_SYS_POLL_H */
432 int
433 sys_poll(struct tcb *tcp)
434 {
435         return 0;
436 }
437 #endif