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