]> granicus.if.org Git - strace/blob - io.c
Declare syscall parsers using SYS_FUNC macro
[strace] / io.c
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/uio.h>
34
35 SYS_FUNC(read)
36 {
37         if (entering(tcp)) {
38                 printfd(tcp, tcp->u_arg[0]);
39                 tprints(", ");
40         } else {
41                 if (syserror(tcp))
42                         tprintf("%#lx", tcp->u_arg[1]);
43                 else
44                         printstr(tcp, tcp->u_arg[1], tcp->u_rval);
45                 tprintf(", %lu", tcp->u_arg[2]);
46         }
47         return 0;
48 }
49
50 SYS_FUNC(write)
51 {
52         if (entering(tcp)) {
53                 printfd(tcp, tcp->u_arg[0]);
54                 tprints(", ");
55                 printstr(tcp, tcp->u_arg[1], tcp->u_arg[2]);
56                 tprintf(", %lu", tcp->u_arg[2]);
57         }
58         return 0;
59 }
60
61 /*
62  * data_size limits the cumulative size of printed data.
63  * Example: recvmsg returing a short read.
64  */
65 void
66 tprint_iov_upto(struct tcb *tcp, unsigned long len, unsigned long addr, int decode_iov, unsigned long data_size)
67 {
68 #if SUPPORTED_PERSONALITIES > 1
69         union {
70                 struct { u_int32_t base; u_int32_t len; } iov32;
71                 struct { u_int64_t base; u_int64_t len; } iov64;
72         } iov;
73 #define sizeof_iov \
74         (current_wordsize == 4 ? sizeof(iov.iov32) : sizeof(iov.iov64))
75 #define iov_iov_base \
76         (current_wordsize == 4 ? (uint64_t) iov.iov32.base : iov.iov64.base)
77 #define iov_iov_len \
78         (current_wordsize == 4 ? (uint64_t) iov.iov32.len : iov.iov64.len)
79 #else
80         struct iovec iov;
81 #define sizeof_iov sizeof(iov)
82 #define iov_iov_base iov.iov_base
83 #define iov_iov_len iov.iov_len
84 #endif
85         unsigned long size, cur, end, abbrev_end;
86         int failed = 0;
87
88         if (!len) {
89                 tprints("[]");
90                 return;
91         }
92         size = len * sizeof_iov;
93         end = addr + size;
94         if (!verbose(tcp) || size / sizeof_iov != len || end < addr) {
95                 tprintf("%#lx", addr);
96                 return;
97         }
98         if (abbrev(tcp)) {
99                 abbrev_end = addr + max_strlen * sizeof_iov;
100                 if (abbrev_end < addr)
101                         abbrev_end = end;
102         } else {
103                 abbrev_end = end;
104         }
105         tprints("[");
106         for (cur = addr; cur < end; cur += sizeof_iov) {
107                 if (cur > addr)
108                         tprints(", ");
109                 if (cur >= abbrev_end) {
110                         tprints("...");
111                         break;
112                 }
113                 if (umoven(tcp, cur, sizeof_iov, &iov) < 0) {
114                         tprints("?");
115                         failed = 1;
116                         break;
117                 }
118                 tprints("{");
119                 if (decode_iov) {
120                         unsigned long len = iov_iov_len;
121                         if (len > data_size)
122                                 len = data_size;
123                         data_size -= len;
124                         printstr(tcp, (long) iov_iov_base, len);
125                 } else
126                         tprintf("%#lx", (long) iov_iov_base);
127                 tprintf(", %lu}", (unsigned long)iov_iov_len);
128         }
129         tprints("]");
130         if (failed)
131                 tprintf(" %#lx", addr);
132 #undef sizeof_iov
133 #undef iov_iov_base
134 #undef iov_iov_len
135 }
136
137 void
138 tprint_iov(struct tcb *tcp, unsigned long len, unsigned long addr, int decode_iov)
139 {
140         tprint_iov_upto(tcp, len, addr, decode_iov, (unsigned long) -1L);
141 }
142
143 SYS_FUNC(readv)
144 {
145         if (entering(tcp)) {
146                 printfd(tcp, tcp->u_arg[0]);
147                 tprints(", ");
148         } else {
149                 if (syserror(tcp)) {
150                         tprintf("%#lx, %lu",
151                                         tcp->u_arg[1], tcp->u_arg[2]);
152                         return 0;
153                 }
154                 tprint_iov(tcp, tcp->u_arg[2], tcp->u_arg[1], 1);
155                 tprintf(", %lu", tcp->u_arg[2]);
156         }
157         return 0;
158 }
159
160 SYS_FUNC(writev)
161 {
162         if (entering(tcp)) {
163                 printfd(tcp, tcp->u_arg[0]);
164                 tprints(", ");
165                 tprint_iov(tcp, tcp->u_arg[2], tcp->u_arg[1], 1);
166                 tprintf(", %lu", tcp->u_arg[2]);
167         }
168         return 0;
169 }
170
171 /* The SH4 ABI does allow long longs in odd-numbered registers, but
172    does not allow them to be split between registers and memory - and
173    there are only four argument registers for normal functions.  As a
174    result pread takes an extra padding argument before the offset.  This
175    was changed late in the 2.4 series (around 2.4.20).  */
176 #if defined(SH)
177 #define PREAD_OFFSET_ARG 4
178 #else
179 #define PREAD_OFFSET_ARG 3
180 #endif
181
182 SYS_FUNC(pread)
183 {
184         if (entering(tcp)) {
185                 printfd(tcp, tcp->u_arg[0]);
186                 tprints(", ");
187         } else {
188                 if (syserror(tcp))
189                         tprintf("%#lx", tcp->u_arg[1]);
190                 else
191                         printstr(tcp, tcp->u_arg[1], tcp->u_rval);
192                 tprintf(", %lu, ", tcp->u_arg[2]);
193                 printllval(tcp, "%llu", PREAD_OFFSET_ARG);
194         }
195         return 0;
196 }
197
198 SYS_FUNC(pwrite)
199 {
200         if (entering(tcp)) {
201                 printfd(tcp, tcp->u_arg[0]);
202                 tprints(", ");
203                 printstr(tcp, tcp->u_arg[1], tcp->u_arg[2]);
204                 tprintf(", %lu, ", tcp->u_arg[2]);
205                 printllval(tcp, "%llu", PREAD_OFFSET_ARG);
206         }
207         return 0;
208 }
209
210 static void
211 print_llu_from_low_high_val(struct tcb *tcp, int arg)
212 {
213 #if SIZEOF_LONG == SIZEOF_LONG_LONG
214 # if SUPPORTED_PERSONALITIES > 1
215         if (current_wordsize == sizeof(long))
216 # endif
217                 tprintf("%lu", (unsigned long) tcp->u_arg[arg]);
218 # if SUPPORTED_PERSONALITIES > 1
219         else
220                 tprintf("%lu",
221                         ((unsigned long) tcp->u_arg[arg + 1] << current_wordsize * 8)
222                         | (unsigned long) tcp->u_arg[arg]);
223 # endif
224 #else
225 # ifdef X32
226         if (current_personality == 0)
227                 tprintf("%llu", (unsigned long long) tcp->ext_arg[arg]);
228         else
229 # endif
230         tprintf("%llu",
231                 ((unsigned long long) (unsigned long) tcp->u_arg[arg + 1] << sizeof(long) * 8)
232                 | (unsigned long long) (unsigned long) tcp->u_arg[arg]);
233 #endif
234 }
235
236 SYS_FUNC(preadv)
237 {
238         if (entering(tcp)) {
239                 printfd(tcp, tcp->u_arg[0]);
240                 tprints(", ");
241         } else {
242                 if (syserror(tcp)) {
243                         tprintf("%#lx, %lu", tcp->u_arg[1], tcp->u_arg[2]);
244                         return 0;
245                 }
246                 tprint_iov(tcp, tcp->u_arg[2], tcp->u_arg[1], 1);
247                 tprintf(", %lu, ", tcp->u_arg[2]);
248                 print_llu_from_low_high_val(tcp, 3);
249         }
250         return 0;
251 }
252
253 SYS_FUNC(pwritev)
254 {
255         if (entering(tcp)) {
256                 printfd(tcp, tcp->u_arg[0]);
257                 tprints(", ");
258                 tprint_iov(tcp, tcp->u_arg[2], tcp->u_arg[1], 1);
259                 tprintf(", %lu, ", tcp->u_arg[2]);
260                 print_llu_from_low_high_val(tcp, 3);
261         }
262         return 0;
263 }
264
265 static void
266 print_off_t(struct tcb *tcp, long addr)
267 {
268         unsigned long offset;
269
270         if (!addr) {
271                 tprints("NULL");
272                 return;
273         }
274
275 #if SUPPORTED_PERSONALITIES > 1 && SIZEOF_LONG > 4
276         if (current_wordsize == 4) {
277                 uint32_t off;
278
279                 if (umove(tcp, addr, &off) < 0)
280                         tprintf("%#lx", addr);
281                 else
282                         tprintf("[%u]", off);
283         } else
284 #endif
285         if (umove(tcp, addr, &offset) < 0)
286                 tprintf("%#lx", addr);
287         else
288                 tprintf("[%lu]", offset);
289 }
290
291 SYS_FUNC(sendfile)
292 {
293         if (entering(tcp)) {
294                 printfd(tcp, tcp->u_arg[0]);
295                 tprints(", ");
296                 printfd(tcp, tcp->u_arg[1]);
297                 tprints(", ");
298                 print_off_t(tcp, tcp->u_arg[2]);
299                 tprintf(", %lu", tcp->u_arg[3]);
300         }
301         return 0;
302 }
303
304 void
305 print_loff_t(struct tcb *tcp, long addr)
306 {
307         loff_t offset;
308
309         if (!addr)
310                 tprints("NULL");
311         else if (umove(tcp, addr, &offset) < 0)
312                 tprintf("%#lx", addr);
313         else
314                 tprintf("[%llu]", (unsigned long long int) offset);
315 }
316
317 SYS_FUNC(sendfile64)
318 {
319         if (entering(tcp)) {
320                 printfd(tcp, tcp->u_arg[0]);
321                 tprints(", ");
322                 printfd(tcp, tcp->u_arg[1]);
323                 tprints(", ");
324                 print_loff_t(tcp, tcp->u_arg[2]);
325                 tprintf(", %lu", tcp->u_arg[3]);
326         }
327         return 0;
328 }
329
330 #include "xlat/splice_flags.h"
331
332 SYS_FUNC(tee)
333 {
334         if (entering(tcp)) {
335                 /* int fd_in */
336                 printfd(tcp, tcp->u_arg[0]);
337                 tprints(", ");
338                 /* int fd_out */
339                 printfd(tcp, tcp->u_arg[1]);
340                 tprints(", ");
341                 /* size_t len */
342                 tprintf("%lu, ", tcp->u_arg[2]);
343                 /* unsigned int flags */
344                 printflags(splice_flags, tcp->u_arg[3], "SPLICE_F_???");
345         }
346         return 0;
347 }
348
349 SYS_FUNC(splice)
350 {
351         if (entering(tcp)) {
352                 /* int fd_in */
353                 printfd(tcp, tcp->u_arg[0]);
354                 tprints(", ");
355                 /* loff_t *off_in */
356                 print_loff_t(tcp, tcp->u_arg[1]);
357                 tprints(", ");
358                 /* int fd_out */
359                 printfd(tcp, tcp->u_arg[2]);
360                 tprints(", ");
361                 /* loff_t *off_out */
362                 print_loff_t(tcp, tcp->u_arg[3]);
363                 tprints(", ");
364                 /* size_t len */
365                 tprintf("%lu, ", tcp->u_arg[4]);
366                 /* unsigned int flags */
367                 printflags(splice_flags, tcp->u_arg[5], "SPLICE_F_???");
368         }
369         return 0;
370 }
371
372 SYS_FUNC(vmsplice)
373 {
374         if (entering(tcp)) {
375                 /* int fd */
376                 printfd(tcp, tcp->u_arg[0]);
377                 tprints(", ");
378                 /* const struct iovec *iov, unsigned long nr_segs */
379                 tprint_iov(tcp, tcp->u_arg[2], tcp->u_arg[1], 1);
380                 tprintf(", %lu, ", tcp->u_arg[2]);
381                 /* unsigned int flags */
382                 printflags(splice_flags, tcp->u_arg[3], "SPLICE_F_???");
383         }
384         return 0;
385 }
386
387 SYS_FUNC(ioctl)
388 {
389         const struct_ioctlent *iop;
390
391         if (entering(tcp)) {
392                 printfd(tcp, tcp->u_arg[0]);
393                 tprints(", ");
394                 if (!ioctl_decode_command_number(tcp->u_arg[1])) {
395                         iop = ioctl_lookup(tcp->u_arg[1]);
396                         if (iop) {
397                                 tprints(iop->symbol);
398                                 while ((iop = ioctl_next_match(iop)))
399                                         tprintf(" or %s", iop->symbol);
400                         } else {
401                                 ioctl_print_code(tcp->u_arg[1]);
402                         }
403                 }
404                 ioctl_decode(tcp, tcp->u_arg[1], tcp->u_arg[2]);
405         }
406         else {
407                 int ret = ioctl_decode(tcp, tcp->u_arg[1], tcp->u_arg[2]);
408                 if (!ret)
409                         tprintf(", %#lx", tcp->u_arg[2]);
410                 else
411                         return ret - 1;
412         }
413         return 0;
414 }