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