]> granicus.if.org Git - strace/blob - desc.c
clone: fix print_tls_arg on x86
[strace] / desc.c
1 /*
2  * Copyright (c) 1991, 1992 Paul Kranenburg <pk@cs.few.eur.nl>
3  * Copyright (c) 1993 Branko Lankester <branko@hacktic.nl>
4  * Copyright (c) 1993, 1994, 1995, 1996 Rick Sladkey <jrs@world.std.com>
5  * Copyright (c) 1996-1999 Wichert Akkerman <wichert@cistron.nl>
6  * Copyright (c) 1999-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 "xstring.h"
14
15 SYS_FUNC(close)
16 {
17         printfd(tcp, tcp->u_arg[0]);
18
19         return RVAL_DECODED;
20 }
21
22 SYS_FUNC(dup)
23 {
24         printfd(tcp, tcp->u_arg[0]);
25
26         return RVAL_DECODED | RVAL_FD;
27 }
28
29 static int
30 do_dup2(struct tcb *tcp, int flags_arg)
31 {
32         printfd(tcp, tcp->u_arg[0]);
33         tprints(", ");
34         printfd(tcp, tcp->u_arg[1]);
35         if (flags_arg >= 0) {
36                 tprints(", ");
37                 printflags(open_mode_flags, tcp->u_arg[flags_arg], "O_???");
38         }
39
40         return RVAL_DECODED | RVAL_FD;
41 }
42
43 SYS_FUNC(dup2)
44 {
45         return do_dup2(tcp, -1);
46 }
47
48 SYS_FUNC(dup3)
49 {
50         return do_dup2(tcp, 2);
51 }
52
53 static int
54 decode_select(struct tcb *const tcp, const kernel_ulong_t *const args,
55               const print_obj_by_addr_fn print_tv_ts,
56               const sprint_obj_by_addr_fn sprint_tv_ts)
57 {
58         int i, j;
59         int nfds, fdsize;
60         fd_set *fds = NULL;
61         const char *sep;
62         kernel_ulong_t addr;
63
64         /* Kernel truncates args[0] to int, we do the same. */
65         nfds = (int) args[0];
66
67         /* Kernel rejects negative nfds, so we don't parse it either. */
68         if (nfds < 0)
69                 nfds = 0;
70
71         /* Beware of select(2^31-1, NULL, NULL, NULL) and similar... */
72         if (nfds > 1024*1024)
73                 nfds = 1024*1024;
74
75         /*
76          * We had bugs a-la "while (j < args[0])" and "umoven(args[0])" below.
77          * Instead of args[0], use nfds for fd count, fdsize for array lengths.
78          */
79         fdsize = (((nfds + 7) / 8) + current_wordsize-1) & -current_wordsize;
80
81         if (entering(tcp)) {
82                 tprintf("%d", (int) args[0]);
83
84                 if (verbose(tcp) && fdsize > 0)
85                         fds = malloc(fdsize);
86                 for (i = 0; i < 3; i++) {
87                         addr = args[i+1];
88                         tprints(", ");
89                         if (!fds) {
90                                 printaddr(addr);
91                                 continue;
92                         }
93                         if (umoven_or_printaddr(tcp, addr, fdsize, fds))
94                                 continue;
95                         tprints("[");
96                         for (j = 0, sep = "";; j++) {
97                                 j = next_set_bit(fds, j, nfds);
98                                 if (j < 0)
99                                         break;
100                                 tprints(sep);
101                                 printfd(tcp, j);
102                                 sep = " ";
103                         }
104                         tprints("]");
105                 }
106                 free(fds);
107                 tprints(", ");
108                 print_tv_ts(tcp, args[4]);
109         } else {
110                 static char outstr[1024];
111                 char *outptr;
112 #define end_outstr (outstr + sizeof(outstr))
113                 int ready_fds;
114
115                 if (syserror(tcp))
116                         return 0;
117
118                 ready_fds = tcp->u_rval;
119                 if (ready_fds == 0) {
120                         tcp->auxstr = "Timeout";
121                         return RVAL_STR;
122                 }
123
124                 fds = malloc(fdsize);
125
126                 outptr = outstr;
127                 sep = "";
128                 for (i = 0; i < 3 && ready_fds > 0; i++) {
129                         int first = 1;
130
131                         addr = args[i+1];
132                         if (!addr || !fds || umoven(tcp, addr, fdsize, fds) < 0)
133                                 continue;
134                         for (j = 0;; j++) {
135                                 j = next_set_bit(fds, j, nfds);
136                                 if (j < 0)
137                                         break;
138                                 /* +2 chars needed at the end: ']',NUL */
139                                 if (outptr < end_outstr - (sizeof(", except [") + sizeof(int)*3 + 2)) {
140                                         if (first) {
141                                                 outptr = xappendstr(outstr,
142                                                         outptr,
143                                                         "%s%s [%u",
144                                                         sep,
145                                                         i == 0 ? "in" : i == 1 ? "out" : "except",
146                                                         j
147                                                 );
148                                                 first = 0;
149                                                 sep = ", ";
150                                         } else {
151                                                 outptr = xappendstr(outstr,
152                                                         outptr,
153                                                         " %u", j);
154                                         }
155                                 }
156                                 if (--ready_fds == 0)
157                                         break;
158                         }
159                         if (outptr != outstr)
160                                 *outptr++ = ']';
161                 }
162                 free(fds);
163                 /* This contains no useful information on SunOS.  */
164                 if (args[4]) {
165                         const char *str = sprint_tv_ts(tcp, args[4]);
166                         if (outptr + sizeof("left ") + strlen(sep) + strlen(str) < end_outstr) {
167                                 outptr = xappendstr(outstr, outptr,
168                                                     "%sleft %s", sep, str);
169                         }
170                 }
171                 *outptr = '\0';
172                 tcp->auxstr = outstr;
173                 return RVAL_STR;
174 #undef end_outstr
175         }
176         return 0;
177 }
178
179 #if HAVE_ARCH_OLD_SELECT
180 SYS_FUNC(oldselect)
181 {
182         kernel_ulong_t *args =
183                 fetch_indirect_syscall_args(tcp, tcp->u_arg[0], 5);
184
185         if (args) {
186                 return decode_select(tcp, args, print_timeval, sprint_timeval);
187         } else {
188                 if (entering(tcp))
189                         printaddr(tcp->u_arg[0]);
190                 return RVAL_DECODED;
191         }
192 }
193 #endif /* HAVE_ARCH_OLD_SELECT */
194
195 #ifdef ALPHA
196 SYS_FUNC(osf_select)
197 {
198         return decode_select(tcp, tcp->u_arg, print_timeval32, sprint_timeval32);
199 }
200 #endif
201
202 SYS_FUNC(select)
203 {
204         return decode_select(tcp, tcp->u_arg, print_timeval, sprint_timeval);
205 }
206
207 static int
208 umove_kulong_array_or_printaddr(struct tcb *const tcp, const kernel_ulong_t addr,
209                                 kernel_ulong_t *const ptr, const size_t n)
210 {
211 #ifndef current_klongsize
212         if (current_klongsize < sizeof(*ptr)) {
213                 uint32_t ptr32[n];
214                 int r = umove_or_printaddr(tcp, addr, &ptr32);
215                 if (!r) {
216                         size_t i;
217
218                         for (i = 0; i < n; ++i)
219                                 ptr[i] = ptr32[i];
220                 }
221                 return r;
222         }
223 #endif /* !current_klongsize */
224         return umoven_or_printaddr(tcp, addr, n * sizeof(*ptr), ptr);
225 }
226
227 static int
228 do_pselect6(struct tcb *const tcp, const print_obj_by_addr_fn print_ts,
229             const sprint_obj_by_addr_fn sprint_ts)
230 {
231         int rc = decode_select(tcp, tcp->u_arg, print_ts, sprint_ts);
232         if (entering(tcp)) {
233                 kernel_ulong_t data[2];
234
235                 tprints(", ");
236                 if (!umove_kulong_array_or_printaddr(tcp, tcp->u_arg[5],
237                                                      data, ARRAY_SIZE(data))) {
238                         tprints("{");
239                         /* NB: kernel requires data[1] == NSIG_BYTES */
240                         print_sigset_addr_len(tcp, data[0], data[1]);
241                         tprintf(", %" PRI_klu "}", data[1]);
242                 }
243         }
244
245         return rc;
246 }
247
248 #if HAVE_ARCH_TIME32_SYSCALLS
249 SYS_FUNC(pselect6_time32)
250 {
251         return do_pselect6(tcp, print_timespec32, sprint_timespec32);
252 }
253 #endif
254
255 SYS_FUNC(pselect6_time64)
256 {
257         return do_pselect6(tcp, print_timespec64, sprint_timespec64);
258 }