]> granicus.if.org Git - strace/blob - aio.c
tests: add support of multi-line diagnostics to check_h
[strace] / aio.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  * Copyright (c) 1999-2019 The strace developers.
7  * All rights reserved.
8  *
9  * SPDX-License-Identifier: LGPL-2.1-or-later
10  */
11
12 #include "defs.h"
13 #include "print_fields.h"
14 #include <linux/aio_abi.h>
15
16 #include "xlat/aio_cmds.h"
17
18 #ifdef HAVE_STRUCT_IOCB_AIO_FLAGS
19 # include "xlat/aio_iocb_flags.h"
20 #endif
21
22 #ifdef HAVE_STRUCT_IOCB_AIO_RW_FLAGS
23 # define AIO_RW_FLAGS_FIELD aio_rw_flags
24 #else
25 # define AIO_RW_FLAGS_FIELD aio_reserved1
26 #endif
27
28 SYS_FUNC(io_setup)
29 {
30         if (entering(tcp))
31                 tprintf("%u, ", (unsigned int) tcp->u_arg[0]);
32         else
33                 printnum_ptr(tcp, tcp->u_arg[1]);
34         return 0;
35 }
36
37 SYS_FUNC(io_destroy)
38 {
39         printaddr(tcp->u_arg[0]);
40
41         return RVAL_DECODED;
42 }
43
44 enum iocb_sub {
45         SUB_NONE, SUB_COMMON, SUB_VECTOR, SUB_POLL
46 };
47
48 static enum iocb_sub
49 tprint_lio_opcode(unsigned int cmd)
50 {
51         static const enum iocb_sub subs[] = {
52                 [IOCB_CMD_PREAD]        = SUB_COMMON,
53                 [IOCB_CMD_PWRITE]       = SUB_COMMON,
54                 [IOCB_CMD_FSYNC]        = SUB_NONE,
55                 [IOCB_CMD_FDSYNC]       = SUB_NONE,
56                 [IOCB_CMD_PREADX]       = SUB_NONE,
57                 [IOCB_CMD_POLL]         = SUB_POLL,
58                 [IOCB_CMD_NOOP]         = SUB_NONE,
59                 [IOCB_CMD_PREADV]       = SUB_VECTOR,
60                 [IOCB_CMD_PWRITEV]      = SUB_VECTOR,
61         };
62
63         printxval_ex(aio_cmds, cmd, "IOCB_CMD_???", XLAT_STYLE_FMT_U);
64
65         return cmd < ARRAY_SIZE(subs) ? subs[cmd] : SUB_NONE;
66 }
67
68 static void
69 print_common_flags(struct tcb *tcp, const struct iocb *cb)
70 {
71 /* aio_flags and aio_resfd fields are available since v2.6.22-rc1~47 */
72 #ifdef HAVE_STRUCT_IOCB_AIO_FLAGS
73         if (cb->aio_flags)
74                 PRINT_FIELD_FLAGS(", ", *cb, aio_flags, aio_iocb_flags,
75                                   "IOCB_FLAG_???");
76
77         if (cb->aio_flags & IOCB_FLAG_RESFD)
78                 PRINT_FIELD_FD(", ", *cb, aio_resfd, tcp);
79         else if (cb->aio_resfd)
80                 PRINT_FIELD_X(", ", *cb, aio_resfd);
81 #endif
82 }
83
84 static bool
85 iocb_is_valid(const struct iocb *cb)
86 {
87         return cb->aio_buf == (unsigned long) cb->aio_buf &&
88                cb->aio_nbytes == (size_t) cb->aio_nbytes &&
89                (ssize_t) cb->aio_nbytes >= 0;
90 }
91
92 static enum iocb_sub
93 print_iocb_header(struct tcb *tcp, const struct iocb *cb)
94 {
95         enum iocb_sub sub;
96
97         PRINT_FIELD_X("", *cb, aio_data);
98
99         if (cb->aio_key)
100                 PRINT_FIELD_U(", ", *cb, aio_key);
101
102         if (cb->AIO_RW_FLAGS_FIELD) {
103                 tprints(", aio_rw_flags=");
104                 printflags(rwf_flags, cb->AIO_RW_FLAGS_FIELD, "RWF_???");
105         }
106
107         tprints(", aio_lio_opcode=");
108         sub = tprint_lio_opcode(cb->aio_lio_opcode);
109
110         if (cb->aio_flags & IOCB_FLAG_IOPRIO) {
111                 tprints(", aio_reqprio=");
112                 print_ioprio(zero_extend_signed_to_ull(cb->aio_reqprio));
113         } else if (cb->aio_reqprio) {
114                 PRINT_FIELD_D(", ", *cb, aio_reqprio);
115         }
116
117         PRINT_FIELD_FD(", ", *cb, aio_fildes, tcp);
118
119         return sub;
120 }
121
122 static void
123 print_iocb(struct tcb *tcp, const struct iocb *cb)
124 {
125         tprints("{");
126
127         enum iocb_sub sub = print_iocb_header(tcp, cb);
128
129         switch (sub) {
130         case SUB_COMMON:
131                 if (cb->aio_lio_opcode == 1 && iocb_is_valid(cb)) {
132                         PRINT_FIELD_STRN(", ", *cb, aio_buf,
133                                          cb->aio_nbytes, tcp);
134                 } else {
135                         PRINT_FIELD_X(", ", *cb, aio_buf);
136                 }
137                 PRINT_FIELD_U(", ", *cb, aio_nbytes);
138                 PRINT_FIELD_D(", ", *cb, aio_offset);
139                 print_common_flags(tcp, cb);
140                 break;
141         case SUB_VECTOR:
142                 if (iocb_is_valid(cb)) {
143                         tprints(", aio_buf=");
144                         tprint_iov(tcp, cb->aio_nbytes, cb->aio_buf,
145                                    cb->aio_lio_opcode == 8
146                                    ? IOV_DECODE_STR
147                                    : IOV_DECODE_ADDR);
148                 } else {
149                         PRINT_FIELD_X(", ", *cb, aio_buf);
150                         PRINT_FIELD_U(", ", *cb, aio_nbytes);
151                 }
152                 PRINT_FIELD_D(", ", *cb, aio_offset);
153                 print_common_flags(tcp, cb);
154                 break;
155         case SUB_POLL:
156                 PRINT_FIELD_FLAGS(", ", *cb, aio_buf, pollflags, "POLL???");
157                 print_common_flags(tcp, cb);
158                 break;
159         case SUB_NONE:
160                 break;
161         }
162
163         tprints("}");
164 }
165
166 static bool
167 print_iocbp(struct tcb *tcp, void *elem_buf, size_t elem_size, void *data)
168 {
169         kernel_ulong_t addr;
170         struct iocb cb;
171
172         if (elem_size < sizeof(kernel_ulong_t)) {
173                 addr = *(unsigned int *) elem_buf;
174         } else {
175                 addr = *(kernel_ulong_t *) elem_buf;
176         }
177
178         if (!umove_or_printaddr(tcp, addr, &cb))
179                 print_iocb(tcp, &cb);
180
181         return true;
182 }
183
184 SYS_FUNC(io_submit)
185 {
186         const kernel_long_t nr =
187                 truncate_klong_to_current_wordsize(tcp->u_arg[1]);
188         const kernel_ulong_t addr = tcp->u_arg[2];
189         kernel_ulong_t iocbp;
190
191         printaddr(tcp->u_arg[0]);
192         tprintf(", %" PRI_kld ", ", nr);
193
194         if (nr < 0)
195                 printaddr(addr);
196         else
197                 print_array(tcp, addr, nr, &iocbp, current_wordsize,
198                             tfetch_mem, print_iocbp, 0);
199
200         return RVAL_DECODED;
201 }
202
203 static bool
204 print_io_event(struct tcb *tcp, void *elem_buf, size_t elem_size, void *data)
205 {
206         struct io_event *event = elem_buf;
207
208         PRINT_FIELD_X("{", *event, data);
209         PRINT_FIELD_X(", ", *event, obj);
210         PRINT_FIELD_D(", ", *event, res);
211         PRINT_FIELD_D(", ", *event, res2);
212         tprints("}");
213
214         return true;
215 }
216
217 SYS_FUNC(io_cancel)
218 {
219         if (entering(tcp)) {
220                 printaddr(tcp->u_arg[0]);
221                 tprints(", ");
222
223                 struct iocb cb;
224
225                 if (!umove_or_printaddr(tcp, tcp->u_arg[1], &cb)) {
226                         tprints("{");
227                         print_iocb_header(tcp, &cb);
228                         tprints("}");
229                 }
230                 tprints(", ");
231         } else {
232                 struct io_event event;
233
234                 if (!umove_or_printaddr(tcp, tcp->u_arg[2], &event))
235                         print_io_event(tcp, &event, sizeof(event), 0);
236         }
237         return 0;
238 }
239
240 static int
241 print_io_getevents(struct tcb *const tcp, const print_obj_by_addr_fn print_ts,
242                    const bool has_usig)
243 {
244         if (entering(tcp)) {
245                 printaddr(tcp->u_arg[0]);
246                 tprintf(", %" PRI_kld ", %" PRI_kld ", ",
247                         truncate_klong_to_current_wordsize(tcp->u_arg[1]),
248                         truncate_klong_to_current_wordsize(tcp->u_arg[2]));
249         } else {
250                 struct io_event buf;
251                 print_array(tcp, tcp->u_arg[3], tcp->u_rval, &buf, sizeof(buf),
252                             tfetch_mem, print_io_event, 0);
253                 tprints(", ");
254                 /*
255                  * Since the timeout and usig parameters are read by the kernel
256                  * on entering syscall, it has to be decoded the same way
257                  * whether the syscall has failed or not.
258                  */
259                 temporarily_clear_syserror(tcp);
260                 print_ts(tcp, tcp->u_arg[4]);
261                 if (has_usig) {
262                         tprints(", ");
263                         print_aio_sigset(tcp, tcp->u_arg[5]);
264                 }
265                 restore_cleared_syserror(tcp);
266         }
267         return 0;
268 }
269
270 #if HAVE_ARCH_TIME32_SYSCALLS
271 SYS_FUNC(io_getevents_time32)
272 {
273         return print_io_getevents(tcp, print_timespec32, false);
274 }
275 #endif
276
277 #if HAVE_ARCH_OLD_TIME64_SYSCALLS
278 SYS_FUNC(io_getevents_time64)
279 {
280         return print_io_getevents(tcp, print_timespec64, false);
281 }
282 #endif
283
284 #if HAVE_ARCH_TIME32_SYSCALLS
285 SYS_FUNC(io_pgetevents_time32)
286 {
287         return print_io_getevents(tcp, print_timespec32, true);
288 }
289 #endif
290
291 SYS_FUNC(io_pgetevents_time64)
292 {
293         return print_io_getevents(tcp, print_timespec64, true);
294 }