]> granicus.if.org Git - strace/blob - mmsghdr.c
mmap_cache: add function to enable mmap_cache
[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  * Copyright (c) 2016-2018 The strace developers.
7  * All rights reserved.
8  *
9  * Redistribution and use in source and binary forms, with or without
10  * modification, are permitted provided that the following conditions
11  * are met:
12  * 1. Redistributions of source code must retain the above copyright
13  *    notice, this list of conditions and the following disclaimer.
14  * 2. Redistributions in binary form must reproduce the above copyright
15  *    notice, this list of conditions and the following disclaimer in the
16  *    documentation and/or other materials provided with the distribution.
17  * 3. The name of the author may not be used to endorse or promote products
18  *    derived from this software without specific prior written permission.
19  *
20  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
21  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
22  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
23  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
24  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
25  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
29  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30  */
31
32 #include "defs.h"
33 #include "msghdr.h"
34 #include "xstring.h"
35 #include <limits.h>
36
37 static int
38 fetch_struct_mmsghdr_or_printaddr(struct tcb *const tcp,
39                                   const kernel_ulong_t addr,
40                                   const unsigned int len, void *const mh)
41 {
42         if ((entering(tcp) || !syserror(tcp))
43             && fetch_struct_mmsghdr(tcp, addr, mh)) {
44                 return 0;
45         } else {
46                 printaddr(addr);
47                 return -1;
48         }
49 }
50
51 struct print_struct_mmsghdr_config {
52         const int *p_user_msg_namelen;
53         unsigned int msg_len_vlen;
54         unsigned int count;
55         bool use_msg_len;
56 };
57
58 static bool
59 print_struct_mmsghdr(struct tcb *tcp, void *elem_buf,
60                      size_t elem_size, void *data)
61 {
62         const struct mmsghdr *const mmsg = elem_buf;
63         struct print_struct_mmsghdr_config *const c = data;
64
65         if (!c->count) {
66                 tprints("...");
67                 return false;
68         }
69         --c->count;
70
71         tprints("{msg_hdr=");
72         print_struct_msghdr(tcp, &mmsg->msg_hdr, c->p_user_msg_namelen,
73                             c->use_msg_len ? mmsg->msg_len : (kernel_ulong_t) -1);
74         if (c->msg_len_vlen) {
75                 tprintf(", msg_len=%u", mmsg->msg_len);
76                 --c->msg_len_vlen;
77         }
78         tprints("}");
79
80         if (c->p_user_msg_namelen)
81                 ++c->p_user_msg_namelen;
82
83         return true;
84 }
85
86 static void
87 free_mmsgvec_data(void *ptr)
88 {
89         char **pstr = ptr;
90         free(*pstr);
91         *pstr = 0;
92
93         free(ptr);
94 }
95
96 struct mmsgvec_data {
97         char *timeout;
98         unsigned int count;
99         int namelen[IOV_MAX];
100 };
101
102 static void
103 save_mmsgvec_namelen(struct tcb *const tcp, kernel_ulong_t addr,
104                      unsigned int len, const char *const timeout)
105 {
106         if (len > IOV_MAX)
107                 len = IOV_MAX;
108
109         const size_t data_size = offsetof(struct mmsgvec_data, namelen)
110                                  + sizeof(int) * len;
111         struct mmsgvec_data *const data = xmalloc(data_size);
112         data->timeout = xstrdup(timeout);
113
114         unsigned int i, fetched;
115
116         for (i = 0; i < len; ++i, addr += fetched) {
117                 struct mmsghdr mh;
118
119                 fetched = fetch_struct_mmsghdr(tcp, addr, &mh);
120                 if (!fetched)
121                         break;
122                 data->namelen[i] = mh.msg_hdr.msg_namelen;
123         }
124         data->count = i;
125
126         set_tcb_priv_data(tcp, data, free_mmsgvec_data);
127 }
128
129 static void
130 decode_mmsgvec(struct tcb *const tcp, const kernel_ulong_t addr,
131                const unsigned int vlen, const unsigned int msg_len_vlen,
132                const bool use_msg_len)
133 {
134         struct mmsghdr mmsg;
135         struct print_struct_mmsghdr_config c = {
136                 .msg_len_vlen = msg_len_vlen,
137                 .count = IOV_MAX,
138                 .use_msg_len = use_msg_len
139         };
140         const struct mmsgvec_data *const data = get_tcb_priv_data(tcp);
141
142         if (data) {
143                 if (data->count < c.count)
144                         c.count = data->count;
145                 c.p_user_msg_namelen = data->namelen;
146         }
147
148         print_array(tcp, addr, vlen, &mmsg, sizeof_struct_mmsghdr(),
149                     fetch_struct_mmsghdr_or_printaddr,
150                     print_struct_mmsghdr, &c);
151 }
152
153 void
154 dumpiov_in_mmsghdr(struct tcb *const tcp, kernel_ulong_t addr)
155 {
156         unsigned int len = tcp->u_rval;
157         unsigned int i, fetched;
158         struct mmsghdr mmsg;
159
160         for (i = 0; i < len; ++i, addr += fetched) {
161                 fetched = fetch_struct_mmsghdr(tcp, addr, &mmsg);
162                 if (!fetched)
163                         break;
164                 tprintf(" = %" PRI_klu " buffers in vector %u\n",
165                         (kernel_ulong_t) mmsg.msg_hdr.msg_iovlen, i);
166                 dumpiov_upto(tcp, mmsg.msg_hdr.msg_iovlen,
167                              ptr_to_kulong(mmsg.msg_hdr.msg_iov),
168                              mmsg.msg_len);
169         }
170 }
171
172 SYS_FUNC(sendmmsg)
173 {
174         if (entering(tcp)) {
175                 /* sockfd */
176                 printfd(tcp, tcp->u_arg[0]);
177                 tprints(", ");
178                 if (!verbose(tcp)) {
179                         /* msgvec */
180                         printaddr(tcp->u_arg[1]);
181                         /* vlen */
182                         tprintf(", %u, ", (unsigned int) tcp->u_arg[2]);
183                         /* flags */
184                         printflags(msg_flags, tcp->u_arg[3], "MSG_???");
185                         return RVAL_DECODED;
186                 }
187         } else {
188                 const unsigned int msg_len_vlen =
189                         syserror(tcp) ? 0 : tcp->u_rval;
190                 /* msgvec */
191                 temporarily_clear_syserror(tcp);
192                 decode_mmsgvec(tcp, tcp->u_arg[1], tcp->u_arg[2],
193                                msg_len_vlen, false);
194                 restore_cleared_syserror(tcp);
195                 /* vlen */
196                 tprintf(", %u, ", (unsigned int) tcp->u_arg[2]);
197                 /* flags */
198                 printflags(msg_flags, tcp->u_arg[3], "MSG_???");
199         }
200         return 0;
201 }
202
203 SYS_FUNC(recvmmsg)
204 {
205         if (entering(tcp)) {
206                 printfd(tcp, tcp->u_arg[0]);
207                 tprints(", ");
208                 if (verbose(tcp)) {
209                         save_mmsgvec_namelen(tcp, tcp->u_arg[1], tcp->u_arg[2],
210                                              sprint_timespec(tcp, tcp->u_arg[4]));
211                 } else {
212                         /* msgvec */
213                         printaddr(tcp->u_arg[1]);
214                         /* vlen */
215                         tprintf(", %u, ", (unsigned int) tcp->u_arg[2]);
216                         /* flags */
217                         printflags(msg_flags, tcp->u_arg[3], "MSG_???");
218                         tprints(", ");
219                         print_timespec(tcp, tcp->u_arg[4]);
220                 }
221                 return 0;
222         } else {
223                 if (verbose(tcp)) {
224                         /* msgvec */
225                         decode_mmsgvec(tcp, tcp->u_arg[1], tcp->u_rval,
226                                        tcp->u_rval, true);
227                         /* vlen */
228                         tprintf(", %u, ", (unsigned int) tcp->u_arg[2]);
229                         /* flags */
230                         printflags(msg_flags, tcp->u_arg[3], "MSG_???");
231                         tprints(", ");
232                         /* timeout on entrance */
233                         tprints(*(const char **) get_tcb_priv_data(tcp));
234                 }
235                 if (syserror(tcp))
236                         return 0;
237                 if (tcp->u_rval == 0) {
238                         tcp->auxstr = "Timeout";
239                         return RVAL_STR;
240                 }
241                 if (!verbose(tcp) || !tcp->u_arg[4])
242                         return 0;
243                 /* timeout on exit */
244                 static char str[sizeof("left") + TIMESPEC_TEXT_BUFSIZE];
245                 xsprintf(str, "left %s", sprint_timespec(tcp, tcp->u_arg[4]));
246                 tcp->auxstr = str;
247                 return RVAL_STR;
248         }
249 }