]> granicus.if.org Git - strace/blob - io.c
Fix printing of negative offsets in pread64 and pwrite64 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
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                         printaddr(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         printfd(tcp, tcp->u_arg[0]);
53         tprints(", ");
54         printstr(tcp, tcp->u_arg[1], tcp->u_arg[2]);
55         tprintf(", %lu", tcp->u_arg[2]);
56
57         return RVAL_DECODED;
58 }
59
60 /*
61  * data_size limits the cumulative size of printed data.
62  * Example: recvmsg returing a short read.
63  */
64 void
65 tprint_iov_upto(struct tcb *tcp, unsigned long len, unsigned long addr, int decode_iov, unsigned long data_size)
66 {
67         unsigned long iov[2];
68         unsigned long size, cur, end, abbrev_end;
69         const unsigned long sizeof_iov = current_wordsize * 2;
70
71         if (!len) {
72                 tprints("[]");
73                 return;
74         }
75         size = len * sizeof_iov;
76         end = addr + size;
77         if (!verbose(tcp) || (exiting(tcp) && syserror(tcp)) ||
78             !addr || size / sizeof_iov != len || end < addr) {
79                 printaddr(addr);
80                 return;
81         }
82         if (abbrev(tcp)) {
83                 abbrev_end = addr + max_strlen * sizeof_iov;
84                 if (abbrev_end < addr)
85                         abbrev_end = end;
86         } else {
87                 abbrev_end = end;
88         }
89         if (addr >= abbrev_end) {
90                 tprints("[...]");
91                 return;
92         }
93         for (cur = addr; cur < end; cur += sizeof_iov) {
94                 if (cur > addr) {
95                         tprints(", ");
96                         if (cur >= abbrev_end) {
97                                 tprints("...");
98                                 break;
99                         }
100                 }
101                 if (umove_ulong_array_or_printaddr(tcp, cur, iov,
102                                                    ARRAY_SIZE(iov)))
103                         break;
104                 if (cur <= addr)
105                         tprints("[");
106                 tprints("{");
107                 if (decode_iov) {
108                         unsigned long len = iov[1];
109                         if (len > data_size)
110                                 len = data_size;
111                         data_size -= len;
112                         printstr(tcp, iov[0], len);
113                 } else
114                         printaddr(iov[0]);
115                 tprintf(", %lu}", iov[1]);
116         }
117         if (cur > addr)
118                 tprints("]");
119 }
120
121 void
122 tprint_iov(struct tcb *tcp, unsigned long len, unsigned long addr, int decode_iov)
123 {
124         tprint_iov_upto(tcp, len, addr, decode_iov, (unsigned long) -1L);
125 }
126
127 SYS_FUNC(readv)
128 {
129         if (entering(tcp)) {
130                 printfd(tcp, tcp->u_arg[0]);
131                 tprints(", ");
132         } else {
133                 tprint_iov_upto(tcp, tcp->u_arg[2], tcp->u_arg[1], 1,
134                                 tcp->u_rval);
135                 tprintf(", %lu", tcp->u_arg[2]);
136         }
137         return 0;
138 }
139
140 SYS_FUNC(writev)
141 {
142         printfd(tcp, tcp->u_arg[0]);
143         tprints(", ");
144         tprint_iov(tcp, tcp->u_arg[2], tcp->u_arg[1], 1);
145         tprintf(", %lu", tcp->u_arg[2]);
146
147         return RVAL_DECODED;
148 }
149
150 /* The SH4 ABI does allow long longs in odd-numbered registers, but
151    does not allow them to be split between registers and memory - and
152    there are only four argument registers for normal functions.  As a
153    result pread takes an extra padding argument before the offset.  This
154    was changed late in the 2.4 series (around 2.4.20).  */
155 #if defined(SH)
156 #define PREAD_OFFSET_ARG 4
157 #else
158 #define PREAD_OFFSET_ARG 3
159 #endif
160
161 SYS_FUNC(pread)
162 {
163         if (entering(tcp)) {
164                 printfd(tcp, tcp->u_arg[0]);
165                 tprints(", ");
166         } else {
167                 if (syserror(tcp))
168                         printaddr(tcp->u_arg[1]);
169                 else
170                         printstr(tcp, tcp->u_arg[1], tcp->u_rval);
171                 tprintf(", %lu, ", tcp->u_arg[2]);
172                 printllval(tcp, "%lld", PREAD_OFFSET_ARG);
173         }
174         return 0;
175 }
176
177 SYS_FUNC(pwrite)
178 {
179         printfd(tcp, tcp->u_arg[0]);
180         tprints(", ");
181         printstr(tcp, tcp->u_arg[1], tcp->u_arg[2]);
182         tprintf(", %lu, ", tcp->u_arg[2]);
183         printllval(tcp, "%lld", PREAD_OFFSET_ARG);
184
185         return RVAL_DECODED;
186 }
187
188 static void
189 print_lld_from_low_high_val(struct tcb *tcp, int arg)
190 {
191 #if SIZEOF_LONG == SIZEOF_LONG_LONG
192 # if SUPPORTED_PERSONALITIES > 1
193 #  ifdef X86_64
194         if (current_personality != 1)
195 #  else
196         if (current_wordsize == sizeof(long))
197 #  endif
198 # endif
199                 tprintf("%ld", tcp->u_arg[arg]);
200 # if SUPPORTED_PERSONALITIES > 1
201         else
202                 tprintf("%ld",
203                         ((unsigned long) tcp->u_arg[arg + 1] << current_wordsize * 8)
204                         | (unsigned long) tcp->u_arg[arg]);
205 # endif
206 #else
207 # ifdef X32
208         if (current_personality == 0)
209                 tprintf("%lld", tcp->ext_arg[arg]);
210         else
211 # endif
212         tprintf("%lld",
213                 ((unsigned long long) (unsigned long) tcp->u_arg[arg + 1] << sizeof(long) * 8)
214                 | (unsigned long long) (unsigned long) tcp->u_arg[arg]);
215 #endif
216 }
217
218 SYS_FUNC(preadv)
219 {
220         if (entering(tcp)) {
221                 printfd(tcp, tcp->u_arg[0]);
222                 tprints(", ");
223         } else {
224                 tprint_iov_upto(tcp, tcp->u_arg[2], tcp->u_arg[1], 1,
225                                 tcp->u_rval);
226                 tprintf(", %lu, ", tcp->u_arg[2]);
227                 print_lld_from_low_high_val(tcp, 3);
228         }
229         return 0;
230 }
231
232 SYS_FUNC(pwritev)
233 {
234         printfd(tcp, tcp->u_arg[0]);
235         tprints(", ");
236         tprint_iov(tcp, tcp->u_arg[2], tcp->u_arg[1], 1);
237         tprintf(", %lu, ", tcp->u_arg[2]);
238         print_lld_from_low_high_val(tcp, 3);
239
240         return RVAL_DECODED;
241 }
242
243 #include "xlat/splice_flags.h"
244
245 SYS_FUNC(tee)
246 {
247         /* int fd_in */
248         printfd(tcp, tcp->u_arg[0]);
249         tprints(", ");
250         /* int fd_out */
251         printfd(tcp, tcp->u_arg[1]);
252         tprints(", ");
253         /* size_t len */
254         tprintf("%lu, ", tcp->u_arg[2]);
255         /* unsigned int flags */
256         printflags(splice_flags, tcp->u_arg[3], "SPLICE_F_???");
257
258         return RVAL_DECODED;
259 }
260
261 SYS_FUNC(splice)
262 {
263         /* int fd_in */
264         printfd(tcp, tcp->u_arg[0]);
265         tprints(", ");
266         /* loff_t *off_in */
267         printnum_int64(tcp, tcp->u_arg[1], "%" PRId64);
268         tprints(", ");
269         /* int fd_out */
270         printfd(tcp, tcp->u_arg[2]);
271         tprints(", ");
272         /* loff_t *off_out */
273         printnum_int64(tcp, tcp->u_arg[3], "%" PRId64);
274         tprints(", ");
275         /* size_t len */
276         tprintf("%lu, ", tcp->u_arg[4]);
277         /* unsigned int flags */
278         printflags(splice_flags, tcp->u_arg[5], "SPLICE_F_???");
279
280         return RVAL_DECODED;
281 }
282
283 SYS_FUNC(vmsplice)
284 {
285         /* int fd */
286         printfd(tcp, tcp->u_arg[0]);
287         tprints(", ");
288         /* const struct iovec *iov, unsigned long nr_segs */
289         tprint_iov(tcp, tcp->u_arg[2], tcp->u_arg[1], 1);
290         tprintf(", %lu, ", tcp->u_arg[2]);
291         /* unsigned int flags */
292         printflags(splice_flags, tcp->u_arg[3], "SPLICE_F_???");
293
294         return RVAL_DECODED;
295 }