I addressed your concerns as well as these of jca, just the kernel part (and the new ktrace stuff) below.
One minor thing: I didn't see any kdump output where one struct was contained in another one but I am printing it like ddb would so I guess it should be fine. Index: kern/syscalls.master =================================================================== RCS file: /mount/openbsd/cvs/src/sys/kern/syscalls.master,v retrieving revision 1.229 diff -u -p -r1.229 syscalls.master --- kern/syscalls.master 1 Aug 2022 14:56:59 -0000 1.229 +++ kern/syscalls.master 1 Sep 2022 14:52:47 -0000 @@ -244,8 +244,10 @@ const char *permissions); } 115 STD { int sys___realpath(const char *pathname, \ char *resolved); } -116 OBSOL t32_gettimeofday -117 OBSOL t32_getrusage +116 STD NOLOCK { int sys_recvmmsg(int s, struct mmsghdr *mmsg, \ + unsigned int vlen, unsigned int flags, \ + struct timespec *timeout); } +117 UNIMPL sendmmsg 118 STD { int sys_getsockopt(int s, int level, int name, \ void *val, socklen_t *avalsize); } 119 STD { int sys_thrkill(pid_t tid, int signum, void *tcb); } Index: kern/uipc_syscalls.c =================================================================== RCS file: /mount/openbsd/cvs/src/sys/kern/uipc_syscalls.c,v retrieving revision 1.201 diff -u -p -r1.201 uipc_syscalls.c --- kern/uipc_syscalls.c 14 Aug 2022 01:58:28 -0000 1.201 +++ kern/uipc_syscalls.c 1 Sep 2022 14:37:26 -0000 @@ -805,6 +805,140 @@ done: } int +sys_recvmmsg(struct proc *p, void *v, register_t *retval) +{ + struct sys_recvmmsg_args /* { + syscallarg(int) s; + syscallarg(struct mmsghdr *) mmsg; + syscallarg(unsigned int) vlen; + syscallarg(unsigned int) flags; + syscallarg(struct timespec *) timeout; + } */ *uap = v; + struct mmsghdr mmsg, *mmsgp; + struct timespec ts, now; + struct iovec aiov[UIO_SMALLIOV], *uiov, *iov = aiov; + struct file *fp; + struct socket *so; + struct timespec *timeout; + size_t iovlen = UIO_SMALLIOV; + register_t retrec; + unsigned int vlen, dgrams; + int error = 0, flags, s; + + s = SCARG(uap, s); + if ((error = getsock(p, s, &fp))) + return (error); + so = (struct socket *)fp->f_data; + + timeout = SCARG(uap, timeout); + if (timeout != NULL) { + error = copyin(timeout, &ts, sizeof(ts)); + if (error) + return error; +#ifdef KTRACE + if (KTRPOINT(p, KTR_STRUCT)) + ktrreltimespec(p, &ts); +#endif + getnanotime(&now); + timespecadd(&now, &ts, &ts); + } + + flags = SCARG(uap, flags); + + /* Arbitrarily capped at 1024 datagrams. */ + vlen = SCARG(uap, vlen); + if (vlen > 1024) + vlen = 1024; + + mmsgp = SCARG(uap, mmsg); + for (dgrams = 0; dgrams < vlen;) { + error = copyin(&mmsgp[dgrams], &mmsg, sizeof(mmsg)); + if (error) + break; + + if (mmsg.msg_hdr.msg_iovlen > IOV_MAX) { + error = EMSGSIZE; + break; + } + + if (mmsg.msg_hdr.msg_iovlen > iovlen) { + if (iov != aiov) + free(iov, M_IOV, iovlen * + sizeof(struct iovec)); + + iovlen = mmsg.msg_hdr.msg_iovlen; + iov = mallocarray(iovlen, sizeof(struct iovec), + M_IOV, M_WAITOK); + } + + if (mmsg.msg_hdr.msg_iovlen > 0) { + error = copyin(mmsg.msg_hdr.msg_iov, iov, + mmsg.msg_hdr.msg_iovlen * sizeof(struct iovec)); + if (error) + break; + } + + uiov = mmsg.msg_hdr.msg_iov; + mmsg.msg_hdr.msg_iov = iov; + mmsg.msg_hdr.msg_flags = flags; + + error = recvit(p, s, &mmsg.msg_hdr, NULL, &retrec); + if (error) { + if (error == EAGAIN && dgrams > 0) + error = 0; + break; + } + + if (dgrams == 0 && flags & MSG_WAITFORONE) { + flags &= ~MSG_WAITFORONE; + flags |= MSG_DONTWAIT; + } + + mmsg.msg_hdr.msg_iov = uiov; + mmsg.msg_len = retrec; +#ifdef KTRACE + if (KTRPOINT(p, KTR_STRUCT)) { + ktrmmsghdr(p, &mmsg); + if (mmsg.msg_hdr.msg_iovlen) + ktriovec(p, iov, mmsg.msg_hdr.msg_iovlen); + } +#endif + + error = copyout(&mmsg, &mmsgp[dgrams], sizeof(mmsg)); + if (error) + break; + + dgrams++; + if (mmsg.msg_hdr.msg_flags & MSG_OOB) + break; + + if (timeout != NULL) { + getnanotime(&now); + timespecsub(&now, &ts, &now); + if (now.tv_sec > 0) + break; + } + } + + if (iov != aiov) + free(iov, M_IOV, iovlen * sizeof(struct iovec)); + + *retval = dgrams; + + /* + * If we succeeded at least once, return 0, hopefully so->so_error + * will catch it next time. + */ + if (error && dgrams > 0) { + so->so_error = error; + error = 0; + } + + FRELE(fp, p); + return (error); +} + +int recvit(struct proc *p, int s, struct msghdr *mp, caddr_t namelenp, register_t *retsize) { Index: sys/ktrace.h =================================================================== RCS file: /mount/openbsd/cvs/src/sys/sys/ktrace.h,v retrieving revision 1.41 diff -u -p -r1.41 ktrace.h --- sys/ktrace.h 22 Feb 2022 17:14:14 -0000 1.41 +++ sys/ktrace.h 1 Sep 2022 14:35:13 -0000 @@ -239,6 +239,8 @@ void ktrstruct(struct proc *, const c ktrstruct((p), "quota", (s), sizeof(struct dqblk)) #define ktrmsghdr(p, s) \ ktrstruct(p, "msghdr", s, sizeof(struct msghdr)) +#define ktrmmsghdr(p, s) \ + ktrstruct(p, "mmsghdr", s, sizeof(struct mmsghdr)) #define ktriovec(p, s, count) \ ktrstruct(p, "iovec", s, (count) * sizeof(struct iovec)) #define ktrcmsghdr(p, c, len) \ Index: sys/socket.h =================================================================== RCS file: /mount/openbsd/cvs/src/sys/sys/socket.h,v retrieving revision 1.102 diff -u -p -r1.102 socket.h --- sys/socket.h 22 Feb 2022 01:01:02 -0000 1.102 +++ sys/socket.h 1 Sep 2022 08:49:48 -0000 @@ -490,6 +490,13 @@ struct msghdr { int msg_flags; /* flags on received message */ }; +struct mmsghdr { + struct msghdr msg_hdr; + unsigned int msg_len; +}; + +struct timespec; + #define MSG_OOB 0x1 /* process out-of-band data */ #define MSG_PEEK 0x2 /* peek at incoming message */ #define MSG_DONTROUTE 0x4 /* send without using routing tables */ @@ -502,6 +509,7 @@ struct msghdr { #define MSG_MCAST 0x200 /* this message rec'd as multicast */ #define MSG_NOSIGNAL 0x400 /* do not send SIGPIPE */ #define MSG_CMSG_CLOEXEC 0x800 /* set FD_CLOEXEC on received fds */ +#define MSG_WAITFORONE 0x1000 /* nonblocking but wait for one msg */ /* * Header for ancillary data objects in msg_control buffer. @@ -565,6 +573,8 @@ int listen(int, int); ssize_t recv(int, void *, size_t, int); ssize_t recvfrom(int, void *, size_t, int, struct sockaddr *, socklen_t *); ssize_t recvmsg(int, struct msghdr *, int); +int recvmmsg(int, struct mmsghdr *, unsigned int, unsigned int, + struct timespec *); ssize_t send(int, const void *, size_t, int); ssize_t sendto(int, const void *, size_t, int, const struct sockaddr *, socklen_t); Index: usr.bin/kdump/kdump.c =================================================================== RCS file: /mount/openbsd/cvs/src/usr.bin/kdump/kdump.c,v retrieving revision 1.149 diff -u -p -r1.149 kdump.c --- usr.bin/kdump/kdump.c 20 Jul 2022 05:56:36 -0000 1.149 +++ usr.bin/kdump/kdump.c 1 Sep 2022 15:03:03 -0000 @@ -795,6 +795,7 @@ static const formatter scargs[][8] = { [SYS_ppoll] = { Pptr, Pucount, Pptr, Pptr }, [SYS_pselect] = { Pcount, Pptr, Pptr, Pptr, Pptr, Pptr }, [SYS_sigsuspend] = { Sigset }, + [SYS_recvmmsg] = { Pfd, Pptr, Pcount, Sendrecvflagsname, Pptr }, [SYS_getsockopt] = { Pfd, PASS_TWO, Sockoptlevelname, Pptr, Pptr }, [SYS_thrkill] = { Ppid_t, Signame, Pptr }, [SYS_readv] = { Pfd, Pptr, Pcount }, Index: usr.bin/kdump/ktrstruct.c =================================================================== RCS file: /mount/openbsd/cvs/src/usr.bin/kdump/ktrstruct.c,v retrieving revision 1.29 diff -u -p -r1.29 ktrstruct.c --- usr.bin/kdump/ktrstruct.c 21 Dec 2020 07:47:37 -0000 1.29 +++ usr.bin/kdump/ktrstruct.c 1 Sep 2022 15:24:42 -0000 @@ -398,6 +398,18 @@ ktrquota(const struct dqblk *quota) } static void +ktrmmsghdr(const struct mmsghdr *mmsg) +{ + printf("struct mmsghdr { msg_hdr = { name=%p, namelen=%u, iov=%p, iovlen=%u," + " control=%p, controllen=%u, flags=", + mmsg->msg_hdr.msg_name, mmsg->msg_hdr.msg_namelen, + mmsg->msg_hdr.msg_iov, mmsg->msg_hdr.msg_iovlen, + mmsg->msg_hdr.msg_control, mmsg->msg_hdr.msg_controllen); + sendrecvflagsname(mmsg->msg_hdr.msg_flags); + printf(" }, msg_len = %u }\n", mmsg->msg_len); +} + +static void ktrmsghdr(const struct msghdr *msg) { printf("struct msghdr { name=%p, namelen=%u, iov=%p, iovlen=%u," @@ -649,6 +661,13 @@ ktrstruct(char *buf, size_t buflen) goto invalid; memcpy(&msg, data, datalen); ktrmsghdr(&msg); + } else if (strcmp(name, "mmsghdr") == 0) { + struct mmsghdr mmsg; + + if (datalen != sizeof(mmsg)) + goto invalid; + memcpy(&mmsg, data, datalen); + ktrmmsghdr(&mmsg); } else if (strcmp(name, "iovec") == 0) { if (datalen % sizeof(struct iovec)) goto invalid;