]> granicus.if.org Git - strace/blob - io.c
Linux: implement decoding of preadv and pwritev syscalls
[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  *      $Id$
31  */
32
33 #include "defs.h"
34
35 #include <fcntl.h>
36 #if HAVE_SYS_UIO_H
37 #include <sys/uio.h>
38 #endif
39
40 #ifdef HAVE_LONG_LONG_OFF_T
41 /*
42  * Hacks for systems that have a long long off_t
43  */
44
45 #define sys_pread64     sys_pread
46 #define sys_pwrite64    sys_pwrite
47 #endif
48
49 int
50 sys_read(struct tcb *tcp)
51 {
52         if (entering(tcp)) {
53                 printfd(tcp, tcp->u_arg[0]);
54                 tprintf(", ");
55         } else {
56                 if (syserror(tcp))
57                         tprintf("%#lx", tcp->u_arg[1]);
58                 else
59                         printstr(tcp, tcp->u_arg[1], tcp->u_rval);
60                 tprintf(", %lu", tcp->u_arg[2]);
61         }
62         return 0;
63 }
64
65 int
66 sys_write(struct tcb *tcp)
67 {
68         if (entering(tcp)) {
69                 printfd(tcp, tcp->u_arg[0]);
70                 tprintf(", ");
71                 printstr(tcp, tcp->u_arg[1], tcp->u_arg[2]);
72                 tprintf(", %lu", tcp->u_arg[2]);
73         }
74         return 0;
75 }
76
77 #if HAVE_SYS_UIO_H
78 void
79 tprint_iov(struct tcb *tcp, unsigned long len, unsigned long addr)
80 {
81 #if defined(LINUX) && SUPPORTED_PERSONALITIES > 1
82         union {
83                 struct { u_int32_t base; u_int32_t len; } iov32;
84                 struct { u_int64_t base; u_int64_t len; } iov64;
85         } iov;
86 #define sizeof_iov \
87   (personality_wordsize[current_personality] == 4 \
88    ? sizeof(iov.iov32) : sizeof(iov.iov64))
89 #define iov_iov_base \
90   (personality_wordsize[current_personality] == 4 \
91    ? (u_int64_t) iov.iov32.base : iov.iov64.base)
92 #define iov_iov_len \
93   (personality_wordsize[current_personality] == 4 \
94    ? (u_int64_t) iov.iov32.len : iov.iov64.len)
95 #else
96         struct iovec iov;
97 #define sizeof_iov sizeof(iov)
98 #define iov_iov_base iov.iov_base
99 #define iov_iov_len iov.iov_len
100 #endif
101         unsigned long size, cur, end, abbrev_end;
102         int failed = 0;
103
104         if (!len) {
105                 tprintf("[]");
106                 return;
107         }
108         size = len * sizeof_iov;
109         end = addr + size;
110         if (!verbose(tcp) || size / sizeof_iov != len || end < addr) {
111                 tprintf("%#lx", addr);
112                 return;
113         }
114         if (abbrev(tcp)) {
115                 abbrev_end = addr + max_strlen * sizeof_iov;
116                 if (abbrev_end < addr)
117                         abbrev_end = end;
118         } else {
119                 abbrev_end = end;
120         }
121         tprintf("[");
122         for (cur = addr; cur < end; cur += sizeof_iov) {
123                 if (cur > addr)
124                         tprintf(", ");
125                 if (cur >= abbrev_end) {
126                         tprintf("...");
127                         break;
128                 }
129                 if (umoven(tcp, cur, sizeof_iov, (char *) &iov) < 0) {
130                         tprintf("?");
131                         failed = 1;
132                         break;
133                 }
134                 tprintf("{");
135                 printstr(tcp, (long) iov_iov_base, iov_iov_len);
136                 tprintf(", %lu}", (unsigned long)iov_iov_len);
137         }
138         tprintf("]");
139         if (failed)
140                 tprintf(" %#lx", addr);
141 #undef sizeof_iov
142 #undef iov_iov_base
143 #undef iov_iov_len
144 }
145
146 int
147 sys_readv(struct tcb *tcp)
148 {
149         if (entering(tcp)) {
150                 printfd(tcp, tcp->u_arg[0]);
151                 tprintf(", ");
152         } else {
153                 if (syserror(tcp)) {
154                         tprintf("%#lx, %lu",
155                                         tcp->u_arg[1], tcp->u_arg[2]);
156                         return 0;
157                 }
158                 tprint_iov(tcp, tcp->u_arg[2], tcp->u_arg[1]);
159                 tprintf(", %lu", tcp->u_arg[2]);
160         }
161         return 0;
162 }
163
164 int
165 sys_writev(struct tcb *tcp)
166 {
167         if (entering(tcp)) {
168                 printfd(tcp, tcp->u_arg[0]);
169                 tprintf(", ");
170                 tprint_iov(tcp, tcp->u_arg[2], tcp->u_arg[1]);
171                 tprintf(", %lu", tcp->u_arg[2]);
172         }
173         return 0;
174 }
175 #endif
176
177 #if defined(SVR4)
178
179 int
180 sys_pread(struct tcb *tcp)
181 {
182         if (entering(tcp)) {
183                 printfd(tcp, tcp->u_arg[0]);
184                 tprintf(", ");
185         } else {
186                 if (syserror(tcp))
187                         tprintf("%#lx", tcp->u_arg[1]);
188                 else
189                         printstr(tcp, tcp->u_arg[1], tcp->u_rval);
190 #if UNIXWARE
191                 /* off_t is signed int */
192                 tprintf(", %lu, %ld", tcp->u_arg[2], tcp->u_arg[3]);
193 #else
194                 tprintf(", %lu, %llu", tcp->u_arg[2],
195                         LONG_LONG(tcp->u_arg[3], tcp->u_arg[4]));
196 #endif
197         }
198         return 0;
199 }
200
201 int
202 sys_pwrite(struct tcb *tcp)
203 {
204         if (entering(tcp)) {
205                 printfd(tcp, tcp->u_arg[0]);
206                 tprintf(", ");
207                 printstr(tcp, tcp->u_arg[1], tcp->u_arg[2]);
208 #if UNIXWARE
209                 /* off_t is signed int */
210                 tprintf(", %lu, %ld", tcp->u_arg[2], tcp->u_arg[3]);
211 #else
212                 tprintf(", %lu, %llu", tcp->u_arg[2],
213                         LONG_LONG(tcp->u_arg[3], tcp->u_arg[4]));
214 #endif
215         }
216         return 0;
217 }
218 #endif /* SVR4 */
219
220 #ifdef FREEBSD
221 #include <sys/types.h>
222 #include <sys/socket.h>
223
224 int
225 sys_sendfile(struct tcb *tcp)
226 {
227         if (entering(tcp)) {
228                 printfd(tcp, tcp->u_arg[0]);
229                 tprintf(", ");
230                 printfd(tcp, tcp->u_arg[1]);
231                 tprintf(", %llu, %lu",
232                         LONG_LONG(tcp->u_arg[2], tcp->u_arg[3]),
233                         tcp->u_arg[4]);
234         } else {
235                 off_t offset;
236
237                 if (!tcp->u_arg[5])
238                         tprintf(", NULL");
239                 else {
240                         struct sf_hdtr hdtr;
241
242                         if (umove(tcp, tcp->u_arg[5], &hdtr) < 0)
243                                 tprintf(", %#lx", tcp->u_arg[5]);
244                         else {
245                                 tprintf(", { ");
246                                 tprint_iov(tcp, hdtr.hdr_cnt, hdtr.headers);
247                                 tprintf(", %u, ", hdtr.hdr_cnt);
248                                 tprint_iov(tcp, hdtr.trl_cnt, hdtr.trailers);
249                                 tprintf(", %u }", hdtr.hdr_cnt);
250                         }
251                 }
252                 if (!tcp->u_arg[6])
253                         tprintf(", NULL");
254                 else if (umove(tcp, tcp->u_arg[6], &offset) < 0)
255                         tprintf(", %#lx", tcp->u_arg[6]);
256                 else
257                         tprintf(", [%llu]", offset);
258                 tprintf(", %lu", tcp->u_arg[7]);
259         }
260         return 0;
261 }
262 #endif /* FREEBSD */
263
264 #ifdef LINUX
265
266 /* The SH4 ABI does allow long longs in odd-numbered registers, but
267    does not allow them to be split between registers and memory - and
268    there are only four argument registers for normal functions.  As a
269    result pread takes an extra padding argument before the offset.  This
270    was changed late in the 2.4 series (around 2.4.20).  */
271 #if defined(SH)
272 #define PREAD_OFFSET_ARG 4
273 #else
274 #define PREAD_OFFSET_ARG 3
275 #endif
276
277 int
278 sys_pread(struct tcb *tcp)
279 {
280         if (entering(tcp)) {
281                 printfd(tcp, tcp->u_arg[0]);
282                 tprintf(", ");
283         } else {
284                 if (syserror(tcp))
285                         tprintf("%#lx", tcp->u_arg[1]);
286                 else
287                         printstr(tcp, tcp->u_arg[1], tcp->u_rval);
288                 tprintf(", %lu, ", tcp->u_arg[2]);
289                 printllval(tcp, "%llu", PREAD_OFFSET_ARG);
290         }
291         return 0;
292 }
293
294 int
295 sys_pwrite(struct tcb *tcp)
296 {
297         if (entering(tcp)) {
298                 printfd(tcp, tcp->u_arg[0]);
299                 tprintf(", ");
300                 printstr(tcp, tcp->u_arg[1], tcp->u_arg[2]);
301                 tprintf(", %lu, ", tcp->u_arg[2]);
302                 printllval(tcp, "%llu", PREAD_OFFSET_ARG);
303         }
304         return 0;
305 }
306
307 #if HAVE_SYS_UIO_H
308 int
309 sys_preadv(struct tcb *tcp)
310 {
311         if (entering(tcp)) {
312                 printfd(tcp, tcp->u_arg[0]);
313                 tprintf(", ");
314         } else {
315                 if (syserror(tcp)) {
316                         tprintf("%#lx, %lu", tcp->u_arg[1], tcp->u_arg[2]);
317                         return 0;
318                 }
319                 tprint_iov(tcp, tcp->u_arg[2], tcp->u_arg[1]);
320                 tprintf(", %lu, ", tcp->u_arg[2]);
321                 printllval(tcp, "%llu", PREAD_OFFSET_ARG);
322         }
323         return 0;
324 }
325
326 int
327 sys_pwritev(struct tcb *tcp)
328 {
329         if (entering(tcp)) {
330                 printfd(tcp, tcp->u_arg[0]);
331                 tprintf(", ");
332                 tprint_iov(tcp, tcp->u_arg[2], tcp->u_arg[1]);
333                 tprintf(", %lu, ", tcp->u_arg[2]);
334                 printllval(tcp, "%llu", PREAD_OFFSET_ARG);
335         }
336         return 0;
337 }
338 #endif /* HAVE_SYS_UIO_H */
339
340 int
341 sys_sendfile(struct tcb *tcp)
342 {
343         if (entering(tcp)) {
344                 off_t offset;
345
346                 printfd(tcp, tcp->u_arg[0]);
347                 tprintf(", ");
348                 printfd(tcp, tcp->u_arg[1]);
349                 tprintf(", ");
350                 if (!tcp->u_arg[2])
351                         tprintf("NULL");
352                 else if (umove(tcp, tcp->u_arg[2], &offset) < 0)
353                         tprintf("%#lx", tcp->u_arg[2]);
354                 else
355                         tprintf("[%lu]", offset);
356                 tprintf(", %lu", tcp->u_arg[3]);
357         }
358         return 0;
359 }
360
361 int
362 sys_sendfile64(struct tcb *tcp)
363 {
364         if (entering(tcp)) {
365                 loff_t offset;
366
367                 printfd(tcp, tcp->u_arg[0]);
368                 tprintf(", ");
369                 printfd(tcp, tcp->u_arg[1]);
370                 tprintf(", ");
371                 if (!tcp->u_arg[2])
372                         tprintf("NULL");
373                 else if (umove(tcp, tcp->u_arg[2], &offset) < 0)
374                         tprintf("%#lx", tcp->u_arg[2]);
375                 else
376                         tprintf("[%llu]", (unsigned long long int) offset);
377                 tprintf(", %lu", tcp->u_arg[3]);
378         }
379         return 0;
380 }
381
382 #endif /* LINUX */
383
384 #if _LFS64_LARGEFILE || HAVE_LONG_LONG_OFF_T
385 int
386 sys_pread64(struct tcb *tcp)
387 {
388         if (entering(tcp)) {
389                 printfd(tcp, tcp->u_arg[0]);
390                 tprintf(", ");
391         } else {
392                 if (syserror(tcp))
393                         tprintf("%#lx", tcp->u_arg[1]);
394                 else
395                         printstr(tcp, tcp->u_arg[1], tcp->u_rval);
396                 tprintf(", %lu, ", tcp->u_arg[2]);
397                 printllval(tcp, "%#llx", 3);
398         }
399         return 0;
400 }
401
402 int
403 sys_pwrite64(struct tcb *tcp)
404 {
405         if (entering(tcp)) {
406                 printfd(tcp, tcp->u_arg[0]);
407                 tprintf(", ");
408                 printstr(tcp, tcp->u_arg[1], tcp->u_arg[2]);
409                 tprintf(", %lu, ", tcp->u_arg[2]);
410                 printllval(tcp, "%#llx", 3);
411         }
412         return 0;
413 }
414 #endif
415
416 int
417 sys_ioctl(struct tcb *tcp)
418 {
419         const struct ioctlent *iop;
420
421         if (entering(tcp)) {
422                 printfd(tcp, tcp->u_arg[0]);
423                 tprintf(", ");
424                 iop = ioctl_lookup(tcp->u_arg[1]);
425                 if (iop) {
426                         tprintf("%s", iop->symbol);
427                         while ((iop = ioctl_next_match(iop)))
428                                 tprintf(" or %s", iop->symbol);
429                 } else
430                         tprintf("%#lx", tcp->u_arg[1]);
431                 ioctl_decode(tcp, tcp->u_arg[1], tcp->u_arg[2]);
432         }
433         else {
434                 int ret;
435                 if (!(ret = ioctl_decode(tcp, tcp->u_arg[1], tcp->u_arg[2])))
436                         tprintf(", %#lx", tcp->u_arg[2]);
437                 else
438                         return ret - 1;
439         }
440         return 0;
441 }