]> granicus.if.org Git - strace/blob - mmsghdr.c
tprint_iov*: change address argument type from unsigned long to kernel_ureg_t
[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                         /* msgvec */
176                         printaddr(tcp->u_arg[1]);
177                         /* vlen */
178                         tprintf(", %u, ", (unsigned int) tcp->u_arg[2]);
179                         /* flags */
180                         printflags(msg_flags, tcp->u_arg[3], "MSG_???");
181                         return RVAL_DECODED;
182                 }
183         } else {
184                 const unsigned int msg_len_vlen =
185                         syserror(tcp) ? 0 : tcp->u_rval;
186                 /* msgvec */
187                 temporarily_clear_syserror(tcp);
188                 decode_mmsgvec(tcp, tcp->u_arg[1], tcp->u_arg[2],
189                                msg_len_vlen, false);
190                 restore_cleared_syserror(tcp);
191                 /* vlen */
192                 tprintf(", %u, ", (unsigned int) tcp->u_arg[2]);
193                 /* flags */
194                 printflags(msg_flags, tcp->u_arg[3], "MSG_???");
195         }
196         return 0;
197 }
198
199 SYS_FUNC(recvmmsg)
200 {
201         if (entering(tcp)) {
202                 printfd(tcp, tcp->u_arg[0]);
203                 tprints(", ");
204                 if (verbose(tcp)) {
205                         save_mmsgvec_namelen(tcp, tcp->u_arg[1], tcp->u_arg[2],
206                                              sprint_timespec(tcp, tcp->u_arg[4]));
207                 } else {
208                         /* msgvec */
209                         printaddr(tcp->u_arg[1]);
210                         /* vlen */
211                         tprintf(", %u, ", (unsigned int) tcp->u_arg[2]);
212                         /* flags */
213                         printflags(msg_flags, tcp->u_arg[3], "MSG_???");
214                         tprints(", ");
215                         print_timespec(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                         /* vlen */
224                         tprintf(", %u, ", (unsigned int) tcp->u_arg[2]);
225                         /* flags */
226                         printflags(msg_flags, tcp->u_arg[3], "MSG_???");
227                         tprints(", ");
228                         /* timeout on entrance */
229                         tprints(*(const char **) get_tcb_priv_data(tcp));
230                 }
231                 if (syserror(tcp))
232                         return 0;
233                 if (tcp->u_rval == 0) {
234                         tcp->auxstr = "Timeout";
235                         return RVAL_STR;
236                 }
237                 if (!verbose(tcp) || !tcp->u_arg[4])
238                         return 0;
239                 /* timeout on exit */
240                 static char str[sizeof("left") + TIMESPEC_TEXT_BUFSIZE];
241                 snprintf(str, sizeof(str), "left %s",
242                          sprint_timespec(tcp, tcp->u_arg[4]));
243                 tcp->auxstr = str;
244                 return RVAL_STR;
245         }
246 }