(root)/
strace-6.5/
src/
mmsghdr.c
       1  /*
       2   * Copyright (c) 2010 Andreas Schwab <schwab@linux-m68k.org>
       3   * Copyright (c) 2012-2013 Denys Vlasenko <vda.linux@googlemail.com>
       4   * Copyright (c) 2014 Masatake YAMATO <yamato@redhat.com>
       5   * Copyright (c) 2010-2016 Dmitry V. Levin <ldv@strace.io>
       6   * Copyright (c) 2016-2023 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 "msghdr.h"
      14  #include "xstring.h"
      15  #include <limits.h>
      16  
      17  static bool
      18  fetch_struct_mmsghdr_for_print(struct tcb *const tcp,
      19  				  const kernel_ulong_t addr,
      20  				  const unsigned int len, void *const mh)
      21  {
      22  	return (entering(tcp) || !syserror(tcp)) &&
      23  	       fetch_struct_mmsghdr(tcp, addr, mh);
      24  }
      25  
      26  struct print_struct_mmsghdr_config {
      27  	const int *p_user_msg_namelen;
      28  	unsigned int msg_len_vlen;
      29  	unsigned int count;
      30  	bool use_msg_len;
      31  };
      32  
      33  static bool
      34  print_struct_mmsghdr(struct tcb *tcp, void *elem_buf,
      35  		     size_t elem_size, void *data)
      36  {
      37  	const struct mmsghdr *const mmsg = elem_buf;
      38  	struct print_struct_mmsghdr_config *const c = data;
      39  
      40  	if (!c->count) {
      41  		tprint_more_data_follows();
      42  		return false;
      43  	}
      44  	--c->count;
      45  
      46  	tprint_struct_begin();
      47  	PRINT_FIELD_OBJ_TCB_PTR(*mmsg, msg_hdr, tcp, print_struct_msghdr,
      48  			c->p_user_msg_namelen,
      49  			c->use_msg_len ? mmsg->msg_len : (kernel_ulong_t) -1);
      50  	if (c->msg_len_vlen) {
      51  		tprint_struct_next();
      52  		PRINT_FIELD_U(*mmsg, msg_len);
      53  		--c->msg_len_vlen;
      54  	}
      55  	tprint_struct_end();
      56  
      57  	if (c->p_user_msg_namelen)
      58  		++c->p_user_msg_namelen;
      59  
      60  	return true;
      61  }
      62  
      63  static void
      64  free_mmsgvec_data(void *ptr)
      65  {
      66  	char **pstr = ptr;
      67  	free(*pstr);
      68  	*pstr = 0;
      69  
      70  	free(ptr);
      71  }
      72  
      73  struct mmsgvec_data {
      74  	char *timeout;
      75  	unsigned int count;
      76  	int namelen[0];
      77  };
      78  
      79  static void
      80  save_mmsgvec_namelen(struct tcb *const tcp, kernel_ulong_t addr,
      81  		     unsigned int len, const char *const timeout)
      82  {
      83  	if (len > IOV_MAX)
      84  		len = IOV_MAX;
      85  
      86  	const size_t data_size = offsetof(struct mmsgvec_data, namelen)
      87  				 + sizeof(int) * len;
      88  	struct mmsgvec_data *const data = xmalloc(data_size);
      89  	data->timeout = xstrdup(timeout);
      90  
      91  	unsigned int i, fetched;
      92  
      93  	for (i = 0; i < len; ++i, addr += fetched) {
      94  		struct mmsghdr mh;
      95  
      96  		fetched = fetch_struct_mmsghdr(tcp, addr, &mh);
      97  		if (!fetched)
      98  			break;
      99  		data->namelen[i] = mh.msg_hdr.msg_namelen;
     100  	}
     101  	data->count = i;
     102  
     103  	set_tcb_priv_data(tcp, data, free_mmsgvec_data);
     104  }
     105  
     106  static void
     107  decode_mmsgvec(struct tcb *const tcp, const kernel_ulong_t addr,
     108  	       const unsigned int vlen, const unsigned int msg_len_vlen,
     109  	       const bool use_msg_len)
     110  {
     111  	struct mmsghdr mmsg;
     112  	struct print_struct_mmsghdr_config c = {
     113  		.msg_len_vlen = msg_len_vlen,
     114  		.count = IOV_MAX,
     115  		.use_msg_len = use_msg_len
     116  	};
     117  	const struct mmsgvec_data *const data = get_tcb_priv_data(tcp);
     118  
     119  	if (data) {
     120  		if (data->count < c.count)
     121  			c.count = data->count;
     122  		c.p_user_msg_namelen = data->namelen;
     123  	}
     124  
     125  	print_array(tcp, addr, vlen, &mmsg, sizeof_struct_mmsghdr(),
     126  		    fetch_struct_mmsghdr_for_print,
     127  		    print_struct_mmsghdr, &c);
     128  }
     129  
     130  void
     131  dumpiov_in_mmsghdr(struct tcb *const tcp, kernel_ulong_t addr)
     132  {
     133  	unsigned int len = tcp->u_rval;
     134  	unsigned int fetched;
     135  
     136  	for (unsigned int i = 0; i < len; ++i, addr += fetched) {
     137  		struct mmsghdr mmsg;
     138  		fetched = fetch_struct_mmsghdr(tcp, addr, &mmsg);
     139  		if (!fetched)
     140  			break;
     141  		tprintf_string(" = %" PRI_klu " buffers in vector %u\n",
     142  			       (kernel_ulong_t) mmsg.msg_hdr.msg_iovlen, i);
     143  		dumpiov_upto(tcp, mmsg.msg_hdr.msg_iovlen,
     144  			     ptr_to_kulong(mmsg.msg_hdr.msg_iov),
     145  			     mmsg.msg_len);
     146  	}
     147  }
     148  
     149  SYS_FUNC(sendmmsg)
     150  {
     151  	if (entering(tcp)) {
     152  		/* sockfd */
     153  		printfd(tcp, tcp->u_arg[0]);
     154  		tprint_arg_next();
     155  
     156  		if (!verbose(tcp)) {
     157  			/* msgvec */
     158  			printaddr(tcp->u_arg[1]);
     159  			tprint_arg_next();
     160  
     161  			/* vlen */
     162  			PRINT_VAL_U((unsigned int) tcp->u_arg[2]);
     163  			tprint_arg_next();
     164  
     165  			/* flags */
     166  			printflags(msg_flags, tcp->u_arg[3], "MSG_???");
     167  			return RVAL_DECODED;
     168  		}
     169  	} else {
     170  		const unsigned int msg_len_vlen =
     171  			syserror(tcp) ? 0 : tcp->u_rval;
     172  		/* msgvec */
     173  		temporarily_clear_syserror(tcp);
     174  		decode_mmsgvec(tcp, tcp->u_arg[1], tcp->u_arg[2],
     175  			       msg_len_vlen, false);
     176  		restore_cleared_syserror(tcp);
     177  		tprint_arg_next();
     178  
     179  		/* vlen */
     180  		PRINT_VAL_U((unsigned int) tcp->u_arg[2]);
     181  		tprint_arg_next();
     182  
     183  		/* flags */
     184  		printflags(msg_flags, tcp->u_arg[3], "MSG_???");
     185  	}
     186  	return 0;
     187  }
     188  
     189  static int
     190  do_recvmmsg(struct tcb *const tcp, const print_obj_by_addr_fn print_ts,
     191  	    const sprint_obj_by_addr_fn sprint_ts)
     192  {
     193  	if (entering(tcp)) {
     194  		/* sockfd */
     195  		printfd(tcp, tcp->u_arg[0]);
     196  		tprint_arg_next();
     197  
     198  		if (verbose(tcp)) {
     199  			save_mmsgvec_namelen(tcp, tcp->u_arg[1], tcp->u_arg[2],
     200  					     sprint_ts(tcp, tcp->u_arg[4]));
     201  		} else {
     202  			/* msgvec */
     203  			printaddr(tcp->u_arg[1]);
     204  			tprint_arg_next();
     205  
     206  			/* vlen */
     207  			PRINT_VAL_U((unsigned int) tcp->u_arg[2]);
     208  			tprint_arg_next();
     209  
     210  			/* flags */
     211  			printflags(msg_flags, tcp->u_arg[3], "MSG_???");
     212  			tprint_arg_next();
     213  
     214  			/* timeout */
     215  			print_ts(tcp, tcp->u_arg[4]);
     216  		}
     217  		return 0;
     218  	} else {
     219  		if (verbose(tcp)) {
     220  			/* msgvec */
     221  			decode_mmsgvec(tcp, tcp->u_arg[1], tcp->u_rval,
     222  				       tcp->u_rval, true);
     223  			tprint_arg_next();
     224  
     225  			/* vlen */
     226  			PRINT_VAL_U((unsigned int) tcp->u_arg[2]);
     227  			tprint_arg_next();
     228  
     229  			/* flags */
     230  			printflags(msg_flags, tcp->u_arg[3], "MSG_???");
     231  			tprint_arg_next();
     232  
     233  			/* timeout on entrance */
     234  			tprints_string(*(const char **) get_tcb_priv_data(tcp));
     235  		}
     236  		if (syserror(tcp))
     237  			return 0;
     238  		if (tcp->u_rval == 0) {
     239  			tcp->auxstr = "Timeout";
     240  			return RVAL_STR;
     241  		}
     242  		if (!verbose(tcp) || !tcp->u_arg[4])
     243  			return 0;
     244  		/* timeout on exit */
     245  		static char str[sizeof("left") + TIMESPEC_TEXT_BUFSIZE];
     246  		xsprintf(str, "left %s", sprint_ts(tcp, tcp->u_arg[4]));
     247  		tcp->auxstr = str;
     248  		return RVAL_STR;
     249  	}
     250  }
     251  
     252  #if HAVE_ARCH_TIME32_SYSCALLS
     253  SYS_FUNC(recvmmsg_time32)
     254  {
     255  	return do_recvmmsg(tcp, print_timespec32, sprint_timespec32);
     256  }
     257  #endif
     258  
     259  SYS_FUNC(recvmmsg_time64)
     260  {
     261  	return do_recvmmsg(tcp, print_timespec64, sprint_timespec64);
     262  }