/
githubmirror
/
strace
Обзор
Документация
Войти
/
githubmirror
/
strace
Код
Запросы
0
Пакеты
0
Релизы
0
Аналитика
Безопасность
master
src/io_uring.c
1 885 строк
44 KB
Dmitry V. Levin
io_uring: add missing CHECK_TYPE_SIZE, use consistent style
14 июл 2026, 11:00
14 июл 2026, 11:00
dcbe0ed
Код
Авторство
О чём код?
/* * Copyright (c) 2019 Dmitry V. Levin <ldv@strace.io> * Copyright (c) 2019-2026 The strace developers. * All rights reserved. * * SPDX-License-Identifier: LGPL-2.1-or-later */ #include "defs.h" #include "kernel_time_types.h" #define UAPI_LINUX_IO_URING_H_SKIP_LINUX_TIME_TYPES_H #include <linux/io_uring.h> #include <linux/io_uring/query.h> #include "xlat/uring_async_cancel_flags.h" #include "xlat/uring_clone_buffers_flags.h" #include "xlat/uring_enter_flags.h" #include "xlat/uring_files_update_fds.h" #include "xlat/uring_iowq_acct.h" #include "xlat/uring_op_flags.h" #include "xlat/uring_ops.h" #include "xlat/uring_setup_features.h" #include "xlat/uring_setup_flags.h" #include "xlat/uring_sqe_flags.h" #include "xlat/uring_register_opcodes.h" #include "xlat/uring_register_opcode_flags.h" #include "xlat/uring_register_rsrc_flags.h" #include "xlat/uring_restriction_opcodes.h" #include "xlat/uring_napi_ops.h" #include "xlat/uring_napi_tracking_strategies.h" #include "xlat/uring_msg_ring_flags.h" #include "xlat/uring_zcrx_reg_flags.h" #include "xlat/uring_zcrx_area_flags.h" #include "xlat/uring_mem_region_reg_flags.h" #include "xlat/uring_query_ops.h" #include "xlat/uring_zcrx_ctrl_ops.h" #include "xlat/uring_zcrx_notif_types.h" #include "xlat/uring_rw_attr_flags.h" #include "xlat/uring_nop_flags.h" #include "xlat/uring_fixed_fd_flags.h" #include "xlat/uring_accept_flags.h" #include "xlat/uring_recvsend_flags.h" #include "xlat/uring_socket_ops.h" static void print_io_sqring_offsets(const struct io_sqring_offsets *const p) { tprint_struct_begin(); PRINT_FIELD_U(*p, head); tprint_struct_next(); PRINT_FIELD_U(*p, tail); tprint_struct_next(); PRINT_FIELD_U(*p, ring_mask); tprint_struct_next(); PRINT_FIELD_U(*p, ring_entries); tprint_struct_next(); PRINT_FIELD_U(*p, flags); tprint_struct_next(); PRINT_FIELD_U(*p, dropped); tprint_struct_next(); PRINT_FIELD_U(*p, array); if (p->resv1) { tprint_struct_next(); PRINT_FIELD_X(*p, resv1); } tprint_struct_next(); PRINT_FIELD_X(*p, user_addr); tprint_struct_end(); } static void print_io_cqring_offsets(const struct io_cqring_offsets *const p) { tprint_struct_begin(); PRINT_FIELD_U(*p, head); tprint_struct_next(); PRINT_FIELD_U(*p, tail); tprint_struct_next(); PRINT_FIELD_U(*p, ring_mask); tprint_struct_next(); PRINT_FIELD_U(*p, ring_entries); tprint_struct_next(); PRINT_FIELD_U(*p, overflow); tprint_struct_next(); PRINT_FIELD_U(*p, cqes); tprint_struct_next(); PRINT_FIELD_U(*p, flags); if (p->resv1) { tprint_struct_next(); PRINT_FIELD_X(*p, resv1); } tprint_struct_next(); PRINT_FIELD_X(*p, user_addr); tprint_struct_end(); } SYS_FUNC(io_uring_setup) { const uint32_t entries = tcp->u_arg[0]; const kernel_ulong_t params_addr = tcp->u_arg[1]; struct io_uring_params params; CHECK_TYPE_SIZE(params.resv, 3 * sizeof(uint32_t)); if (entering(tcp)) { /* entries */ tprints_arg_name("entries"); PRINT_VAL_U(entries); /* params */ tprints_arg_next_name("params"); if (umove_or_printaddr(tcp, params_addr, ¶ms)) return RVAL_DECODED | RVAL_FD; tprint_struct_begin(); PRINT_FIELD_FLAGS(params, flags, uring_setup_flags, "IORING_SETUP_???"); tprint_struct_next(); PRINT_FIELD_X(params, sq_thread_cpu); tprint_struct_next(); PRINT_FIELD_U(params, sq_thread_idle); if (params.flags & IORING_SETUP_ATTACH_WQ) { tprint_struct_next(); PRINT_FIELD_FD(params, wq_fd, tcp); } if (!IS_ARRAY_ZERO(params.resv)) { tprint_struct_next(); PRINT_FIELD_ARRAY(params, resv, tcp, print_xint_array_member); } return 0; } /* exiting */ if (tfetch_mem(tcp, params_addr, sizeof(params), ¶ms)) { tprint_struct_next(); PRINT_FIELD_U(params, sq_entries); tprint_struct_next(); PRINT_FIELD_U(params, cq_entries); tprint_struct_next(); PRINT_FIELD_FLAGS(params, features, uring_setup_features, "IORING_FEAT_???"); tprint_struct_next(); PRINT_FIELD_OBJ_PTR(params, sq_off, print_io_sqring_offsets); tprint_struct_next(); PRINT_FIELD_OBJ_PTR(params, cq_off, print_io_cqring_offsets); } tprint_struct_end(); return RVAL_DECODED | RVAL_FD; } static void print_io_uring_getevents_arg(struct tcb *tcp, const kernel_ulong_t addr) { struct io_uring_getevents_arg arg; CHECK_TYPE_SIZE(arg, 24); if (umove_or_printaddr(tcp, addr, &arg)) return; tprint_struct_begin(); tprints_field_name("sigmask"); print_sigset_addr_len(tcp, arg.sigmask, arg.sigmask_sz); tprint_struct_next(); PRINT_FIELD_U(arg, sigmask_sz); tprint_struct_next(); PRINT_FIELD_U(arg, min_wait_usec); tprint_struct_next(); tprints_field_name("ts"); print_timespec64(tcp, arg.ts); tprint_struct_end(); } SYS_FUNC(io_uring_enter) { const int fd = tcp->u_arg[0]; const uint32_t to_submit = tcp->u_arg[1]; const uint32_t min_complete = tcp->u_arg[2]; const uint32_t flags = tcp->u_arg[3]; const kernel_ulong_t sigset_addr = tcp->u_arg[4]; const kernel_ulong_t sigset_size = tcp->u_arg[5]; /* fd */ tprints_arg_name("fd"); printfd(tcp, fd); /* to_submit */ tprints_arg_next_name("to_submit"); PRINT_VAL_U(to_submit); /* min_complete */ tprints_arg_next_name("min_complete"); PRINT_VAL_U(min_complete); /* flags */ tprints_arg_next_name("flags"); printflags(uring_enter_flags, flags, "IORING_ENTER_???"); /* * Conditional decoding of arguments 4 and 5 based on flags. * Note: IORING_ENTER_EXT_ARG and IORING_ENTER_EXT_ARG_REG are mutually * exclusive. If both are set, kernel returns -EINVAL, but for backward * compatibility with existing tests, decode as traditional sigset. */ if ((flags & IORING_ENTER_EXT_ARG_REG) && !(flags & IORING_ENTER_EXT_ARG)) { /* * Registered wait region case: arg[4] is a byte offset, * not a pointer. */ tprints_arg_next_name("arg"); PRINT_VAL_U(sigset_addr); tprints_arg_next_name("argsz"); PRINT_VAL_U(sigset_size); } else if ((flags & IORING_ENTER_EXT_ARG) && !(flags & IORING_ENTER_EXT_ARG_REG)) { /* * Extended argument case: arg[4] is pointer to * io_uring_getevents_arg. */ tprints_arg_next_name("arg"); print_io_uring_getevents_arg(tcp, sigset_addr); tprints_arg_next_name("argsz"); PRINT_VAL_U(sigset_size); } else { /* Traditional sigset case. */ tprints_arg_next_name("sigset"); print_sigset_addr_len(tcp, sigset_addr, sigset_size); tprints_arg_next_name("sigsetsize"); PRINT_VAL_U(sigset_size); } return RVAL_DECODED; } static bool print_files_update_array_member(struct tcb *tcp, void *elem_buf, size_t elem_size, void *data) { int fd = *(int *) elem_buf; if (fd < -1) printxval_d(uring_files_update_fds, fd, NULL); else printfd(tcp, fd); return true; } static void print_io_uring_files_update(struct tcb *tcp, const kernel_ulong_t addr, const unsigned int nargs) { struct io_uring_files_update arg; int buf; if (umove_or_printaddr(tcp, addr, &arg)) return; tprint_struct_begin(); PRINT_FIELD_U(arg, offset); if (arg.resv) { tprint_struct_next(); PRINT_FIELD_X(arg, resv); } tprint_struct_next(); tprints_field_name("fds"); print_big_u64_addr(arg.fds); print_array(tcp, arg.fds, nargs, &buf, sizeof(buf), tfetch_mem, print_files_update_array_member, NULL); tprint_struct_end(); } static bool print_io_uring_probe_op(struct tcb *tcp, void *elem_buf, size_t elem_size, void *data) { struct io_uring_probe_op *op = (struct io_uring_probe_op *) elem_buf; tprint_struct_begin(); PRINT_FIELD_XVAL_U(*op, op, uring_ops, "IORING_OP_???"); if (op->resv) { tprint_struct_next(); PRINT_FIELD_X(*op, resv); } tprint_struct_next(); PRINT_FIELD_FLAGS(*op, flags, uring_op_flags, "IO_URING_OP_???"); if (op->resv2) { tprint_struct_next(); PRINT_FIELD_X(*op, resv2); } tprint_struct_end(); return true; } static int print_io_uring_probe(struct tcb *tcp, const kernel_ulong_t addr, const unsigned int nargs) { struct io_uring_probe *probe; CHECK_TYPE_SIZE(*probe, 16); CHECK_TYPE_SIZE(probe->resv2, 3 * sizeof(uint32_t)); unsigned long printed = exiting(tcp) ? get_tcb_priv_ulong(tcp) : false; if (exiting(tcp) && syserror(tcp)) { if (!printed) printaddr(addr); return RVAL_DECODED; } if (nargs > 256) { printaddr(addr); return RVAL_DECODED; } if (printed) tprint_value_changed(); /* Maximum size is 8 * 256 + 16, a bit over 4k */ size_t probe_sz = sizeof(probe->ops[0]) * nargs + sizeof(*probe); probe = alloca(probe_sz); /* * So far, the operation doesn't use any data from the arg provided, * but it checks that it is filled with zeroes. */ if (umoven_or_printaddr(tcp, addr, probe_sz, probe)) return RVAL_DECODED; if (entering(tcp) && is_filled((const char *) probe, 0, probe_sz)) return 0; set_tcb_priv_ulong(tcp, true); tprint_struct_begin(); PRINT_FIELD_XVAL_U(*probe, last_op, uring_ops, "IORING_OP_???"); tprint_struct_next(); PRINT_FIELD_U(*probe, ops_len); if (probe->resv) { tprint_struct_next(); PRINT_FIELD_X(*probe, resv); } if (!IS_ARRAY_ZERO(probe->resv2)) { tprint_struct_next(); PRINT_FIELD_ARRAY(*probe, resv2, tcp, print_xint_array_member); } tprint_struct_next(); PRINT_FIELD_OBJ_TCB_VAL(*probe, ops, tcp, print_local_array_ex, entering(tcp) ? nargs : MIN(probe->ops_len, nargs), sizeof(probe->ops[0]), print_io_uring_probe_op, NULL, exiting(tcp) && (nargs < probe->ops_len) ? PAF_ARRAY_TRUNCATED : 0, NULL, NULL); tprint_struct_end(); return 0; } static bool print_io_uring_restriction(struct tcb *tcp, void *elem_buf, size_t elem_size, void *data) { struct io_uring_restriction *r = (struct io_uring_restriction *) elem_buf; CHECK_TYPE_SIZE(*r, 16); CHECK_TYPE_SIZE(r->resv2, 12); tprint_struct_begin(); PRINT_FIELD_XVAL(*r, opcode, uring_restriction_opcodes, "IORING_RESTRICTION_???"); switch (r->opcode) { case IORING_RESTRICTION_REGISTER_OP: tprint_struct_next(); PRINT_FIELD_XVAL(*r, register_op, uring_register_opcodes, "IORING_REGISTER_???"); break; case IORING_RESTRICTION_SQE_OP: tprint_struct_next(); PRINT_FIELD_XVAL(*r, sqe_op, uring_ops, "IORING_OP_???"); break; case IORING_RESTRICTION_SQE_FLAGS_ALLOWED: case IORING_RESTRICTION_SQE_FLAGS_REQUIRED: tprint_struct_next(); PRINT_FIELD_FLAGS(*r, sqe_flags, uring_sqe_flags, "IOSQE_???"); break; default: tprintf_comment("op: %#x", r->register_op); } if (r->resv) { tprint_struct_next(); PRINT_FIELD_X(*r, resv); } if (!IS_ARRAY_ZERO(r->resv2)) { tprint_struct_next(); PRINT_FIELD_ARRAY(*r, resv2, tcp, print_xint_array_member); } tprint_struct_end(); return true; } static void print_io_uring_restrictions(struct tcb *tcp, const kernel_ulong_t addr, const unsigned int nargs) { struct io_uring_restriction buf; print_array(tcp, addr, nargs, &buf, sizeof(buf), tfetch_mem, print_io_uring_restriction, NULL); } static void print_io_uring_rsrc_data(struct tcb *tcp, const uint64_t data, const unsigned int nr, const unsigned int opcode) { int fd_buf; switch (opcode) { case IORING_REGISTER_FILES2: case IORING_REGISTER_BUFFERS2: case IORING_REGISTER_BUFFERS_UPDATE: case IORING_REGISTER_FILES_UPDATE2: tprint_struct_next(); tprints_field_name("data"); print_big_u64_addr(data); break; } switch (opcode) { case IORING_REGISTER_FILES2: print_array(tcp, data, nr, &fd_buf, sizeof(fd_buf), tfetch_mem, print_fd_array_member, NULL); break; case IORING_REGISTER_FILES_UPDATE2: print_array(tcp, data, nr, &fd_buf, sizeof(fd_buf), tfetch_mem, print_files_update_array_member, NULL); break; case IORING_REGISTER_BUFFERS2: case IORING_REGISTER_BUFFERS_UPDATE: tprint_iov(tcp, nr, data, iov_decode_addr); break; } } static void print_io_uring_rsrc_tags(struct tcb *tcp, const uint64_t tags, const unsigned int nr) { uint64_t tag_buf; tprint_struct_next(); tprints_field_name("tags"); print_big_u64_addr(tags); print_array(tcp, tags, nr, &tag_buf, sizeof(tag_buf), tfetch_mem, print_xint_array_member, NULL); } static void print_io_uring_register_rsrc(struct tcb *tcp, const kernel_ulong_t addr, const unsigned int size, const unsigned int opcode) { struct io_uring_rsrc_register arg; CHECK_TYPE_SIZE(arg, 32); CHECK_TYPE_SIZE(arg.resv2, sizeof(uint64_t)); if (size < 32) { printaddr(addr); return; } if (umove_or_printaddr(tcp, addr, &arg)) return; tprint_struct_begin(); PRINT_FIELD_U(arg, nr); tprint_struct_next(); PRINT_FIELD_FLAGS(arg, flags, uring_register_rsrc_flags, "IORING_RSRC_REGISTER_???"); if (arg.resv2) { tprint_struct_next(); PRINT_FIELD_X(arg, resv2); } print_io_uring_rsrc_data(tcp, arg.data, arg.nr, opcode); print_io_uring_rsrc_tags(tcp, arg.tags, arg.nr); if (size > sizeof(arg)) { print_nonzero_bytes(tcp, tprint_struct_next, addr, sizeof(arg), MIN(size, get_pagesize()), QUOTE_FORCE_HEX); } tprint_struct_end(); } static void print_io_uring_update_rsrc(struct tcb *tcp, const kernel_ulong_t addr, const unsigned int size, const unsigned int opcode) { struct io_uring_rsrc_update2 arg; CHECK_TYPE_SIZE(arg, 32); CHECK_TYPE_SIZE(arg.resv, sizeof(uint32_t)); CHECK_TYPE_SIZE(arg.resv2, sizeof(uint32_t)); if (size < 32) { printaddr(addr); return; } if (umove_or_printaddr(tcp, addr, &arg)) return; tprint_struct_begin(); PRINT_FIELD_U(arg, offset); if (arg.resv) { tprint_struct_next(); PRINT_FIELD_X(arg, resv); } print_io_uring_rsrc_data(tcp, arg.data, arg.nr, opcode); print_io_uring_rsrc_tags(tcp, arg.tags, arg.nr); tprint_struct_next(); PRINT_FIELD_U(arg, nr); if (arg.resv2) { tprint_struct_next(); PRINT_FIELD_X(arg, resv2); } if (size > sizeof(arg)) { print_nonzero_bytes(tcp, tprint_struct_next, addr, sizeof(arg), MIN(size, get_pagesize()), QUOTE_FORCE_HEX); } tprint_struct_end(); } static int print_io_uring_iowq_acct(struct tcb *tcp, const kernel_ulong_t addr, const unsigned int nargs) { uint32_t val; bool ret = print_array_ex(tcp, addr, nargs, &val, sizeof(val), tfetch_mem, print_uint_array_member, NULL, PAF_PRINT_INDICES | XLAT_STYLE_FMT_U, uring_iowq_acct, "IO_WQ_???"); return ret ? 0 : RVAL_DECODED; } static bool print_ringfd_register_array_member(struct tcb *tcp, void *buf, size_t elem_size, void *data) { /* offset - offset to insert at or -1 for the first free place */ /* resv - reserved */ /* data - FD to register */ struct io_uring_rsrc_update *elem = buf; tprint_struct_begin(); if (elem->offset == -1U) PRINT_FIELD_D(*elem, offset); else PRINT_FIELD_U(*elem, offset); if (elem->resv) { tprint_struct_next(); PRINT_FIELD_X(*elem, resv); } tprint_struct_next(); PRINT_FIELD_FD(*elem, data, tcp); tprint_struct_end(); return true; } static void print_io_uring_ringfds_register(struct tcb *tcp, const kernel_ulong_t arg, const unsigned int nargs) { struct io_uring_rsrc_update buf; CHECK_TYPE_SIZE(buf, 16); CHECK_TYPE_SIZE(buf.resv, sizeof(uint32_t)); print_array(tcp, arg, nargs, &buf, sizeof(buf), tfetch_mem, print_ringfd_register_array_member, NULL); } static bool print_ringfd_unregister_array_member(struct tcb *tcp, void *buf, size_t elem_size, void *data) { /* offset - offset to unregister FD */ /* resv - reserved */ /* data - unused */ struct io_uring_rsrc_update *elem = buf; tprint_struct_begin(); PRINT_FIELD_U(*elem, offset); if (elem->resv) { tprint_struct_next(); PRINT_FIELD_X(*elem, resv); } if (elem->data) { tprint_struct_next(); PRINT_FIELD_X(*elem, data); } tprint_struct_end(); return true; } static void print_io_uring_ringfds_unregister(struct tcb *tcp, const kernel_ulong_t arg, const unsigned int nargs) { struct io_uring_rsrc_update buf; print_array(tcp, arg, nargs, &buf, sizeof(buf), tfetch_mem, print_ringfd_unregister_array_member, NULL); } static void print_io_uring_buf_reg(struct tcb *tcp, const kernel_ulong_t addr, const unsigned int nargs) { struct io_uring_buf_reg arg; CHECK_TYPE_SIZE(arg, 40); CHECK_TYPE_SIZE(arg.flags, sizeof(uint16_t)); CHECK_TYPE_SIZE(arg.min_left, sizeof(uint32_t)); CHECK_TYPE_SIZE(arg.resv, sizeof(uint32_t) * 5); if (nargs != 1) { printaddr(addr); return; } if (umove_or_printaddr(tcp, addr, &arg)) return; tprint_struct_begin(); PRINT_FIELD_ADDR64(arg, ring_addr); tprint_struct_next(); PRINT_FIELD_U(arg, ring_entries); tprint_struct_next(); PRINT_FIELD_U(arg, bgid); tprint_struct_next(); PRINT_FIELD_X(arg, flags); tprint_struct_next(); PRINT_FIELD_U(arg, min_left); if (!IS_ARRAY_ZERO(arg.resv)) { tprint_struct_next(); PRINT_FIELD_ARRAY(arg, resv, tcp, print_xint_array_member); } tprint_struct_end(); } static void print_io_uring_sync_cancel_reg(struct tcb *tcp, const kernel_ulong_t addr, const unsigned int nargs) { struct io_uring_sync_cancel_reg arg; CHECK_TYPE_SIZE(arg, 64); CHECK_TYPE_SIZE(arg.pad, 7 * sizeof(uint8_t)); CHECK_TYPE_SIZE(arg.pad2, 3 * sizeof(uint64_t)); if (nargs != 1) { printaddr(addr); return; } if (umove_or_printaddr(tcp, addr, &arg)) return; tprint_struct_begin(); PRINT_FIELD_ADDR64(arg, addr); tprint_struct_next(); PRINT_FIELD_FD(arg, fd, tcp); tprint_struct_next(); PRINT_FIELD_FLAGS(arg, flags, uring_async_cancel_flags, "IORING_ASYNC_CANCEL_???"); tprint_struct_next(); tprints_field_name("timeout"); tprint_struct_begin(); PRINT_FIELD_D(arg.timeout, tv_sec); tprint_struct_next(); PRINT_FIELD_D(arg.timeout, tv_nsec); tprint_struct_end(); tprint_struct_next(); PRINT_FIELD_XVAL(arg, opcode, uring_ops, "IORING_OP_???"); if (!IS_ARRAY_ZERO(arg.pad)) { tprint_struct_next(); PRINT_FIELD_ARRAY(arg, pad, tcp, print_xint_array_member); } if (!IS_ARRAY_ZERO(arg.pad2)) { tprint_struct_next(); PRINT_FIELD_ARRAY(arg, pad2, tcp, print_xint_array_member); } tprint_struct_end(); } static void print_io_uring_file_index_range(struct tcb *tcp, const kernel_ulong_t addr, const unsigned int nargs) { struct io_uring_file_index_range arg; if (nargs != 1) { printaddr(addr); return; } if (umove_or_printaddr(tcp, addr, &arg)) return; tprint_struct_begin(); PRINT_FIELD_U(arg, off); tprint_struct_next(); PRINT_FIELD_U(arg, len); if (arg.resv) { tprint_struct_next(); PRINT_FIELD_X(arg, resv); } tprint_struct_end(); } static int print_io_uring_buf_status(struct tcb *tcp, const kernel_ulong_t addr, const unsigned int nargs) { struct io_uring_buf_status arg; CHECK_TYPE_SIZE(arg, 40); CHECK_TYPE_SIZE(arg.resv, 8 * sizeof(uint32_t)); if (nargs != 1) { printaddr(addr); return RVAL_DECODED; } if (entering(tcp)) return 0; if (umove_or_printaddr(tcp, addr, &arg)) return RVAL_DECODED; tprint_struct_begin(); PRINT_FIELD_X(arg, buf_group); tprint_struct_next(); PRINT_FIELD_X(arg, head); if (!IS_ARRAY_ZERO(arg.resv)) { tprint_struct_next(); PRINT_FIELD_ARRAY(arg, resv, tcp, print_xint_array_member); } tprint_struct_end(); return RVAL_DECODED; } static int print_io_uring_napi(struct tcb *tcp, const kernel_ulong_t addr) { struct io_uring_napi arg; CHECK_TYPE_SIZE(arg, 16); CHECK_TYPE_SIZE(arg.pad, 2 * sizeof(uint8_t)); if (umove_or_printaddr(tcp, addr, &arg)) return RVAL_DECODED; tprint_struct_begin(); PRINT_FIELD_X(arg, busy_poll_to); tprint_struct_next(); PRINT_FIELD_X(arg, prefer_busy_poll); tprint_struct_next(); PRINT_FIELD_XVAL(arg, opcode, uring_napi_ops, "IO_URING_NAPI_???"); if (!IS_ARRAY_ZERO(arg.pad)) { tprint_struct_next(); PRINT_FIELD_ARRAY(arg, pad, tcp, print_xint_array_member); } tprint_struct_next(); if (arg.opcode == IO_URING_NAPI_REGISTER_OP) PRINT_FIELD_XVAL(arg, op_param, uring_napi_tracking_strategies, "IO_URING_NAPI_TRACKING_???"); else PRINT_FIELD_X(arg, op_param); if (arg.resv) { tprint_struct_next(); PRINT_FIELD_X(arg, resv); } tprint_struct_end(); return 0; } static int print_ioring_register_napi(struct tcb *tcp, const kernel_ulong_t addr, const unsigned int nargs) { if (exiting(tcp)) { if (syserror(tcp)) return 0; tprint_value_changed(); } if (nargs != 1) { printaddr(addr); return RVAL_DECODED; } return print_io_uring_napi(tcp, addr); } static int print_ioring_unregister_napi(struct tcb *tcp, const kernel_ulong_t addr, const unsigned int nargs) { if (nargs != 1) { printaddr(addr); return RVAL_DECODED; } if (entering(tcp)) return 0; print_io_uring_napi(tcp, addr); return RVAL_DECODED; } static void print_io_uring_clock_register(struct tcb *tcp, const kernel_ulong_t addr) { struct io_uring_clock_register arg; CHECK_TYPE_SIZE(arg, 16); CHECK_TYPE_SIZE(arg.__resv, 3 * sizeof(uint32_t)); if (umove_or_printaddr(tcp, addr, &arg)) return; tprint_struct_begin(); PRINT_FIELD_XVAL(arg, clockid, clocknames, "CLOCK_???"); if (!IS_ARRAY_ZERO(arg.__resv)) { tprint_struct_next(); PRINT_FIELD_ARRAY(arg, __resv, tcp, print_xint_array_member); } tprint_struct_end(); } static int print_ioring_register_clock(struct tcb *tcp, const kernel_ulong_t addr, const unsigned int nargs) { if (nargs == 0) print_io_uring_clock_register(tcp, addr); else printaddr(addr); return RVAL_DECODED; } static void print_io_uring_clone_buffers(struct tcb *tcp, const kernel_ulong_t addr) { struct io_uring_clone_buffers arg; CHECK_TYPE_SIZE(arg, 32); CHECK_TYPE_SIZE(arg.pad, 3 * sizeof(uint32_t)); if (umove_or_printaddr(tcp, addr, &arg)) return; tprint_struct_begin(); PRINT_FIELD_FD(arg, src_fd, tcp); tprint_struct_next(); PRINT_FIELD_FLAGS(arg, flags, uring_clone_buffers_flags, "IORING_REGISTER_???"); tprint_struct_next(); PRINT_FIELD_U(arg, src_off); tprint_struct_next(); PRINT_FIELD_U(arg, dst_off); tprint_struct_next(); PRINT_FIELD_U(arg, nr); if (!IS_ARRAY_ZERO(arg.pad)) { tprint_struct_next(); PRINT_FIELD_ARRAY(arg, pad, tcp, print_xint_array_member); } tprint_struct_end(); } static int print_ioring_register_clone_buffers(struct tcb *tcp, const kernel_ulong_t addr, const unsigned int nargs) { if (nargs == 1) print_io_uring_clone_buffers(tcp, addr); else printaddr(addr); return RVAL_DECODED; } static void print_io_uring_attr_pi(struct tcb *tcp, const uint64_t addr) { struct io_uring_attr_pi attr; CHECK_TYPE_SIZE(attr, 32); if (umove_or_printaddr64(tcp, addr, &attr)) return; tprint_struct_begin(); PRINT_FIELD_X(attr, flags); tprint_struct_next(); PRINT_FIELD_X(attr, app_tag); tprint_struct_next(); PRINT_FIELD_U(attr, len); tprint_struct_next(); PRINT_FIELD_X(attr, addr); tprint_struct_next(); PRINT_FIELD_X(attr, seed); tprint_struct_next(); PRINT_FIELD_X(attr, rsvd); tprint_struct_end(); } static void print_io_uring_attr_ptr(struct tcb *tcp, const uint64_t addr, unsigned long attr_type_mask) { if (attr_type_mask & IORING_RW_ATTR_FLAG_PI) { /* Decode as io_uring_attr_pi structure. */ print_io_uring_attr_pi(tcp, addr); } else { printaddr64(addr); } } static void print_io_uring_sqe_flags_union(const struct io_uring_sqe *sqe) { switch (sqe->opcode) { case IORING_OP_NOP: case IORING_OP_NOP128: PRINT_FIELD_FLAGS(*sqe, nop_flags, uring_nop_flags, "IORING_NOP_???"); break; case IORING_OP_FIXED_FD_INSTALL: PRINT_FIELD_FLAGS(*sqe, install_fd_flags, uring_fixed_fd_flags, "IORING_FIXED_FD_???"); break; case IORING_OP_MSG_RING: PRINT_FIELD_FLAGS(*sqe, msg_ring_flags, uring_msg_ring_flags, "IORING_MSG_RING_???"); break; case IORING_OP_PIPE: /* * PIPE flags are in the union, but no flags are currently * defined in the kernel header. Fall through to default * to print as hex (same as rw_flags since they're in the * same union). */ ATTRIBUTE_FALLTHROUGH; default: /* * For other opcodes, use rw_flags (default). */ PRINT_FIELD_X(*sqe, rw_flags); break; } } static void print_io_uring_sqe_ioprio(const struct io_uring_sqe *sqe) { switch (sqe->opcode) { case IORING_OP_ACCEPT: /* * For accept operations, ioprio contains flags. */ PRINT_FIELD_FLAGS(*sqe, ioprio, uring_accept_flags, "IORING_ACCEPT_???"); break; case IORING_OP_SEND: case IORING_OP_SENDMSG: case IORING_OP_SEND_ZC: case IORING_OP_SENDMSG_ZC: case IORING_OP_RECV: case IORING_OP_RECVMSG: case IORING_OP_RECV_ZC: /* * For send/recv operations, ioprio contains flags. */ PRINT_FIELD_FLAGS(*sqe, ioprio, uring_recvsend_flags, "IORING_RECVSEND_???"); break; default: /* * For other operations, ioprio contains the actual * ioprio value. */ PRINT_FIELD_U(*sqe, ioprio); break; } } static bool is_128_byte_sqe(const struct io_uring_sqe *sqe) { switch (sqe->opcode) { case IORING_OP_NOP128: case IORING_OP_URING_CMD128: return true; default: return false; } } static bool is_op_cmd_sqe(const struct io_uring_sqe *sqe) { switch (sqe->opcode) { case IORING_OP_URING_CMD: case IORING_OP_URING_CMD128: return true; default: return false; } } static void print_io_uring_sqe_off(struct tcb *tcp, const struct io_uring_sqe *sqe) { if (is_op_cmd_sqe(sqe) && getfdinode(tcp, sqe->fd)) { /* * For IORING_OP_URING_CMD or IORING_OP_URING_CMD128 with * a socket fd, print off as a socket operation. */ PRINT_FIELD_XVAL_U(*sqe, off, uring_socket_ops, "SOCKET_URING_OP_???"); } else { /* Not a socket or not URING_CMD/URING_CMD128, print as offset */ PRINT_FIELD_X(*sqe, off); } } static void print_io_uring_sqe(struct tcb *tcp, const kernel_ulong_t addr) { struct io_uring_sqe sqe; CHECK_TYPE_SIZE(sqe, 64); if (umove_or_printaddr(tcp, addr, &sqe)) return; tprint_struct_begin(); PRINT_FIELD_XVAL_U(sqe, opcode, uring_ops, "IORING_OP_???"); tprint_struct_next(); PRINT_FIELD_FLAGS(sqe, flags, uring_sqe_flags, "IOSQE_???"); tprint_struct_next(); print_io_uring_sqe_ioprio(&sqe); tprint_struct_next(); PRINT_FIELD_FD(sqe, fd, tcp); tprint_struct_next(); print_io_uring_sqe_off(tcp, &sqe); tprint_struct_next(); PRINT_FIELD_X(sqe, addr); tprint_struct_next(); PRINT_FIELD_U(sqe, len); tprint_struct_next(); print_io_uring_sqe_flags_union(&sqe); tprint_struct_next(); PRINT_FIELD_X(sqe, user_data); tprint_struct_next(); PRINT_FIELD_X(sqe, buf_index); tprint_struct_next(); PRINT_FIELD_U(sqe, personality); tprint_struct_next(); PRINT_FIELD_X(sqe, file_index); tprint_struct_next(); /* * Decode union field based on opcode and attr_type_mask. * Note: attr_type_mask/attr_ptr and optval are in the same union. * attr_type_mask is only used for RW operations that call __io_prep_rw. */ switch (sqe.opcode) { case IORING_OP_READ: case IORING_OP_WRITE: case IORING_OP_READV: case IORING_OP_WRITEV: case IORING_OP_READ_FIXED: case IORING_OP_WRITE_FIXED: case IORING_OP_READV_FIXED: case IORING_OP_WRITEV_FIXED: case IORING_OP_SEND: case IORING_OP_RECV: case IORING_OP_SENDMSG: case IORING_OP_RECVMSG: case IORING_OP_SEND_ZC: case IORING_OP_RECV_ZC: case IORING_OP_READ_MULTISHOT: /* * RW operations with attr_type_mask set use attr_ptr/attr_type_mask. */ if (sqe.attr_type_mask) { PRINT_FIELD_FLAGS(sqe, attr_type_mask, uring_rw_attr_flags, "IORING_RW_ATTR_FLAG_???"); tprint_struct_next(); PRINT_FIELD_OBJ_TCB_VAL(sqe, attr_ptr, tcp, print_io_uring_attr_ptr, sqe.attr_type_mask); break; } /* RW operations without attr_type_mask fall through to optval. */ ATTRIBUTE_FALLTHROUGH; default: /* * For non-RW operations or RW operations without attr_type_mask, * decode as optval (backward compatible). */ tprints_field_name("optval"); PRINT_VAL_X(sqe.optval); break; } /* * For 128-byte SQEs, decode the cmd[] array (64 bytes starting * at offset 64). * * Error handling: If reading the cmd[] array fails, print_array * will print the address gracefully. The base 64-byte structure * is already decoded, so cmd[] failure doesn't affect it. * print_array with tfetch_mem handles partial reads gracefully, * printing what it can if only partial data is available. */ if (is_128_byte_sqe(&sqe)) { const kernel_ulong_t cmd_addr = addr + 64; uint8_t cmd_buf; tprint_struct_next(); tprints_field_name("cmd"); print_array(tcp, cmd_addr, 64, &cmd_buf, sizeof(cmd_buf), tfetch_mem, print_xint_array_member, NULL); } tprint_struct_end(); } static int print_ioring_register_send_msg_ring(struct tcb *tcp, const kernel_ulong_t addr, const unsigned int nargs) { if (nargs == 1) print_io_uring_sqe(tcp, addr); else printaddr(addr); return RVAL_DECODED; } static void print_io_uring_zcrx_offsets(struct tcb *tcp, const struct io_uring_zcrx_offsets *const offsets) { CHECK_TYPE_SIZE(*offsets, 32); CHECK_TYPE_SIZE(offsets->__resv, 2 * sizeof(uint64_t)); tprint_struct_begin(); PRINT_FIELD_U(*offsets, head); tprint_struct_next(); PRINT_FIELD_U(*offsets, tail); tprint_struct_next(); PRINT_FIELD_U(*offsets, rqes); if (offsets->__resv2) { tprint_struct_next(); PRINT_FIELD_X(*offsets, __resv2); } if (!IS_ARRAY_ZERO(offsets->__resv)) { tprint_struct_next(); PRINT_FIELD_ARRAY(*offsets, __resv, tcp, print_xint_array_member); } tprint_struct_end(); } static void print_io_uring_zcrx_ifq_reg(struct tcb *tcp, const kernel_ulong_t addr) { struct io_uring_zcrx_ifq_reg arg; CHECK_TYPE_SIZE(arg, 96); CHECK_TYPE_SIZE(arg.__resv, sizeof(uint64_t) * 2); if (umove_or_printaddr(tcp, addr, &arg)) return; tprint_struct_begin(); PRINT_FIELD_U(arg, if_idx); tprint_struct_next(); PRINT_FIELD_U(arg, if_rxq); tprint_struct_next(); PRINT_FIELD_U(arg, rq_entries); tprint_struct_next(); PRINT_FIELD_FLAGS(arg, flags, uring_zcrx_reg_flags, "ZCRX_REG_???"); tprint_struct_next(); PRINT_FIELD_ADDR64(arg, area_ptr); tprint_struct_next(); PRINT_FIELD_ADDR64(arg, region_ptr); tprint_struct_next(); tprints_field_name("offsets"); print_io_uring_zcrx_offsets(tcp, &arg.offsets); tprint_struct_next(); PRINT_FIELD_U(arg, zcrx_id); tprint_struct_next(); PRINT_FIELD_U(arg, rx_buf_len); tprint_struct_next(); PRINT_FIELD_ADDR64(arg, notif_desc); if (!IS_ARRAY_ZERO(arg.__resv)) { tprint_struct_next(); PRINT_FIELD_ARRAY(arg, __resv, tcp, print_xint_array_member); } tprint_struct_end(); } static int print_ioring_register_zcrx_ifq(struct tcb *tcp, const kernel_ulong_t addr, const unsigned int nargs) { if (nargs == 1) print_io_uring_zcrx_ifq_reg(tcp, addr); else printaddr(addr); return RVAL_DECODED; } static void print_zcrx_ctrl_flush_rq(struct tcb *tcp, const struct zcrx_ctrl_flush_rq *const flush) { CHECK_TYPE_SIZE(*flush, 6 * sizeof(uint64_t)); CHECK_TYPE_SIZE(flush->__resv, 6 * sizeof(uint64_t)); tprint_struct_begin(); /* All fields are reserved, only print if non-zero */ if (!IS_ARRAY_ZERO(flush->__resv)) { PRINT_FIELD_ARRAY(*flush, __resv, tcp, print_xint_array_member); } tprint_struct_end(); } static void print_zcrx_ctrl_export(struct tcb *tcp, const struct zcrx_ctrl_export *const export) { CHECK_TYPE_SIZE(*export, 12 * sizeof(uint32_t)); CHECK_TYPE_SIZE(export->__resv1, 11 * sizeof(uint32_t)); tprint_struct_begin(); /* zcrx_fd is an output field: kernel fills it with new fd on output */ PRINT_FIELD_FD(*export, zcrx_fd, tcp); /* Reserved fields only printed if non-zero */ if (!IS_ARRAY_ZERO(export->__resv1)) { tprint_struct_next(); PRINT_FIELD_ARRAY(*export, __resv1, tcp, print_xint_array_member); } tprint_struct_end(); } static void print_zcrx_ctrl_arm_notif(struct tcb *tcp, const struct zcrx_ctrl_arm_notif *const arm) { CHECK_TYPE_SIZE(*arm, 12 * sizeof(uint32_t)); CHECK_TYPE_SIZE(arm->__resv, 11 * sizeof(uint32_t)); tprint_struct_begin(); PRINT_FIELD_XVAL(*arm, notif_type, uring_zcrx_notif_types, "ZCRX_NOTIF_???"); if (!IS_ARRAY_ZERO(arm->__resv)) { tprint_struct_next(); PRINT_FIELD_ARRAY(*arm, __resv, tcp, print_xint_array_member); } tprint_struct_end(); } static int print_io_uring_zcrx_ctrl(struct tcb *tcp, const kernel_ulong_t addr) { struct zcrx_ctrl arg; CHECK_TYPE_SIZE(arg, 72); CHECK_TYPE_SIZE(arg.__resv, 2 * sizeof(uint64_t)); if (exiting(tcp)) { /* * We only get here if op == ZCRX_CTRL_EXPORT, * other ops return RVAL_DECODED on entry. */ if (tfetch_obj(tcp, addr, &arg)) { tprint_struct_next(); tprints_field_name("zc_export"); print_zcrx_ctrl_export(tcp, &arg.zc_export); } tprint_struct_end(); return RVAL_DECODED; } /* On entry, print input fields */ /* Copy structure from tracee's memory */ if (umove_or_printaddr(tcp, addr, &arg)) return RVAL_DECODED; /* Invalid address, already printed */ /* On entry, print input fields */ tprint_struct_begin(); /* zcrx_id: ZCRX resource identifier */ PRINT_FIELD_U(arg, zcrx_id); /* op: Control operation type */ tprint_struct_next(); PRINT_FIELD_XVAL(arg, op, uring_zcrx_ctrl_ops, "ZCRX_CTRL_???"); /* If op is unknown, prints as hex with "ZCRX_CTRL_???" fallback */ /* Reserved fields: only print if non-zero */ if (!IS_ARRAY_ZERO(arg.__resv)) { tprint_struct_next(); PRINT_FIELD_ARRAY(arg, __resv, tcp, print_xint_array_member); } /* Union member: decode based on op value */ switch (arg.op) { case ZCRX_CTRL_FLUSH_RQ: tprint_struct_next(); tprints_field_name("zc_flush"); print_zcrx_ctrl_flush_rq(tcp, &arg.zc_flush); /* No output fields, nothing to decode on exit */ tprint_struct_end(); return RVAL_DECODED; case ZCRX_CTRL_EXPORT: /* On entry, skip zc_export (zcrx_fd is 0, no meaningful input) */ /* Don't close structure - it will be closed on exit after adding zc_export */ /* Return 0 to indicate we need to decode on exit */ return 0; case ZCRX_CTRL_ARM_NOTIFICATION: tprint_struct_next(); tprints_field_name("zc_arm_notif"); print_zcrx_ctrl_arm_notif(tcp, &arg.zc_arm_notif); tprint_struct_end(); return RVAL_DECODED; default: /* Unknown opcode - skip union printing */ tprint_struct_end(); /* Unknown opcode, no output fields to decode on exit */ return RVAL_DECODED; } } static int print_ioring_register_zcrx_ctrl(struct tcb *tcp, const kernel_ulong_t addr, const unsigned int nargs) { if (nargs != 1) { printaddr(addr); /* Invalid nargs, just print address */ return RVAL_DECODED; } return print_io_uring_zcrx_ctrl(tcp, addr); } static void print_io_uring_params_input(struct tcb *tcp, const kernel_ulong_t addr) { struct io_uring_params params; CHECK_TYPE_SIZE(params, 120); CHECK_TYPE_SIZE(params.resv, 3 * sizeof(uint32_t)); if (umove_or_printaddr(tcp, addr, ¶ms)) return; tprint_struct_begin(); PRINT_FIELD_U(params, sq_entries); tprint_struct_next(); PRINT_FIELD_U(params, cq_entries); tprint_struct_next(); PRINT_FIELD_FLAGS(params, flags, uring_setup_flags, "IORING_SETUP_???"); /* Print user_addr fields if non-zero (only meaningful if * IORING_SETUP_NO_MMAP was set during original io_uring_setup(), * but we can't know that from the register call alone) */ if (params.sq_off.user_addr) { tprint_struct_next(); tprints_field_name("sq_off"); tprint_struct_begin(); PRINT_FIELD_X(params.sq_off, user_addr); tprint_struct_end(); } if (params.cq_off.user_addr) { tprint_struct_next(); tprints_field_name("cq_off"); tprint_struct_begin(); PRINT_FIELD_X(params.cq_off, user_addr); tprint_struct_end(); } if (!IS_ARRAY_ZERO(params.resv)) { tprint_struct_next(); PRINT_FIELD_ARRAY(params, resv, tcp, print_xint_array_member); } tprint_struct_end(); } static int print_ioring_register_resize_rings(struct tcb *tcp, const kernel_ulong_t addr, const unsigned int nargs) { if (nargs == 1) print_io_uring_params_input(tcp, addr); else printaddr(addr); return RVAL_DECODED; } static void print_io_uring_mem_region_reg(struct tcb *tcp, const kernel_ulong_t addr) { struct io_uring_mem_region_reg arg; CHECK_TYPE_SIZE(arg, 32); CHECK_TYPE_SIZE(arg.__resv, 2 * sizeof(uint64_t)); if (umove_or_printaddr(tcp, addr, &arg)) return; tprint_struct_begin(); PRINT_FIELD_ADDR64(arg, region_uptr); tprint_struct_next(); PRINT_FIELD_FLAGS(arg, flags, uring_mem_region_reg_flags, "IORING_MEM_REGION_REG_???"); if (!IS_ARRAY_ZERO(arg.__resv)) { tprint_struct_next(); PRINT_FIELD_ARRAY(arg, __resv, tcp, print_xint_array_member); } tprint_struct_end(); } static int print_ioring_register_mem_region(struct tcb *tcp, const kernel_ulong_t addr, const unsigned int nargs) { if (nargs == 1) print_io_uring_mem_region_reg(tcp, addr); else printaddr(addr); return RVAL_DECODED; } static void print_io_uring_query_opcode(struct tcb *tcp, const kernel_ulong_t addr) { struct io_uring_query_opcode opcode; CHECK_TYPE_SIZE(opcode, 48); if (umove_or_printaddr(tcp, addr, &opcode)) return; tprint_struct_begin(); PRINT_FIELD_U(opcode, nr_request_opcodes); tprint_struct_next(); PRINT_FIELD_U(opcode, nr_register_opcodes); tprint_struct_next(); PRINT_FIELD_FLAGS(opcode, feature_flags, uring_setup_features, "IORING_FEAT_???"); tprint_struct_next(); PRINT_FIELD_FLAGS(opcode, ring_setup_flags, uring_setup_flags, "IORING_SETUP_???"); tprint_struct_next(); PRINT_FIELD_FLAGS(opcode, enter_flags, uring_enter_flags, "IORING_ENTER_???"); tprint_struct_next(); PRINT_FIELD_FLAGS(opcode, sqe_flags, uring_sqe_flags, "IOSQE_???"); tprint_struct_next(); PRINT_FIELD_U(opcode, nr_query_opcodes); if (opcode.__pad) { tprint_struct_next(); PRINT_FIELD_X(opcode, __pad); } tprint_struct_end(); } static void print_io_uring_query_zcrx(struct tcb *tcp, const kernel_ulong_t addr) { struct io_uring_query_zcrx zcrx; CHECK_TYPE_SIZE(zcrx, 40); if (umove_or_printaddr(tcp, addr, &zcrx)) return; tprint_struct_begin(); PRINT_FIELD_FLAGS(zcrx, register_flags, uring_zcrx_reg_flags, "ZCRX_REG_???"); tprint_struct_next(); PRINT_FIELD_FLAGS(zcrx, area_flags, uring_zcrx_area_flags, "IORING_ZCRX_AREA_???"); tprint_struct_next(); PRINT_FIELD_U(zcrx, nr_ctrl_opcodes); tprint_struct_next(); PRINT_FIELD_X(zcrx, features); tprint_struct_next(); PRINT_FIELD_U(zcrx, rq_hdr_size); tprint_struct_next(); PRINT_FIELD_U(zcrx, rq_hdr_alignment); if (zcrx.__resv2) { tprint_struct_next(); PRINT_FIELD_X(zcrx, __resv2); } tprint_struct_end(); } static void print_io_uring_query_zcrx_notif(struct tcb *tcp, const kernel_ulong_t addr) { struct io_uring_query_zcrx_notif notif; CHECK_TYPE_SIZE(notif, 48); CHECK_TYPE_SIZE(notif.__resv2, 4 * sizeof(uint64_t)); if (umove_or_printaddr(tcp, addr, ¬if)) return; tprint_struct_begin(); PRINT_FIELD_X(notif, notif_flags); tprint_struct_next(); PRINT_FIELD_U(notif, notif_stats_size); tprint_struct_next(); PRINT_FIELD_U(notif, notif_stats_off_alignment); if (notif.__resv1) { tprint_struct_next(); PRINT_FIELD_X(notif, __resv1); } if (!IS_ARRAY_ZERO(notif.__resv2)) { tprint_struct_next(); PRINT_FIELD_ARRAY(notif, __resv2, tcp, print_xint_array_member); } tprint_struct_end(); } static void print_io_uring_query_scq(struct tcb *tcp, const kernel_ulong_t addr) { struct io_uring_query_scq scq; CHECK_TYPE_SIZE(scq, 16); if (umove_or_printaddr(tcp, addr, &scq)) return; tprint_struct_begin(); PRINT_FIELD_U(scq, hdr_size); tprint_struct_next(); PRINT_FIELD_U(scq, hdr_alignment); tprint_struct_end(); } static void print_io_uring_query_list(struct tcb *tcp, kernel_ulong_t addr) { #define IO_MAX_QUERY_ENTRIES 1000 struct io_uring_query_hdr hdr; CHECK_TYPE_SIZE(hdr, 40); CHECK_TYPE_SIZE(hdr.__resv, 3 * sizeof(uint32_t)); unsigned int count = 0; for (;;) { if (umove_or_printaddr(tcp, addr, &hdr)) break; if (count >= IO_MAX_QUERY_ENTRIES || sequence_truncation_needed(tcp, count + 1)) { printaddr(addr); tprintf_comment("..."); break; } tprint_struct_begin(); ++count; /* Print all fields of current entry (except next_entry) */ PRINT_FIELD_ADDR64(hdr, query_data); tprint_struct_next(); PRINT_FIELD_XVAL(hdr, query_op, uring_query_ops, "IO_URING_QUERY_???"); tprint_struct_next(); PRINT_FIELD_U(hdr, size); tprint_struct_next(); PRINT_FIELD_D(hdr, result); if (!IS_ARRAY_ZERO(hdr.__resv)) { tprint_struct_next(); PRINT_FIELD_ARRAY(hdr, __resv, tcp, print_xint_array_member); } /* Decode query_data if present */ if (hdr.query_data && hdr.size > 0) { tprint_struct_next(); tprints_field_name("query_data"); switch (hdr.query_op) { case IO_URING_QUERY_OPCODES: print_io_uring_query_opcode(tcp, hdr.query_data); break; case IO_URING_QUERY_ZCRX: print_io_uring_query_zcrx(tcp, hdr.query_data); break; case IO_URING_QUERY_SCQ: print_io_uring_query_scq(tcp, hdr.query_data); break; case IO_URING_QUERY_ZCRX_NOTIF: print_io_uring_query_zcrx_notif(tcp, hdr.query_data); break; default: printaddr(hdr.query_data); break; } } /* Handle next_entry field */ tprint_struct_next(); tprints_field_name("next_entry"); addr = (kernel_ulong_t) hdr.next_entry; } /* Close any remaining open structures */ while (count > 0) { tprint_struct_end(); --count; } } static int print_ioring_register_query(struct tcb *tcp, const kernel_ulong_t addr, const unsigned int nargs) { if (nargs != 0) { printaddr(addr); return RVAL_DECODED; } print_io_uring_query_list(tcp, addr); return RVAL_DECODED; } static void print_io_uring_register_opcode(struct tcb *tcp, const unsigned int opcode, const unsigned int flags) { if (flags) tprint_flags_begin(); printxval(uring_register_opcodes, opcode, "IORING_REGISTER_???"); if (flags) { tprint_flags_or(); printflags_in(uring_register_opcode_flags, flags, NULL); tprint_flags_end(); } } SYS_FUNC(io_uring_register) { const int fd = tcp->u_arg[0]; unsigned int opcode = tcp->u_arg[1]; const kernel_ulong_t arg = tcp->u_arg[2]; const unsigned int nargs = tcp->u_arg[3]; const unsigned int opcode_flags = opcode & IORING_REGISTER_USE_REGISTERED_RING; opcode &= ~IORING_REGISTER_USE_REGISTERED_RING; int rc = RVAL_DECODED; int buf; if (entering(tcp)) { /* fd */ tprints_arg_name("fd"); if (opcode_flags) PRINT_VAL_U(fd); else printfd(tcp, fd); /* opcode */ tprints_arg_next_name("opcode"); print_io_uring_register_opcode(tcp, opcode, opcode_flags); tprints_arg_next_name("arg"); } /* arg */ switch (opcode) { case IORING_REGISTER_BUFFERS: tprint_iov(tcp, nargs, arg, iov_decode_addr); break; case IORING_REGISTER_FILES: case IORING_REGISTER_EVENTFD: case IORING_REGISTER_EVENTFD_ASYNC: print_array(tcp, arg, nargs, &buf, sizeof(buf), tfetch_mem, print_fd_array_member, NULL); break; case IORING_REGISTER_FILES_UPDATE: print_io_uring_files_update(tcp, arg, nargs); break; case IORING_REGISTER_PROBE: rc = print_io_uring_probe(tcp, arg, nargs); break; case IORING_REGISTER_RESTRICTIONS: print_io_uring_restrictions(tcp, arg, nargs); break; case IORING_REGISTER_FILES2: case IORING_REGISTER_BUFFERS2: print_io_uring_register_rsrc(tcp, arg, nargs, opcode); break; case IORING_REGISTER_FILES_UPDATE2: case IORING_REGISTER_BUFFERS_UPDATE: print_io_uring_update_rsrc(tcp, arg, nargs, opcode); break; case IORING_REGISTER_IOWQ_AFF: print_affinitylist(tcp, arg, nargs); break; case IORING_REGISTER_IOWQ_MAX_WORKERS: rc = print_io_uring_iowq_acct(tcp, arg, nargs); if (entering(tcp) && !rc) tprint_value_changed(); break; case IORING_REGISTER_RING_FDS: print_io_uring_ringfds_register(tcp, arg, nargs); break; case IORING_UNREGISTER_RING_FDS: print_io_uring_ringfds_unregister(tcp, arg, nargs); break; case IORING_REGISTER_PBUF_RING: case IORING_UNREGISTER_PBUF_RING: print_io_uring_buf_reg(tcp, arg, nargs); break; case IORING_REGISTER_SYNC_CANCEL: print_io_uring_sync_cancel_reg(tcp, arg, nargs); break; case IORING_REGISTER_FILE_ALLOC_RANGE: print_io_uring_file_index_range(tcp, arg, nargs); break; case IORING_REGISTER_PBUF_STATUS: rc = print_io_uring_buf_status(tcp, arg, nargs); break; case IORING_REGISTER_NAPI: rc = print_ioring_register_napi(tcp, arg, nargs); break; case IORING_UNREGISTER_NAPI: rc = print_ioring_unregister_napi(tcp, arg, nargs); break; case IORING_REGISTER_CLOCK: rc = print_ioring_register_clock(tcp, arg, nargs); break; case IORING_REGISTER_CLONE_BUFFERS: rc = print_ioring_register_clone_buffers(tcp, arg, nargs); break; case IORING_REGISTER_SEND_MSG_RING: rc = print_ioring_register_send_msg_ring(tcp, arg, nargs); break; case IORING_REGISTER_ZCRX_IFQ: rc = print_ioring_register_zcrx_ifq(tcp, arg, nargs); break; case IORING_REGISTER_ZCRX_CTRL: rc = print_ioring_register_zcrx_ctrl(tcp, arg, nargs); break; case IORING_REGISTER_RESIZE_RINGS: rc = print_ioring_register_resize_rings(tcp, arg, nargs); break; case IORING_REGISTER_MEM_REGION: rc = print_ioring_register_mem_region(tcp, arg, nargs); break; case IORING_REGISTER_QUERY: rc = print_ioring_register_query(tcp, arg, nargs); break; case IORING_UNREGISTER_BUFFERS: case IORING_UNREGISTER_FILES: case IORING_UNREGISTER_EVENTFD: case IORING_REGISTER_PERSONALITY: case IORING_UNREGISTER_PERSONALITY: case IORING_REGISTER_ENABLE_RINGS: case IORING_UNREGISTER_IOWQ_AFF: default: printaddr(arg); break; } if (rc || exiting(tcp)) { /* nr_args */ tprints_arg_next_name("nr_args"); PRINT_VAL_U(nargs); } return rc; }