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