blob: e05efcd80cbc16f4add6e3c636a0986cbddf76ef [file] [log] [blame]
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001/*
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>
Wichert Akkerman4dc8a2a1999-12-23 14:20:14 +00005 * Copyright (c) 1996-1999 Wichert Akkerman <wichert@cistron.nl>
6 * Copyright (c) 1999 IBM Deutschland Entwicklung GmbH, IBM Corporation
7 * Linux for s390 port by D.J. Barrow
8 * <barrow_dj@mail.yahoo.com,djbarrow@de.ibm.com>
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00009 * All rights reserved.
10 *
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions
13 * are met:
14 * 1. Redistributions of source code must retain the above copyright
15 * notice, this list of conditions and the following disclaimer.
16 * 2. Redistributions in binary form must reproduce the above copyright
17 * notice, this list of conditions and the following disclaimer in the
18 * documentation and/or other materials provided with the distribution.
19 * 3. The name of the author may not be used to endorse or promote products
20 * derived from this software without specific prior written permission.
21 *
22 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
23 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
24 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
25 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
26 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
27 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
28 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
29 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
30 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
31 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
Wichert Akkerman76baf7c1999-02-19 00:21:36 +000032 */
33
34#include "defs.h"
Wichert Akkerman76baf7c1999-02-19 00:21:36 +000035#include <sys/user.h>
36#include <sys/param.h>
37#include <fcntl.h>
Dmitry V. Levinb2fa2be2014-11-21 20:46:16 +000038#include <sys/uio.h>
Wichert Akkerman36915a11999-07-13 15:45:02 +000039
Denys Vlasenko84703742012-02-25 02:38:52 +010040#if defined(IA64)
Roland McGrathd81f1d92003-01-09 06:53:34 +000041# include <asm/ptrace_offsets.h>
42# include <asm/rse.h>
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +000043#endif
44
Wichert Akkerman36915a11999-07-13 15:45:02 +000045#ifdef HAVE_SYS_REG_H
Denys Vlasenko84703742012-02-25 02:38:52 +010046# include <sys/reg.h>
Maarten ter Huurne40c174b2014-10-20 01:02:48 +020047#endif
48
49#ifdef HAVE_LINUX_PTRACE_H
Denys Vlasenko84703742012-02-25 02:38:52 +010050# undef PTRACE_SYSCALL
Roland McGrathce9f0742004-03-01 21:29:22 +000051# ifdef HAVE_STRUCT_IA64_FPREG
52# define ia64_fpreg XXX_ia64_fpreg
53# endif
54# ifdef HAVE_STRUCT_PT_ALL_USER_REGS
55# define pt_all_user_regs XXX_pt_all_user_regs
56# endif
Ali Polatel0b4060f2013-09-24 20:04:32 +030057# ifdef HAVE_STRUCT_PTRACE_PEEKSIGINFO_ARGS
58# define ptrace_peeksiginfo_args XXX_ptrace_peeksiginfo_args
59# endif
Denys Vlasenko84703742012-02-25 02:38:52 +010060# include <linux/ptrace.h>
Ali Polatel0b4060f2013-09-24 20:04:32 +030061# undef ptrace_peeksiginfo_args
Roland McGrathce9f0742004-03-01 21:29:22 +000062# undef ia64_fpreg
63# undef pt_all_user_regs
Wichert Akkerman2e2553a1999-05-09 00:29:58 +000064#endif
65
Wichert Akkerman76baf7c1999-02-19 00:21:36 +000066int
Dmitry V. Levinccee1692012-03-25 21:49:48 +000067string_to_uint(const char *str)
68{
69 char *error;
70 long value;
71
72 if (!*str)
73 return -1;
74 errno = 0;
75 value = strtol(str, &error, 10);
76 if (errno || *error || value < 0 || (long)(int)value != value)
77 return -1;
78 return (int)value;
79}
80
81int
Dmitry V. Levin447db452014-05-29 17:59:01 +000082tv_nz(const struct timeval *a)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +000083{
84 return a->tv_sec || a->tv_usec;
85}
86
87int
Dmitry V. Levin447db452014-05-29 17:59:01 +000088tv_cmp(const struct timeval *a, const struct timeval *b)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +000089{
90 if (a->tv_sec < b->tv_sec
91 || (a->tv_sec == b->tv_sec && a->tv_usec < b->tv_usec))
92 return -1;
93 if (a->tv_sec > b->tv_sec
94 || (a->tv_sec == b->tv_sec && a->tv_usec > b->tv_usec))
95 return 1;
96 return 0;
97}
98
99double
Dmitry V. Levin447db452014-05-29 17:59:01 +0000100tv_float(const struct timeval *tv)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000101{
102 return tv->tv_sec + tv->tv_usec/1000000.0;
103}
104
105void
Dmitry V. Levin447db452014-05-29 17:59:01 +0000106tv_add(struct timeval *tv, const struct timeval *a, const struct timeval *b)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000107{
108 tv->tv_sec = a->tv_sec + b->tv_sec;
109 tv->tv_usec = a->tv_usec + b->tv_usec;
Roland McGrath58372f52007-07-24 01:38:22 +0000110 if (tv->tv_usec >= 1000000) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000111 tv->tv_sec++;
112 tv->tv_usec -= 1000000;
113 }
114}
115
116void
Dmitry V. Levin447db452014-05-29 17:59:01 +0000117tv_sub(struct timeval *tv, const struct timeval *a, const struct timeval *b)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000118{
119 tv->tv_sec = a->tv_sec - b->tv_sec;
120 tv->tv_usec = a->tv_usec - b->tv_usec;
121 if (((long) tv->tv_usec) < 0) {
122 tv->tv_sec--;
123 tv->tv_usec += 1000000;
124 }
125}
126
127void
Dmitry V. Levin447db452014-05-29 17:59:01 +0000128tv_div(struct timeval *tv, const struct timeval *a, int n)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000129{
130 tv->tv_usec = (a->tv_sec % n * 1000000 + a->tv_usec + n / 2) / n;
131 tv->tv_sec = a->tv_sec / n + tv->tv_usec / 1000000;
132 tv->tv_usec %= 1000000;
133}
134
135void
Dmitry V. Levin447db452014-05-29 17:59:01 +0000136tv_mul(struct timeval *tv, const struct timeval *a, int n)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000137{
138 tv->tv_usec = a->tv_usec * n;
Dmitry V. Levinfefdd972007-06-29 21:25:56 +0000139 tv->tv_sec = a->tv_sec * n + tv->tv_usec / 1000000;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000140 tv->tv_usec %= 1000000;
141}
142
Dmitry V. Levinab9008b2007-01-11 22:05:04 +0000143const char *
Dmitry V. Levin3ed5d022014-09-10 13:46:04 +0000144xlookup(const struct xlat *xlat, const unsigned int val)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000145{
146 for (; xlat->str != NULL; xlat++)
147 if (xlat->val == val)
148 return xlat->str;
149 return NULL;
150}
151
Dmitry V. Levin4176d532014-09-21 22:42:45 +0000152static int
153xlat_bsearch_compare(const void *a, const void *b)
154{
155 const unsigned int val1 = (const unsigned long) a;
156 const unsigned int val2 = ((const struct xlat *) b)->val;
157 return (val1 > val2) ? 1 : (val1 < val2) ? -1 : 0;
158}
159
160const char *
161xlat_search(const struct xlat *xlat, const size_t nmemb, const unsigned int val)
162{
163 const struct xlat *e =
164 bsearch((const void*) (const unsigned long) val,
165 xlat, nmemb, sizeof(*xlat), xlat_bsearch_compare);
166
167 return e ? e->str : NULL;
168}
169
Denys Vlasenko0a295bc2011-09-01 16:31:48 +0200170#if !defined HAVE_STPCPY
Denys Vlasenko52845572011-08-31 12:07:38 +0200171char *
172stpcpy(char *dst, const char *src)
173{
174 while ((*dst = *src++) != '\0')
175 dst++;
176 return dst;
177}
Denys Vlasenko0a295bc2011-09-01 16:31:48 +0200178#endif
Denys Vlasenko52845572011-08-31 12:07:38 +0200179
Denys Vlasenkob338f2d2013-11-09 20:40:31 +0100180/* Find a next bit which is set.
181 * Starts testing at cur_bit.
182 * Returns -1 if no more bits are set.
183 *
184 * We never touch bytes we don't need to.
185 * On big-endian, array is assumed to consist of
186 * current_wordsize wide words: for example, is current_wordsize is 4,
187 * the bytes are walked in 3,2,1,0, 7,6,5,4, 11,10,9,8 ... sequence.
188 * On little-endian machines, word size is immaterial.
189 */
190int
191next_set_bit(const void *bit_array, unsigned cur_bit, unsigned size_bits)
192{
193 const unsigned endian = 1;
194 int little_endian = *(char*)&endian;
195
196 const uint8_t *array = bit_array;
197 unsigned pos = cur_bit / 8;
198 unsigned pos_xor_mask = little_endian ? 0 : current_wordsize-1;
199
200 for (;;) {
201 uint8_t bitmask;
202 uint8_t cur_byte;
203
204 if (cur_bit >= size_bits)
205 return -1;
206 cur_byte = array[pos ^ pos_xor_mask];
207 if (cur_byte == 0) {
208 cur_bit = (cur_bit + 8) & (-8);
209 pos++;
210 continue;
211 }
212 bitmask = 1 << (cur_bit & 7);
213 for (;;) {
214 if (cur_byte & bitmask)
215 return cur_bit;
216 cur_bit++;
217 if (cur_bit >= size_bits)
218 return -1;
219 bitmask <<= 1;
220 /* This check *can't be* optimized out: */
221 if (bitmask == 0)
222 break;
223 }
224 pos++;
225 }
226}
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000227/*
228 * Print entry in struct xlat table, if there.
229 */
230void
Dmitry V. Levin3ed5d022014-09-10 13:46:04 +0000231printxval(const struct xlat *xlat, const unsigned int val, const char *dflt)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000232{
Dmitry V. Levinab9008b2007-01-11 22:05:04 +0000233 const char *str = xlookup(xlat, val);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000234
235 if (str)
Denys Vlasenko5940e652011-09-01 09:55:05 +0200236 tprints(str);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000237 else
238 tprintf("%#x /* %s */", val, dflt);
239}
240
Andreas Schwabb5600fc2009-11-04 17:08:34 +0100241/*
Chris Metcalf879dddd2013-03-01 10:41:02 +0100242 * Print 64bit argument at position arg_no and return the index of the next
Andreas Schwabb5600fc2009-11-04 17:08:34 +0100243 * argument.
244 */
245int
Dmitry V. Levin3c49b022014-08-07 00:07:28 +0000246printllval(struct tcb *tcp, const char *format, int arg_no)
Andreas Schwabb5600fc2009-11-04 17:08:34 +0100247{
Dmitry V. Levin7a498be2013-05-04 19:51:57 +0000248#if SIZEOF_LONG > 4 && SIZEOF_LONG == SIZEOF_LONG_LONG
249# if SUPPORTED_PERSONALITIES > 1
250 if (current_wordsize > 4) {
251# endif
Chris Metcalf879dddd2013-03-01 10:41:02 +0100252 tprintf(format, tcp->u_arg[arg_no]);
253 arg_no++;
Dmitry V. Levin7a498be2013-05-04 19:51:57 +0000254# if SUPPORTED_PERSONALITIES > 1
Andreas Schwabb5600fc2009-11-04 17:08:34 +0100255 } else {
Dmitry V. Levin7a498be2013-05-04 19:51:57 +0000256# if defined(AARCH64) || defined(POWERPC64)
Dmitry V. Levin3c49b022014-08-07 00:07:28 +0000257 /* Align arg_no to the next even number. */
258 arg_no = (arg_no + 1) & 0xe;
Dmitry V. Levin7a498be2013-05-04 19:51:57 +0000259# endif
Chris Metcalf879dddd2013-03-01 10:41:02 +0100260 tprintf(format, LONG_LONG(tcp->u_arg[arg_no], tcp->u_arg[arg_no + 1]));
261 arg_no += 2;
Andreas Schwabb5600fc2009-11-04 17:08:34 +0100262 }
Dmitry V. Levin7a498be2013-05-04 19:51:57 +0000263# endif /* SUPPORTED_PERSONALITIES */
264#elif SIZEOF_LONG > 4
265# error Unsupported configuration: SIZEOF_LONG > 4 && SIZEOF_LONG_LONG > SIZEOF_LONG
266#elif defined LINUX_MIPSN32
267 tprintf(format, tcp->ext_arg[arg_no]);
Chris Metcalf879dddd2013-03-01 10:41:02 +0100268 arg_no++;
Dmitry V. Levin0b468832013-05-02 08:41:27 +0000269#elif defined X32
270 if (current_personality == 0) {
271 tprintf(format, tcp->ext_arg[arg_no]);
272 arg_no++;
273 } else {
274 tprintf(format, LONG_LONG(tcp->u_arg[arg_no], tcp->u_arg[arg_no + 1]));
275 arg_no += 2;
276 }
Denys Vlasenkoc9d0fc02013-02-17 22:41:33 +0100277#else
Dmitry V. Levin8e096c42013-05-06 18:23:01 +0000278# if defined __ARM_EABI__ || \
279 defined LINUX_MIPSO32 || \
280 defined POWERPC || \
281 defined XTENSA
Dmitry V. Levin3c49b022014-08-07 00:07:28 +0000282 /* Align arg_no to the next even number. */
283 arg_no = (arg_no + 1) & 0xe;
Dmitry V. Levin7a498be2013-05-04 19:51:57 +0000284# endif
Chris Metcalf879dddd2013-03-01 10:41:02 +0100285 tprintf(format, LONG_LONG(tcp->u_arg[arg_no], tcp->u_arg[arg_no + 1]));
286 arg_no += 2;
Denys Vlasenkoc9d0fc02013-02-17 22:41:33 +0100287#endif
Dmitry V. Levin7a498be2013-05-04 19:51:57 +0000288
Chris Metcalf879dddd2013-03-01 10:41:02 +0100289 return arg_no;
Andreas Schwabb5600fc2009-11-04 17:08:34 +0100290}
Andreas Schwabb5600fc2009-11-04 17:08:34 +0100291
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000292/*
293 * Interpret `xlat' as an array of flags
294 * print the entries whose bits are on in `flags'
295 * return # of flags printed.
296 */
Denys Vlasenko4924dbd2011-08-19 18:06:46 +0200297void
Denys Vlasenko12014262011-05-30 14:00:14 +0200298addflags(const struct xlat *xlat, int flags)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000299{
Denys Vlasenko4924dbd2011-08-19 18:06:46 +0200300 for (; xlat->str; xlat++) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000301 if (xlat->val && (flags & xlat->val) == xlat->val) {
302 tprintf("|%s", xlat->str);
303 flags &= ~xlat->val;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000304 }
305 }
306 if (flags) {
307 tprintf("|%#x", flags);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000308 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000309}
310
Roland McGratha6c0d8c2007-11-01 21:46:22 +0000311/*
Denys Vlasenko4924dbd2011-08-19 18:06:46 +0200312 * Interpret `xlat' as an array of flags.
Roland McGratha6c0d8c2007-11-01 21:46:22 +0000313 * Print to static string the entries whose bits are on in `flags'
314 * Return static string.
315 */
316const char *
317sprintflags(const char *prefix, const struct xlat *xlat, int flags)
318{
319 static char outstr[1024];
Denys Vlasenko52845572011-08-31 12:07:38 +0200320 char *outptr;
Roland McGratha6c0d8c2007-11-01 21:46:22 +0000321 int found = 0;
322
Denys Vlasenko52845572011-08-31 12:07:38 +0200323 outptr = stpcpy(outstr, prefix);
Roland McGratha6c0d8c2007-11-01 21:46:22 +0000324
325 for (; xlat->str; xlat++) {
326 if ((flags & xlat->val) == xlat->val) {
327 if (found)
Denys Vlasenko52845572011-08-31 12:07:38 +0200328 *outptr++ = '|';
329 outptr = stpcpy(outptr, xlat->str);
Roland McGratha6c0d8c2007-11-01 21:46:22 +0000330 found = 1;
Denys Vlasenko4f3df072012-01-29 22:38:35 +0100331 flags &= ~xlat->val;
332 if (!flags)
333 break;
Roland McGratha6c0d8c2007-11-01 21:46:22 +0000334 }
335 }
336 if (flags) {
337 if (found)
Denys Vlasenko52845572011-08-31 12:07:38 +0200338 *outptr++ = '|';
339 outptr += sprintf(outptr, "%#x", flags);
Roland McGratha6c0d8c2007-11-01 21:46:22 +0000340 }
341
342 return outstr;
343}
344
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000345int
Dmitry V. Levin30145dd2010-09-06 22:08:24 +0000346printflags(const struct xlat *xlat, int flags, const char *dflt)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000347{
348 int n;
Dmitry V. Levin30145dd2010-09-06 22:08:24 +0000349 const char *sep;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000350
351 if (flags == 0 && xlat->val == 0) {
Denys Vlasenko5940e652011-09-01 09:55:05 +0200352 tprints(xlat->str);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000353 return 1;
354 }
355
356 sep = "";
357 for (n = 0; xlat->str; xlat++) {
358 if (xlat->val && (flags & xlat->val) == xlat->val) {
359 tprintf("%s%s", sep, xlat->str);
360 flags &= ~xlat->val;
361 sep = "|";
362 n++;
363 }
364 }
Roland McGrathb2dee132005-06-01 19:02:36 +0000365
366 if (n) {
367 if (flags) {
368 tprintf("%s%#x", sep, flags);
369 n++;
370 }
371 } else {
372 if (flags) {
373 tprintf("%#x", flags);
374 if (dflt)
375 tprintf(" /* %s */", dflt);
376 } else {
377 if (dflt)
Denys Vlasenko60fe8c12011-09-01 10:00:28 +0200378 tprints("0");
Roland McGrathb2dee132005-06-01 19:02:36 +0000379 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000380 }
Roland McGrathb2dee132005-06-01 19:02:36 +0000381
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000382 return n;
383}
384
385void
Dmitry V. Levin30145dd2010-09-06 22:08:24 +0000386printnum(struct tcb *tcp, long addr, const char *fmt)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000387{
Roland McGratheb285352003-01-14 09:59:00 +0000388 long num;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000389
390 if (!addr) {
Denys Vlasenko60fe8c12011-09-01 10:00:28 +0200391 tprints("NULL");
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000392 return;
393 }
394 if (umove(tcp, addr, &num) < 0) {
395 tprintf("%#lx", addr);
396 return;
397 }
Denys Vlasenko60fe8c12011-09-01 10:00:28 +0200398 tprints("[");
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000399 tprintf(fmt, num);
Denys Vlasenko60fe8c12011-09-01 10:00:28 +0200400 tprints("]");
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000401}
402
Roland McGrath6bc12202003-11-13 22:32:27 +0000403void
Dmitry V. Levin30145dd2010-09-06 22:08:24 +0000404printnum_int(struct tcb *tcp, long addr, const char *fmt)
Roland McGrath9814a942005-07-04 23:28:10 +0000405{
406 int num;
407
408 if (!addr) {
Denys Vlasenko60fe8c12011-09-01 10:00:28 +0200409 tprints("NULL");
Roland McGrath9814a942005-07-04 23:28:10 +0000410 return;
411 }
412 if (umove(tcp, addr, &num) < 0) {
413 tprintf("%#lx", addr);
414 return;
415 }
Denys Vlasenko60fe8c12011-09-01 10:00:28 +0200416 tprints("[");
Roland McGrath9814a942005-07-04 23:28:10 +0000417 tprintf(fmt, num);
Denys Vlasenko60fe8c12011-09-01 10:00:28 +0200418 tprints("]");
Roland McGrath9814a942005-07-04 23:28:10 +0000419}
420
421void
Dmitry V. Levin31382132011-03-04 05:08:02 +0300422printfd(struct tcb *tcp, int fd)
423{
Denys Vlasenko61ad0a42013-03-06 18:24:34 +0100424 char path[PATH_MAX + 1];
Dmitry V. Levin2f6510c2014-08-21 03:17:48 +0000425 if (show_fd_path && getfdpath(tcp, fd, path, sizeof(path)) >= 0) {
426 static const char socket_prefix[] = "socket:[";
427 const size_t socket_prefix_len = sizeof(socket_prefix) - 1;
428 size_t path_len;
Grant Edwards8a082772011-04-07 20:25:40 +0000429
Dmitry V. Levin2f6510c2014-08-21 03:17:48 +0000430 if (show_fd_path > 1 &&
431 strncmp(path, socket_prefix, socket_prefix_len) == 0 &&
432 path[(path_len = strlen(path)) - 1] == ']') {
433 unsigned long inodenr;
434 inodenr = strtoul(path + socket_prefix_len, NULL, 10);
435 tprintf("%d<", fd);
436 if (!print_sockaddr_by_inode(inodenr))
437 tprints(path);
438 tprints(">");
439 } else {
440 tprintf("%d<%s>", fd, path);
441 }
442 } else
Grant Edwards8a082772011-04-07 20:25:40 +0000443 tprintf("%d", fd);
Dmitry V. Levin31382132011-03-04 05:08:02 +0300444}
445
446void
Denys Vlasenko12014262011-05-30 14:00:14 +0200447printuid(const char *text, unsigned long uid)
Roland McGrath6bc12202003-11-13 22:32:27 +0000448{
Dmitry V. Levin3ed5d022014-09-10 13:46:04 +0000449 tprintf(((long) uid == -1) ? "%s%ld" : "%s%lu", text, uid);
Roland McGrath6bc12202003-11-13 22:32:27 +0000450}
451
Dmitry V. Levina501f142008-11-10 23:19:13 +0000452/*
453 * Quote string `instr' of length `size'
454 * Write up to (3 + `size' * 4) bytes to `outstr' buffer.
Denys Vlasenkob5d43b82012-04-28 14:58:35 +0200455 * If `len' is -1, treat `instr' as a NUL-terminated string
Dmitry V. Levina501f142008-11-10 23:19:13 +0000456 * and quote at most (`size' - 1) bytes.
Denys Vlasenko6cecba52012-01-20 11:56:00 +0100457 *
Denys Vlasenkob5d43b82012-04-28 14:58:35 +0200458 * Returns 0 if len == -1 and NUL was seen, 1 otherwise.
Denys Vlasenko6cecba52012-01-20 11:56:00 +0100459 * Note that if len >= 0, always returns 1.
Dmitry V. Levina501f142008-11-10 23:19:13 +0000460 */
Mike Frysingerebee04c2012-04-17 22:19:31 -0400461int
Denys Vlasenkob5d43b82012-04-28 14:58:35 +0200462string_quote(const char *instr, char *outstr, long len, int size)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000463{
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000464 const unsigned char *ustr = (const unsigned char *) instr;
465 char *s = outstr;
Denys Vlasenko8778bff2011-08-31 12:22:56 +0200466 int usehex, c, i, eol;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000467
Denys Vlasenko8778bff2011-08-31 12:22:56 +0200468 eol = 0x100; /* this can never match a char */
Denys Vlasenkob5d43b82012-04-28 14:58:35 +0200469 if (len == -1) {
Denys Vlasenko8778bff2011-08-31 12:22:56 +0200470 size--;
471 eol = '\0';
472 }
473
474 usehex = 0;
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000475 if (xflag > 1)
476 usehex = 1;
477 else if (xflag) {
Dmitry V. Levina501f142008-11-10 23:19:13 +0000478 /* Check for presence of symbol which require
479 to hex-quote the whole string. */
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000480 for (i = 0; i < size; ++i) {
481 c = ustr[i];
Dmitry V. Levina501f142008-11-10 23:19:13 +0000482 /* Check for NUL-terminated string. */
Denys Vlasenko8778bff2011-08-31 12:22:56 +0200483 if (c == eol)
484 break;
Denys Vlasenko5198ed42013-03-06 23:44:23 +0100485
486 /* Force hex unless c is printable or whitespace */
487 if (c > 0x7e) {
488 usehex = 1;
489 break;
490 }
491 /* In ASCII isspace is only these chars: "\t\n\v\f\r".
492 * They happen to have ASCII codes 9,10,11,12,13.
493 */
494 if (c < ' ' && (unsigned)(c - 9) >= 5) {
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000495 usehex = 1;
496 break;
497 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000498 }
499 }
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000500
501 *s++ = '\"';
502
503 if (usehex) {
Dmitry V. Levina501f142008-11-10 23:19:13 +0000504 /* Hex-quote the whole string. */
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000505 for (i = 0; i < size; ++i) {
506 c = ustr[i];
Dmitry V. Levina501f142008-11-10 23:19:13 +0000507 /* Check for NUL-terminated string. */
Denys Vlasenko8778bff2011-08-31 12:22:56 +0200508 if (c == eol)
509 goto asciz_ended;
510 *s++ = '\\';
511 *s++ = 'x';
512 *s++ = "0123456789abcdef"[c >> 4];
513 *s++ = "0123456789abcdef"[c & 0xf];
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000514 }
515 } else {
516 for (i = 0; i < size; ++i) {
517 c = ustr[i];
Dmitry V. Levina501f142008-11-10 23:19:13 +0000518 /* Check for NUL-terminated string. */
Denys Vlasenko8778bff2011-08-31 12:22:56 +0200519 if (c == eol)
520 goto asciz_ended;
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000521 switch (c) {
522 case '\"': case '\\':
523 *s++ = '\\';
524 *s++ = c;
525 break;
526 case '\f':
527 *s++ = '\\';
528 *s++ = 'f';
529 break;
530 case '\n':
531 *s++ = '\\';
532 *s++ = 'n';
533 break;
534 case '\r':
535 *s++ = '\\';
536 *s++ = 'r';
537 break;
538 case '\t':
539 *s++ = '\\';
540 *s++ = 't';
541 break;
542 case '\v':
543 *s++ = '\\';
544 *s++ = 'v';
545 break;
546 default:
Denys Vlasenko5198ed42013-03-06 23:44:23 +0100547 if (c >= ' ' && c <= 0x7e)
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000548 *s++ = c;
Denys Vlasenko8778bff2011-08-31 12:22:56 +0200549 else {
550 /* Print \octal */
551 *s++ = '\\';
552 if (i + 1 < size
553 && ustr[i + 1] >= '0'
554 && ustr[i + 1] <= '9'
555 ) {
556 /* Print \ooo */
557 *s++ = '0' + (c >> 6);
558 *s++ = '0' + ((c >> 3) & 0x7);
559 } else {
560 /* Print \[[o]o]o */
561 if ((c >> 3) != 0) {
562 if ((c >> 6) != 0)
563 *s++ = '0' + (c >> 6);
564 *s++ = '0' + ((c >> 3) & 0x7);
565 }
566 }
567 *s++ = '0' + (c & 0x7);
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000568 }
569 break;
570 }
571 }
572 }
573
574 *s++ = '\"';
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000575 *s = '\0';
Roland McGrath6d970322007-11-01 23:53:59 +0000576
Denys Vlasenko8778bff2011-08-31 12:22:56 +0200577 /* Return zero if we printed entire ASCIZ string (didn't truncate it) */
Denys Vlasenkob5d43b82012-04-28 14:58:35 +0200578 if (len == -1 && ustr[i] == '\0') {
Denys Vlasenko8778bff2011-08-31 12:22:56 +0200579 /* We didn't see NUL yet (otherwise we'd jump to 'asciz_ended')
580 * but next char is NUL.
581 */
582 return 0;
583 }
584
585 return 1;
586
587 asciz_ended:
588 *s++ = '\"';
589 *s = '\0';
590 /* Return zero: we printed entire ASCIZ string (didn't truncate it) */
591 return 0;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000592}
593
Dmitry V. Levina501f142008-11-10 23:19:13 +0000594/*
595 * Print path string specified by address `addr' and length `n'.
596 * If path length exceeds `n', append `...' to the output.
597 */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000598void
Dmitry V. Levin3ed5d022014-09-10 13:46:04 +0000599printpathn(struct tcb *tcp, long addr, unsigned int n)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000600{
Denys Vlasenkob3c52cf2012-01-19 17:20:23 +0100601 char path[MAXPATHLEN + 1];
Denys Vlasenko6cecba52012-01-20 11:56:00 +0100602 int nul_seen;
Denys Vlasenkob3c52cf2012-01-19 17:20:23 +0100603
Dmitry V. Levina501f142008-11-10 23:19:13 +0000604 if (!addr) {
Denys Vlasenko60fe8c12011-09-01 10:00:28 +0200605 tprints("NULL");
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000606 return;
607 }
608
Denys Vlasenko6cecba52012-01-20 11:56:00 +0100609 /* Cap path length to the path buffer size */
Dmitry V. Levina501f142008-11-10 23:19:13 +0000610 if (n > sizeof path - 1)
611 n = sizeof path - 1;
Dmitry V. Levina501f142008-11-10 23:19:13 +0000612
613 /* Fetch one byte more to find out whether path length > n. */
Denys Vlasenko6cecba52012-01-20 11:56:00 +0100614 nul_seen = umovestr(tcp, addr, n + 1, path);
615 if (nul_seen < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000616 tprintf("%#lx", addr);
617 else {
Denys Vlasenkob3c52cf2012-01-19 17:20:23 +0100618 char *outstr;
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000619
Denys Vlasenko6cecba52012-01-20 11:56:00 +0100620 path[n] = '\0';
Denys Vlasenkob3c52cf2012-01-19 17:20:23 +0100621 n++;
Denys Vlasenko6cecba52012-01-20 11:56:00 +0100622 outstr = alloca(4 * n); /* 4*(n-1) + 3 for quotes and NUL */
Denys Vlasenkob3c52cf2012-01-19 17:20:23 +0100623 string_quote(path, outstr, -1, n);
624 tprints(outstr);
Denys Vlasenko6cecba52012-01-20 11:56:00 +0100625 if (!nul_seen)
Denys Vlasenkob3c52cf2012-01-19 17:20:23 +0100626 tprints("...");
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000627 }
628}
629
630void
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000631printpath(struct tcb *tcp, long addr)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000632{
Denys Vlasenkob3c52cf2012-01-19 17:20:23 +0100633 /* Size must correspond to char path[] size in printpathn */
634 printpathn(tcp, addr, MAXPATHLEN);
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000635}
636
Dmitry V. Levina501f142008-11-10 23:19:13 +0000637/*
638 * Print string specified by address `addr' and length `len'.
639 * If `len' < 0, treat the string as a NUL-terminated string.
640 * If string length exceeds `max_strlen', append `...' to the output.
641 */
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000642void
Denys Vlasenkob5d43b82012-04-28 14:58:35 +0200643printstr(struct tcb *tcp, long addr, long len)
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000644{
645 static char *str = NULL;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000646 static char *outstr;
Dmitry V. Levin3ed5d022014-09-10 13:46:04 +0000647 unsigned int size;
Denys Vlasenkob3c52cf2012-01-19 17:20:23 +0100648 int ellipsis;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000649
650 if (!addr) {
Denys Vlasenko60fe8c12011-09-01 10:00:28 +0200651 tprints("NULL");
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000652 return;
653 }
Dmitry V. Levina501f142008-11-10 23:19:13 +0000654 /* Allocate static buffers if they are not allocated yet. */
Denys Vlasenko1d46ba52011-08-31 14:00:02 +0200655 if (!str) {
Dmitry V. Levin378f9c52012-03-25 22:56:53 +0000656 unsigned int outstr_size = 4 * max_strlen + /*for quotes and NUL:*/ 3;
657
658 if (outstr_size / 4 != max_strlen)
659 die_out_of_memory();
Dmitry V. Levina501f142008-11-10 23:19:13 +0000660 str = malloc(max_strlen + 1);
Denys Vlasenko1d46ba52011-08-31 14:00:02 +0200661 if (!str)
662 die_out_of_memory();
Dmitry V. Levin378f9c52012-03-25 22:56:53 +0000663 outstr = malloc(outstr_size);
Denys Vlasenko1d46ba52011-08-31 14:00:02 +0200664 if (!outstr)
665 die_out_of_memory();
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000666 }
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000667
Denys Vlasenkob5d43b82012-04-28 14:58:35 +0200668 if (len == -1) {
Dmitry V. Levina501f142008-11-10 23:19:13 +0000669 /*
670 * Treat as a NUL-terminated string: fetch one byte more
671 * because string_quote() quotes one byte less.
672 */
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000673 size = max_strlen + 1;
674 if (umovestr(tcp, addr, size, str) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000675 tprintf("%#lx", addr);
676 return;
677 }
678 }
679 else {
Denys Vlasenkob5d43b82012-04-28 14:58:35 +0200680 size = max_strlen;
681 if (size > (unsigned long)len)
682 size = (unsigned long)len;
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000683 if (umoven(tcp, addr, size, str) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000684 tprintf("%#lx", addr);
685 return;
686 }
687 }
688
Denys Vlasenko6cecba52012-01-20 11:56:00 +0100689 /* If string_quote didn't see NUL and (it was supposed to be ASCIZ str
690 * or we were requested to print more than -s NUM chars)...
691 */
Denys Vlasenkob3c52cf2012-01-19 17:20:23 +0100692 ellipsis = (string_quote(str, outstr, len, size) &&
Dmitry V. Levin3ed5d022014-09-10 13:46:04 +0000693 (len < 0 || (unsigned long) len > max_strlen));
Roland McGratha503dcf2007-08-02 02:06:26 +0000694
Denys Vlasenkob3c52cf2012-01-19 17:20:23 +0100695 tprints(outstr);
696 if (ellipsis)
697 tprints("...");
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000698}
699
John Hughes1d08dcf2001-07-10 13:48:44 +0000700void
Denys Vlasenko12014262011-05-30 14:00:14 +0200701dumpiov(struct tcb *tcp, int len, long addr)
John Hughes1d08dcf2001-07-10 13:48:44 +0000702{
Denys Vlasenko84703742012-02-25 02:38:52 +0100703#if SUPPORTED_PERSONALITIES > 1
Dmitry V. Levin4ebb4e32006-12-13 17:08:08 +0000704 union {
705 struct { u_int32_t base; u_int32_t len; } *iov32;
706 struct { u_int64_t base; u_int64_t len; } *iov64;
707 } iovu;
708#define iov iovu.iov64
709#define sizeof_iov \
Denys Vlasenko9fd4f962012-03-19 09:36:42 +0100710 (current_wordsize == 4 ? sizeof(*iovu.iov32) : sizeof(*iovu.iov64))
Dmitry V. Levin4ebb4e32006-12-13 17:08:08 +0000711#define iov_iov_base(i) \
Denys Vlasenko9fd4f962012-03-19 09:36:42 +0100712 (current_wordsize == 4 ? (uint64_t) iovu.iov32[i].base : iovu.iov64[i].base)
Dmitry V. Levin4ebb4e32006-12-13 17:08:08 +0000713#define iov_iov_len(i) \
Denys Vlasenko9fd4f962012-03-19 09:36:42 +0100714 (current_wordsize == 4 ? (uint64_t) iovu.iov32[i].len : iovu.iov64[i].len)
Dmitry V. Levin4ebb4e32006-12-13 17:08:08 +0000715#else
John Hughes1d08dcf2001-07-10 13:48:44 +0000716 struct iovec *iov;
Dmitry V. Levin4ebb4e32006-12-13 17:08:08 +0000717#define sizeof_iov sizeof(*iov)
718#define iov_iov_base(i) iov[i].iov_base
719#define iov_iov_len(i) iov[i].iov_len
720#endif
John Hughes1d08dcf2001-07-10 13:48:44 +0000721 int i;
Denys Vlasenko79a79ea2011-09-01 16:35:44 +0200722 unsigned size;
John Hughes1d08dcf2001-07-10 13:48:44 +0000723
Denys Vlasenko79a79ea2011-09-01 16:35:44 +0200724 size = sizeof_iov * len;
725 /* Assuming no sane program has millions of iovs */
726 if ((unsigned)len > 1024*1024 /* insane or negative size? */
Dmitry V. Levin4ebb4e32006-12-13 17:08:08 +0000727 || (iov = malloc(size)) == NULL) {
Denys Vlasenko79a79ea2011-09-01 16:35:44 +0200728 fprintf(stderr, "Out of memory\n");
729 return;
John Hughes1d08dcf2001-07-10 13:48:44 +0000730 }
Roland McGrathaa524c82005-06-01 19:22:06 +0000731 if (umoven(tcp, addr, size, (char *) iov) >= 0) {
John Hughes1d08dcf2001-07-10 13:48:44 +0000732 for (i = 0; i < len; i++) {
Denys Vlasenkoadedb512008-12-30 18:47:55 +0000733 /* include the buffer number to make it easy to
734 * match up the trace with the source */
735 tprintf(" * %lu bytes in buffer %d\n",
736 (unsigned long)iov_iov_len(i), i);
737 dumpstr(tcp, (long) iov_iov_base(i),
738 iov_iov_len(i));
739 }
John Hughes1d08dcf2001-07-10 13:48:44 +0000740 }
Denys Vlasenko79a79ea2011-09-01 16:35:44 +0200741 free(iov);
Dmitry V. Levin4ebb4e32006-12-13 17:08:08 +0000742#undef sizeof_iov
743#undef iov_iov_base
744#undef iov_iov_len
745#undef iov
John Hughes1d08dcf2001-07-10 13:48:44 +0000746}
John Hughes1d08dcf2001-07-10 13:48:44 +0000747
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000748void
Denys Vlasenko12014262011-05-30 14:00:14 +0200749dumpstr(struct tcb *tcp, long addr, int len)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000750{
751 static int strsize = -1;
752 static unsigned char *str;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000753
Denys Vlasenko76325802013-02-22 14:47:39 +0100754 char outbuf[
755 (
756 (sizeof(
757 "xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx "
758 "1234567890123456") + /*in case I'm off by few:*/ 4)
759 /*align to 8 to make memset easier:*/ + 7) & -8
760 ];
761 const unsigned char *src;
762 int i;
763
764 memset(outbuf, ' ', sizeof(outbuf));
765
766 if (strsize < len + 16) {
Denys Vlasenko5d645812011-08-20 12:48:18 +0200767 free(str);
Denys Vlasenko76325802013-02-22 14:47:39 +0100768 str = malloc(len + 16);
Denys Vlasenko79a79ea2011-09-01 16:35:44 +0200769 if (!str) {
770 strsize = -1;
771 fprintf(stderr, "Out of memory\n");
772 return;
773 }
Denys Vlasenko76325802013-02-22 14:47:39 +0100774 strsize = len + 16;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000775 }
776
777 if (umoven(tcp, addr, len, (char *) str) < 0)
778 return;
779
Denys Vlasenko76325802013-02-22 14:47:39 +0100780 /* Space-pad to 16 bytes */
781 i = len;
782 while (i & 0xf)
783 str[i++] = ' ';
Denys Vlasenko1d46ba52011-08-31 14:00:02 +0200784
Denys Vlasenko76325802013-02-22 14:47:39 +0100785 i = 0;
786 src = str;
787 while (i < len) {
788 char *dst = outbuf;
789 /* Hex dump */
790 do {
791 if (i < len) {
792 *dst++ = "0123456789abcdef"[*src >> 4];
793 *dst++ = "0123456789abcdef"[*src & 0xf];
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000794 }
795 else {
Denys Vlasenko76325802013-02-22 14:47:39 +0100796 *dst++ = ' ';
797 *dst++ = ' ';
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000798 }
Denys Vlasenko76325802013-02-22 14:47:39 +0100799 dst++; /* space is there by memset */
800 i++;
801 if ((i & 7) == 0)
802 dst++; /* space is there by memset */
803 src++;
804 } while (i & 0xf);
805 /* ASCII dump */
806 i -= 16;
807 src -= 16;
808 do {
809 if (*src >= ' ' && *src < 0x7f)
810 *dst++ = *src;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000811 else
Denys Vlasenko76325802013-02-22 14:47:39 +0100812 *dst++ = '.';
813 src++;
814 } while (++i & 0xf);
815 *dst = '\0';
Denys Vlasenkof90979b2013-02-22 15:00:11 +0100816 tprintf(" | %05x %s |\n", i - 16, outbuf);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000817 }
818}
819
Mike Frysinger612659e2012-02-14 14:38:28 +0100820#ifdef HAVE_PROCESS_VM_READV
821/* C library supports this, but the kernel might not. */
822static bool process_vm_readv_not_supported = 0;
823#else
824
Denys Vlasenko3af224c2012-01-28 01:46:33 +0100825/* Need to do this since process_vm_readv() is not yet available in libc.
826 * When libc is be updated, only "static bool process_vm_readv_not_supported"
827 * line should remain.
828 */
829#if !defined(__NR_process_vm_readv)
830# if defined(I386)
831# define __NR_process_vm_readv 347
832# elif defined(X86_64)
833# define __NR_process_vm_readv 310
834# elif defined(POWERPC)
835# define __NR_process_vm_readv 351
836# endif
837#endif
838
839#if defined(__NR_process_vm_readv)
840static bool process_vm_readv_not_supported = 0;
Mike Frysinger24ee60b2012-05-04 19:37:29 -0400841/* Have to avoid duplicating with the C library headers. */
842static ssize_t strace_process_vm_readv(pid_t pid,
Denys Vlasenko3af224c2012-01-28 01:46:33 +0100843 const struct iovec *lvec,
844 unsigned long liovcnt,
845 const struct iovec *rvec,
846 unsigned long riovcnt,
847 unsigned long flags)
848{
849 return syscall(__NR_process_vm_readv, (long)pid, lvec, liovcnt, rvec, riovcnt, flags);
850}
Mike Frysinger24ee60b2012-05-04 19:37:29 -0400851#define process_vm_readv strace_process_vm_readv
Denys Vlasenko3af224c2012-01-28 01:46:33 +0100852#else
853static bool process_vm_readv_not_supported = 1;
854# define process_vm_readv(...) (errno = ENOSYS, -1)
855#endif
Mike Frysinger612659e2012-02-14 14:38:28 +0100856
857#endif /* end of hack */
Denys Vlasenko3af224c2012-01-28 01:46:33 +0100858
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000859#define PAGMASK (~(PAGSIZ - 1))
860/*
861 * move `len' bytes of data from process `pid'
862 * at address `addr' to our space at `laddr'
863 */
864int
Denys Vlasenkoef2fbf82009-01-06 21:45:06 +0000865umoven(struct tcb *tcp, long addr, int len, char *laddr)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000866{
Roland McGratheb9e2e82009-06-02 16:49:22 -0700867 int pid = tcp->pid;
Dmitry V. Levin97005922013-02-26 21:16:22 +0000868 int n, m, nread;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000869 union {
870 long val;
871 char x[sizeof(long)];
872 } u;
873
Denys Vlasenko2544f982013-02-19 17:39:56 +0100874#if SUPPORTED_PERSONALITIES > 1 && SIZEOF_LONG > 4
Denys Vlasenko9fd4f962012-03-19 09:36:42 +0100875 if (current_wordsize < sizeof(addr))
876 addr &= (1ul << 8 * current_wordsize) - 1;
Denys Vlasenkod2a660f2012-02-25 00:43:22 +0100877#endif
878
Denys Vlasenko3af224c2012-01-28 01:46:33 +0100879 if (!process_vm_readv_not_supported) {
880 struct iovec local[1], remote[1];
881 int r;
882
883 local[0].iov_base = laddr;
884 remote[0].iov_base = (void*)addr;
885 local[0].iov_len = remote[0].iov_len = len;
Dmitry V. Levin97005922013-02-26 21:16:22 +0000886 r = process_vm_readv(pid, local, 1, remote, 1, 0);
Ben Noordhuis1d58fe92013-02-26 12:24:25 +0100887 if (r == len)
888 return 0;
Dmitry V. Levin97005922013-02-26 21:16:22 +0000889 if (r >= 0) {
890 error_msg("umoven: short read (%d < %d) @0x%lx",
891 r, len, addr);
892 return -1;
893 }
894 switch (errno) {
895 case ENOSYS:
Denys Vlasenko3af224c2012-01-28 01:46:33 +0100896 process_vm_readv_not_supported = 1;
Dmitry V. Levin97005922013-02-26 21:16:22 +0000897 break;
898 case ESRCH:
899 /* the process is gone */
900 return -1;
901 case EFAULT: case EIO: case EPERM:
902 /* address space is inaccessible */
903 return -1;
904 default:
905 /* all the rest is strange and should be reported */
Denys Vlasenko905e8e02013-02-26 12:30:09 +0100906 perror_msg("process_vm_readv");
Dmitry V. Levin97005922013-02-26 21:16:22 +0000907 return -1;
Denys Vlasenko3af224c2012-01-28 01:46:33 +0100908 }
Denys Vlasenko3af224c2012-01-28 01:46:33 +0100909 }
Denys Vlasenko3af224c2012-01-28 01:46:33 +0100910
Dmitry V. Levin97005922013-02-26 21:16:22 +0000911 nread = 0;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000912 if (addr & (sizeof(long) - 1)) {
913 /* addr not a multiple of sizeof(long) */
914 n = addr - (addr & -sizeof(long)); /* residue */
915 addr &= -sizeof(long); /* residue */
Roland McGratheb9e2e82009-06-02 16:49:22 -0700916 errno = 0;
917 u.val = ptrace(PTRACE_PEEKDATA, pid, (char *) addr, 0);
Dmitry V. Levin97005922013-02-26 21:16:22 +0000918 switch (errno) {
919 case 0:
920 break;
921 case ESRCH: case EINVAL:
922 /* these could be seen if the process is gone */
923 return -1;
924 case EFAULT: case EIO: case EPERM:
925 /* address space is inaccessible */
926 return -1;
927 default:
928 /* all the rest is strange and should be reported */
929 perror_msg("umoven: PTRACE_PEEKDATA pid:%d @0x%lx",
930 pid, addr);
931 return -1;
Roland McGratheb9e2e82009-06-02 16:49:22 -0700932 }
Denys Vlasenkoa47e6b92012-01-21 04:01:56 +0100933 m = MIN(sizeof(long) - n, len);
934 memcpy(laddr, &u.x[n], m);
Denys Vlasenko16940922013-03-01 18:52:59 +0100935 addr += sizeof(long);
936 laddr += m;
937 nread += m;
938 len -= m;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000939 }
940 while (len) {
Roland McGratheb9e2e82009-06-02 16:49:22 -0700941 errno = 0;
942 u.val = ptrace(PTRACE_PEEKDATA, pid, (char *) addr, 0);
Dmitry V. Levin97005922013-02-26 21:16:22 +0000943 switch (errno) {
944 case 0:
945 break;
946 case ESRCH: case EINVAL:
947 /* these could be seen if the process is gone */
948 return -1;
949 case EFAULT: case EIO: case EPERM:
950 /* address space is inaccessible */
951 if (nread) {
952 perror_msg("umoven: short read (%d < %d) @0x%lx",
953 nread, nread + len, addr - nread);
954 }
955 return -1;
956 default:
957 /* all the rest is strange and should be reported */
958 perror_msg("umoven: PTRACE_PEEKDATA pid:%d @0x%lx",
959 pid, addr);
960 return -1;
Roland McGratheb9e2e82009-06-02 16:49:22 -0700961 }
Denys Vlasenkoa47e6b92012-01-21 04:01:56 +0100962 m = MIN(sizeof(long), len);
963 memcpy(laddr, u.x, m);
Denys Vlasenko16940922013-03-01 18:52:59 +0100964 addr += sizeof(long);
965 laddr += m;
966 nread += m;
967 len -= m;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000968 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000969
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000970 return 0;
971}
972
973/*
Denys Vlasenko6cecba52012-01-20 11:56:00 +0100974 * Like `umove' but make the additional effort of looking
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000975 * for a terminating zero byte.
Denys Vlasenko6cecba52012-01-20 11:56:00 +0100976 *
977 * Returns < 0 on error, > 0 if NUL was seen,
978 * (TODO if useful: return count of bytes including NUL),
979 * else 0 if len bytes were read but no NUL byte seen.
980 *
981 * Note: there is no guarantee we won't overwrite some bytes
982 * in laddr[] _after_ terminating NUL (but, of course,
983 * we never write past laddr[len-1]).
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000984 */
985int
Denys Vlasenkoef2fbf82009-01-06 21:45:06 +0000986umovestr(struct tcb *tcp, long addr, int len, char *laddr)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000987{
Denys Vlasenko16940922013-03-01 18:52:59 +0100988#if SIZEOF_LONG == 4
989 const unsigned long x01010101 = 0x01010101ul;
990 const unsigned long x80808080 = 0x80808080ul;
991#elif SIZEOF_LONG == 8
992 const unsigned long x01010101 = 0x0101010101010101ul;
993 const unsigned long x80808080 = 0x8080808080808080ul;
994#else
995# error SIZEOF_LONG > 8
996#endif
997
Roland McGratheb9e2e82009-06-02 16:49:22 -0700998 int pid = tcp->pid;
Denys Vlasenko16940922013-03-01 18:52:59 +0100999 int n, m, nread;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001000 union {
Denys Vlasenko16940922013-03-01 18:52:59 +01001001 unsigned long val;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001002 char x[sizeof(long)];
1003 } u;
1004
Denys Vlasenko2544f982013-02-19 17:39:56 +01001005#if SUPPORTED_PERSONALITIES > 1 && SIZEOF_LONG > 4
Denys Vlasenko9fd4f962012-03-19 09:36:42 +01001006 if (current_wordsize < sizeof(addr))
1007 addr &= (1ul << 8 * current_wordsize) - 1;
Dmitry V. Levin856c7ed2011-12-26 20:12:02 +00001008#endif
1009
Dmitry V. Levin97005922013-02-26 21:16:22 +00001010 nread = 0;
Denys Vlasenko3af224c2012-01-28 01:46:33 +01001011 if (!process_vm_readv_not_supported) {
1012 struct iovec local[1], remote[1];
1013
1014 local[0].iov_base = laddr;
1015 remote[0].iov_base = (void*)addr;
1016
1017 while (len > 0) {
1018 int end_in_page;
1019 int r;
1020 int chunk_len;
1021
1022 /* Don't read kilobytes: most strings are short */
1023 chunk_len = len;
1024 if (chunk_len > 256)
1025 chunk_len = 256;
1026 /* Don't cross pages. I guess otherwise we can get EFAULT
1027 * and fail to notice that terminating NUL lies
1028 * in the existing (first) page.
1029 * (I hope there aren't arches with pages < 4K)
1030 */
1031 end_in_page = ((addr + chunk_len) & 4095);
1032 r = chunk_len - end_in_page;
1033 if (r > 0) /* if chunk_len > end_in_page */
1034 chunk_len = r; /* chunk_len -= end_in_page */
1035
1036 local[0].iov_len = remote[0].iov_len = chunk_len;
Dmitry V. Levin97005922013-02-26 21:16:22 +00001037 r = process_vm_readv(pid, local, 1, remote, 1, 0);
1038 if (r > 0) {
1039 if (memchr(local[0].iov_base, '\0', r))
1040 return 1;
1041 local[0].iov_base += r;
1042 remote[0].iov_base += r;
1043 len -= r;
1044 nread += r;
1045 continue;
Denys Vlasenko3af224c2012-01-28 01:46:33 +01001046 }
Dmitry V. Levin97005922013-02-26 21:16:22 +00001047 switch (errno) {
1048 case ENOSYS:
1049 process_vm_readv_not_supported = 1;
1050 goto vm_readv_didnt_work;
1051 case ESRCH:
1052 /* the process is gone */
1053 return -1;
1054 case EFAULT: case EIO: case EPERM:
1055 /* address space is inaccessible */
1056 if (nread) {
1057 perror_msg("umovestr: short read (%d < %d) @0x%lx",
1058 nread, nread + len, addr);
1059 }
1060 return -1;
1061 default:
1062 /* all the rest is strange and should be reported */
1063 perror_msg("process_vm_readv");
1064 return -1;
1065 }
Denys Vlasenko3af224c2012-01-28 01:46:33 +01001066 }
1067 return 0;
1068 }
1069 vm_readv_didnt_work:
1070
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001071 if (addr & (sizeof(long) - 1)) {
1072 /* addr not a multiple of sizeof(long) */
1073 n = addr - (addr & -sizeof(long)); /* residue */
1074 addr &= -sizeof(long); /* residue */
Roland McGratheb9e2e82009-06-02 16:49:22 -07001075 errno = 0;
1076 u.val = ptrace(PTRACE_PEEKDATA, pid, (char *)addr, 0);
Dmitry V. Levin97005922013-02-26 21:16:22 +00001077 switch (errno) {
1078 case 0:
1079 break;
1080 case ESRCH: case EINVAL:
1081 /* these could be seen if the process is gone */
1082 return -1;
1083 case EFAULT: case EIO: case EPERM:
1084 /* address space is inaccessible */
1085 return -1;
1086 default:
1087 /* all the rest is strange and should be reported */
1088 perror_msg("umovestr: PTRACE_PEEKDATA pid:%d @0x%lx",
1089 pid, addr);
1090 return -1;
Roland McGratheb9e2e82009-06-02 16:49:22 -07001091 }
Denys Vlasenkoa47e6b92012-01-21 04:01:56 +01001092 m = MIN(sizeof(long) - n, len);
1093 memcpy(laddr, &u.x[n], m);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001094 while (n & (sizeof(long) - 1))
1095 if (u.x[n++] == '\0')
Denys Vlasenko6cecba52012-01-20 11:56:00 +01001096 return 1;
Denys Vlasenko16940922013-03-01 18:52:59 +01001097 addr += sizeof(long);
1098 laddr += m;
1099 nread += m;
1100 len -= m;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001101 }
Denys Vlasenko16940922013-03-01 18:52:59 +01001102
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001103 while (len) {
Roland McGratheb9e2e82009-06-02 16:49:22 -07001104 errno = 0;
1105 u.val = ptrace(PTRACE_PEEKDATA, pid, (char *)addr, 0);
Dmitry V. Levin97005922013-02-26 21:16:22 +00001106 switch (errno) {
1107 case 0:
1108 break;
1109 case ESRCH: case EINVAL:
1110 /* these could be seen if the process is gone */
1111 return -1;
1112 case EFAULT: case EIO: case EPERM:
1113 /* address space is inaccessible */
1114 if (nread) {
1115 perror_msg("umovestr: short read (%d < %d) @0x%lx",
1116 nread, nread + len, addr - nread);
1117 }
1118 return -1;
1119 default:
1120 /* all the rest is strange and should be reported */
1121 perror_msg("umovestr: PTRACE_PEEKDATA pid:%d @0x%lx",
1122 pid, addr);
1123 return -1;
Roland McGratheb9e2e82009-06-02 16:49:22 -07001124 }
Denys Vlasenkoa47e6b92012-01-21 04:01:56 +01001125 m = MIN(sizeof(long), len);
1126 memcpy(laddr, u.x, m);
Denys Vlasenko16940922013-03-01 18:52:59 +01001127 /* "If a NUL char exists in this word" */
1128 if ((u.val - x01010101) & ~u.val & x80808080)
1129 return 1;
1130 addr += sizeof(long);
1131 laddr += m;
1132 nread += m;
1133 len -= m;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001134 }
John Hughesaa09c6b2001-05-15 14:53:43 +00001135 return 0;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001136}
1137
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001138int
Denys Vlasenko752e5a02013-06-28 14:35:47 +02001139upeek(int pid, long off, long *res)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001140{
1141 long val;
1142
Roland McGratheb9e2e82009-06-02 16:49:22 -07001143 errno = 0;
Denys Vlasenko752e5a02013-06-28 14:35:47 +02001144 val = ptrace(PTRACE_PEEKUSER, (pid_t)pid, (char *) off, 0);
Roland McGratheb9e2e82009-06-02 16:49:22 -07001145 if (val == -1 && errno) {
1146 if (errno != ESRCH) {
Denys Vlasenko752e5a02013-06-28 14:35:47 +02001147 perror_msg("upeek: PTRACE_PEEKUSER pid:%d @0x%lx)", pid, off);
Roland McGratheb9e2e82009-06-02 16:49:22 -07001148 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001149 return -1;
Roland McGratheb9e2e82009-06-02 16:49:22 -07001150 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001151 *res = val;
1152 return 0;
1153}
1154
Denys Vlasenkod27809c2013-02-12 12:50:10 +01001155/* Note! On new kernels (about 2.5.46+), we use PTRACE_O_TRACECLONE
1156 * and PTRACE_O_TRACE[V]FORK for tracing children.
1157 * If you are adding a new arch which is only supported by newer kernels,
1158 * you most likely don't need to add any code below
1159 * beside a dummy "return 0" block in change_syscall().
1160 */
1161
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001162/*
1163 * These #if's are huge, please indent them correctly.
1164 * It's easy to get confused otherwise.
1165 */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001166
Denys Vlasenko2d1e90f2012-02-25 02:46:14 +01001167#include "syscall.h"
Roland McGrath3291ef22008-05-20 00:34:34 +00001168
Denys Vlasenko2d1e90f2012-02-25 02:46:14 +01001169#ifndef CLONE_PTRACE
1170# define CLONE_PTRACE 0x00002000
1171#endif
1172#ifndef CLONE_VFORK
1173# define CLONE_VFORK 0x00004000
1174#endif
1175#ifndef CLONE_VM
1176# define CLONE_VM 0x00000100
1177#endif
Roland McGrathd81f1d92003-01-09 06:53:34 +00001178
Denys Vlasenko2d1e90f2012-02-25 02:46:14 +01001179#ifdef IA64
Roland McGrathd81f1d92003-01-09 06:53:34 +00001180
1181typedef unsigned long *arg_setup_state;
1182
1183static int
1184arg_setup(struct tcb *tcp, arg_setup_state *state)
1185{
Jan Kratochvil1f942712008-08-06 21:38:52 +00001186 unsigned long cfm, sof, sol;
1187 long bsp;
Roland McGrathd81f1d92003-01-09 06:53:34 +00001188
Denys Vlasenkoc09646a2013-07-01 12:28:17 +02001189 if (ia64_ia32mode) {
Jan Kratochvil1f942712008-08-06 21:38:52 +00001190 /* Satisfy a false GCC warning. */
1191 *state = NULL;
Roland McGrath08267b82004-02-20 22:56:43 +00001192 return 0;
Jan Kratochvil1f942712008-08-06 21:38:52 +00001193 }
Roland McGrath08267b82004-02-20 22:56:43 +00001194
Denys Vlasenko752e5a02013-06-28 14:35:47 +02001195 if (upeek(tcp->pid, PT_AR_BSP, &bsp) < 0)
Roland McGrathd81f1d92003-01-09 06:53:34 +00001196 return -1;
Denys Vlasenko752e5a02013-06-28 14:35:47 +02001197 if (upeek(tcp->pid, PT_CFM, (long *) &cfm) < 0)
Roland McGrathd81f1d92003-01-09 06:53:34 +00001198 return -1;
1199
1200 sof = (cfm >> 0) & 0x7f;
1201 sol = (cfm >> 7) & 0x7f;
Jan Kratochvil1f942712008-08-06 21:38:52 +00001202 bsp = (long) ia64_rse_skip_regs((unsigned long *) bsp, -sof + sol);
Roland McGrathd81f1d92003-01-09 06:53:34 +00001203
Jan Kratochvil1f942712008-08-06 21:38:52 +00001204 *state = (unsigned long *) bsp;
Roland McGrathd81f1d92003-01-09 06:53:34 +00001205 return 0;
1206}
1207
Denys Vlasenko2d1e90f2012-02-25 02:46:14 +01001208# define arg_finish_change(tcp, state) 0
Roland McGrathd81f1d92003-01-09 06:53:34 +00001209
Roland McGrathd81f1d92003-01-09 06:53:34 +00001210static int
Denys Vlasenko12014262011-05-30 14:00:14 +02001211get_arg0(struct tcb *tcp, arg_setup_state *state, long *valp)
Roland McGrathd81f1d92003-01-09 06:53:34 +00001212{
Roland McGrath08267b82004-02-20 22:56:43 +00001213 int ret;
1214
Denys Vlasenkoc09646a2013-07-01 12:28:17 +02001215 if (ia64_ia32mode)
Denys Vlasenko752e5a02013-06-28 14:35:47 +02001216 ret = upeek(tcp->pid, PT_R11, valp);
Roland McGrath08267b82004-02-20 22:56:43 +00001217 else
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001218 ret = umoven(tcp,
Roland McGrath08267b82004-02-20 22:56:43 +00001219 (unsigned long) ia64_rse_skip_regs(*state, 0),
1220 sizeof(long), (void *) valp);
1221 return ret;
Roland McGrathd81f1d92003-01-09 06:53:34 +00001222}
1223
1224static int
Denys Vlasenko12014262011-05-30 14:00:14 +02001225get_arg1(struct tcb *tcp, arg_setup_state *state, long *valp)
Roland McGrathd81f1d92003-01-09 06:53:34 +00001226{
Roland McGrath08267b82004-02-20 22:56:43 +00001227 int ret;
1228
Denys Vlasenkoc09646a2013-07-01 12:28:17 +02001229 if (ia64_ia32mode)
Denys Vlasenko752e5a02013-06-28 14:35:47 +02001230 ret = upeek(tcp->pid, PT_R9, valp);
Roland McGrath08267b82004-02-20 22:56:43 +00001231 else
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001232 ret = umoven(tcp,
Roland McGrath08267b82004-02-20 22:56:43 +00001233 (unsigned long) ia64_rse_skip_regs(*state, 1),
1234 sizeof(long), (void *) valp);
1235 return ret;
Roland McGrathd81f1d92003-01-09 06:53:34 +00001236}
Roland McGrathd81f1d92003-01-09 06:53:34 +00001237
1238static int
Denys Vlasenko12014262011-05-30 14:00:14 +02001239set_arg0(struct tcb *tcp, arg_setup_state *state, long val)
Roland McGrathd81f1d92003-01-09 06:53:34 +00001240{
Roland McGrath08267b82004-02-20 22:56:43 +00001241 int req = PTRACE_POKEDATA;
1242 void *ap;
1243
Denys Vlasenkoc09646a2013-07-01 12:28:17 +02001244 if (ia64_ia32mode) {
Roland McGrath08267b82004-02-20 22:56:43 +00001245 ap = (void *) (intptr_t) PT_R11; /* r11 == EBX */
1246 req = PTRACE_POKEUSER;
1247 } else
1248 ap = ia64_rse_skip_regs(*state, 0);
Roland McGratheb9e2e82009-06-02 16:49:22 -07001249 errno = 0;
1250 ptrace(req, tcp->pid, ap, val);
1251 return errno ? -1 : 0;
Roland McGrathd81f1d92003-01-09 06:53:34 +00001252}
1253
1254static int
Denys Vlasenko12014262011-05-30 14:00:14 +02001255set_arg1(struct tcb *tcp, arg_setup_state *state, long val)
Roland McGrathd81f1d92003-01-09 06:53:34 +00001256{
Roland McGrath08267b82004-02-20 22:56:43 +00001257 int req = PTRACE_POKEDATA;
1258 void *ap;
1259
Denys Vlasenkoc09646a2013-07-01 12:28:17 +02001260 if (ia64_ia32mode) {
Roland McGrath08267b82004-02-20 22:56:43 +00001261 ap = (void *) (intptr_t) PT_R9; /* r9 == ECX */
1262 req = PTRACE_POKEUSER;
1263 } else
1264 ap = ia64_rse_skip_regs(*state, 1);
Roland McGratheb9e2e82009-06-02 16:49:22 -07001265 errno = 0;
1266 ptrace(req, tcp->pid, ap, val);
1267 return errno ? -1 : 0;
Roland McGrathd81f1d92003-01-09 06:53:34 +00001268}
1269
Roland McGrathb659f872008-07-18 01:19:36 +00001270/* ia64 does not return the input arguments from functions (and syscalls)
1271 according to ia64 RSE (Register Stack Engine) behavior. */
1272
Denys Vlasenko2d1e90f2012-02-25 02:46:14 +01001273# define restore_arg0(tcp, state, val) ((void) (state), 0)
1274# define restore_arg1(tcp, state, val) ((void) (state), 0)
Roland McGrathb659f872008-07-18 01:19:36 +00001275
Denys Vlasenko2d1e90f2012-02-25 02:46:14 +01001276#elif defined(SPARC) || defined(SPARC64)
Roland McGrathd81f1d92003-01-09 06:53:34 +00001277
Denys Vlasenkoce7d9532013-02-05 16:36:13 +01001278# if defined(SPARC64)
1279# undef PTRACE_GETREGS
1280# define PTRACE_GETREGS PTRACE_GETREGS64
1281# undef PTRACE_SETREGS
1282# define PTRACE_SETREGS PTRACE_SETREGS64
1283# endif
1284
Mike Frysinger8566c502009-10-12 11:05:14 -04001285typedef struct pt_regs arg_setup_state;
Roland McGrathd81f1d92003-01-09 06:53:34 +00001286
Denys Vlasenko2d1e90f2012-02-25 02:46:14 +01001287# define arg_setup(tcp, state) \
1288 (ptrace(PTRACE_GETREGS, (tcp)->pid, (char *) (state), 0))
1289# define arg_finish_change(tcp, state) \
1290 (ptrace(PTRACE_SETREGS, (tcp)->pid, (char *) (state), 0))
Roland McGrathd81f1d92003-01-09 06:53:34 +00001291
Denys Vlasenko2d1e90f2012-02-25 02:46:14 +01001292# define get_arg0(tcp, state, valp) (*(valp) = (state)->u_regs[U_REG_O0], 0)
1293# define get_arg1(tcp, state, valp) (*(valp) = (state)->u_regs[U_REG_O1], 0)
1294# define set_arg0(tcp, state, val) ((state)->u_regs[U_REG_O0] = (val), 0)
1295# define set_arg1(tcp, state, val) ((state)->u_regs[U_REG_O1] = (val), 0)
1296# define restore_arg0(tcp, state, val) 0
Roland McGrathd81f1d92003-01-09 06:53:34 +00001297
Denys Vlasenko2d1e90f2012-02-25 02:46:14 +01001298#else /* other architectures */
Roland McGrathd81f1d92003-01-09 06:53:34 +00001299
Denys Vlasenko2d1e90f2012-02-25 02:46:14 +01001300# if defined S390 || defined S390X
Roland McGrath7b308222003-01-20 09:04:36 +00001301/* Note: this is only true for the `clone' system call, which handles
1302 arguments specially. We could as well say that its first two arguments
1303 are swapped relative to other architectures, but that would just be
1304 another #ifdef in the calls. */
Denys Vlasenko2d1e90f2012-02-25 02:46:14 +01001305# define arg0_offset PT_GPR3
1306# define arg1_offset PT_ORIGGPR2
1307# define restore_arg0(tcp, state, val) ((void) (state), 0)
1308# define restore_arg1(tcp, state, val) ((void) (state), 0)
1309# define arg0_index 1
1310# define arg1_index 0
1311# elif defined(ALPHA) || defined(MIPS)
1312# define arg0_offset REG_A0
1313# define arg1_offset (REG_A0+1)
Denys Vlasenko2d1e90f2012-02-25 02:46:14 +01001314# elif defined(POWERPC)
1315# define arg0_offset (sizeof(unsigned long)*PT_R3)
1316# define arg1_offset (sizeof(unsigned long)*PT_R4)
1317# define restore_arg0(tcp, state, val) ((void) (state), 0)
1318# elif defined(HPPA)
1319# define arg0_offset PT_GR26
1320# define arg1_offset (PT_GR26-4)
H.J. Lu35be5812012-04-16 13:00:01 +02001321# elif defined(X86_64) || defined(X32)
Denys Vlasenko2d1e90f2012-02-25 02:46:14 +01001322# define arg0_offset ((long)(8*(current_personality ? RBX : RDI)))
1323# define arg1_offset ((long)(8*(current_personality ? RCX : RSI)))
1324# elif defined(SH)
1325# define arg0_offset (4*(REG_REG0+4))
1326# define arg1_offset (4*(REG_REG0+5))
1327# elif defined(SH64)
1328 /* ABI defines arg0 & 1 in r2 & r3 */
1329# define arg0_offset (REG_OFFSET+16)
1330# define arg1_offset (REG_OFFSET+24)
1331# define restore_arg0(tcp, state, val) 0
1332# elif defined CRISV10 || defined CRISV32
1333# define arg0_offset (4*PT_R11)
1334# define arg1_offset (4*PT_ORIG_R10)
1335# define restore_arg0(tcp, state, val) 0
1336# define restore_arg1(tcp, state, val) 0
1337# define arg0_index 1
1338# define arg1_index 0
1339# else
1340# define arg0_offset 0
1341# define arg1_offset 4
1342# if defined ARM
1343# define restore_arg0(tcp, state, val) 0
1344# endif
1345# endif
Roland McGrathd81f1d92003-01-09 06:53:34 +00001346
1347typedef int arg_setup_state;
1348
Denys Vlasenko2d1e90f2012-02-25 02:46:14 +01001349# define arg_setup(tcp, state) (0)
1350# define arg_finish_change(tcp, state) 0
Denys Vlasenko752e5a02013-06-28 14:35:47 +02001351# define get_arg0(tcp, cookie, valp) (upeek((tcp)->pid, arg0_offset, (valp)))
1352# define get_arg1(tcp, cookie, valp) (upeek((tcp)->pid, arg1_offset, (valp)))
Roland McGrathd81f1d92003-01-09 06:53:34 +00001353
1354static int
Denys Vlasenko12014262011-05-30 14:00:14 +02001355set_arg0(struct tcb *tcp, void *cookie, long val)
Roland McGrathd81f1d92003-01-09 06:53:34 +00001356{
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001357 return ptrace(PTRACE_POKEUSER, tcp->pid, (char*)arg0_offset, val);
Roland McGrathd81f1d92003-01-09 06:53:34 +00001358}
1359
1360static int
Denys Vlasenko12014262011-05-30 14:00:14 +02001361set_arg1(struct tcb *tcp, void *cookie, long val)
Roland McGrathd81f1d92003-01-09 06:53:34 +00001362{
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001363 return ptrace(PTRACE_POKEUSER, tcp->pid, (char*)arg1_offset, val);
Roland McGrathd81f1d92003-01-09 06:53:34 +00001364}
1365
Denys Vlasenko2d1e90f2012-02-25 02:46:14 +01001366#endif /* architectures */
Roland McGrathd81f1d92003-01-09 06:53:34 +00001367
Denys Vlasenko2d1e90f2012-02-25 02:46:14 +01001368#ifndef restore_arg0
1369# define restore_arg0(tcp, state, val) set_arg0((tcp), (state), (val))
1370#endif
1371#ifndef restore_arg1
1372# define restore_arg1(tcp, state, val) set_arg1((tcp), (state), (val))
1373#endif
Roland McGrathd81f1d92003-01-09 06:53:34 +00001374
Denys Vlasenko2d1e90f2012-02-25 02:46:14 +01001375#ifndef arg0_index
1376# define arg0_index 0
1377# define arg1_index 1
1378#endif
Roland McGrath90d0afd2004-03-01 21:05:16 +00001379
James Hogan05eb9052012-11-29 17:37:37 +00001380static int
1381change_syscall(struct tcb *tcp, arg_setup_state *state, int new)
1382{
1383#if defined(I386)
1384 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(ORIG_EAX * 4), new) < 0)
1385 return -1;
1386 return 0;
Denys Vlasenkobf357fc2013-02-12 13:06:51 +01001387#elif defined(X86_64)
James Hogan05eb9052012-11-29 17:37:37 +00001388 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(ORIG_RAX * 8), new) < 0)
1389 return -1;
1390 return 0;
Denys Vlasenkobf357fc2013-02-12 13:06:51 +01001391#elif defined(X32)
1392 /* setbpt/clearbpt never used: */
1393 /* X32 is only supported since about linux-3.0.30 */
James Hogan05eb9052012-11-29 17:37:37 +00001394#elif defined(POWERPC)
1395 if (ptrace(PTRACE_POKEUSER, tcp->pid,
1396 (char*)(sizeof(unsigned long)*PT_R0), new) < 0)
1397 return -1;
1398 return 0;
1399#elif defined(S390) || defined(S390X)
1400 /* s390 linux after 2.4.7 has a hook in entry.S to allow this */
1401 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(PT_GPR2), new) < 0)
1402 return -1;
1403 return 0;
1404#elif defined(M68K)
1405 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(4*PT_ORIG_D0), new) < 0)
1406 return -1;
1407 return 0;
1408#elif defined(SPARC) || defined(SPARC64)
1409 state->u_regs[U_REG_G1] = new;
1410 return 0;
1411#elif defined(MIPS)
1412 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(REG_V0), new) < 0)
1413 return -1;
1414 return 0;
1415#elif defined(ALPHA)
1416 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(REG_A3), new) < 0)
1417 return -1;
1418 return 0;
1419#elif defined(AVR32)
Denys Vlasenkod27809c2013-02-12 12:50:10 +01001420 /* setbpt/clearbpt never used: */
1421 /* AVR32 is only supported since about linux-2.6.19 */
James Hogan05eb9052012-11-29 17:37:37 +00001422#elif defined(BFIN)
Denys Vlasenkod27809c2013-02-12 12:50:10 +01001423 /* setbpt/clearbpt never used: */
1424 /* Blackfin is only supported since about linux-2.6.23 */
James Hogan05eb9052012-11-29 17:37:37 +00001425#elif defined(IA64)
Denys Vlasenkoc09646a2013-07-01 12:28:17 +02001426 if (ia64_ia32mode) {
James Hogan05eb9052012-11-29 17:37:37 +00001427 switch (new) {
1428 case 2:
1429 break; /* x86 SYS_fork */
1430 case SYS_clone:
1431 new = 120;
1432 break;
1433 default:
1434 fprintf(stderr, "%s: unexpected syscall %d\n",
1435 __FUNCTION__, new);
1436 return -1;
1437 }
1438 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(PT_R1), new) < 0)
1439 return -1;
1440 } else if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(PT_R15), new) < 0)
1441 return -1;
1442 return 0;
1443#elif defined(HPPA)
1444 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(PT_GR20), new) < 0)
1445 return -1;
1446 return 0;
1447#elif defined(SH)
1448 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(4*(REG_REG0+3)), new) < 0)
1449 return -1;
1450 return 0;
1451#elif defined(SH64)
1452 /* Top half of reg encodes the no. of args n as 0x1n.
1453 Assume 0 args as kernel never actually checks... */
1454 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(REG_SYSCALL),
1455 0x100000 | new) < 0)
1456 return -1;
1457 return 0;
1458#elif defined(CRISV10) || defined(CRISV32)
1459 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(4*PT_R9), new) < 0)
1460 return -1;
1461 return 0;
1462#elif defined(ARM)
1463 /* Some kernels support this, some (pre-2.6.16 or so) don't. */
1464# ifndef PTRACE_SET_SYSCALL
1465# define PTRACE_SET_SYSCALL 23
1466# endif
1467 if (ptrace(PTRACE_SET_SYSCALL, tcp->pid, 0, new & 0xffff) != 0)
1468 return -1;
1469 return 0;
Denys Vlasenkobf357fc2013-02-12 13:06:51 +01001470#elif defined(AARCH64)
1471 /* setbpt/clearbpt never used: */
1472 /* AARCH64 is only supported since about linux-3.0.31 */
James Hogan05eb9052012-11-29 17:37:37 +00001473#elif defined(TILE)
Denys Vlasenkod27809c2013-02-12 12:50:10 +01001474 /* setbpt/clearbpt never used: */
1475 /* Tilera CPUs are only supported since about linux-2.6.34 */
James Hogan05eb9052012-11-29 17:37:37 +00001476#elif defined(MICROBLAZE)
Denys Vlasenkoa86696b2013-02-12 16:07:54 +01001477 /* setbpt/clearbpt never used: */
1478 /* microblaze is only supported since about linux-2.6.30 */
Christian Svensson492f81f2013-02-14 13:26:27 +01001479#elif defined(OR1K)
1480 /* never reached; OR1K is only supported by kernels since 3.1.0. */
James Hogan5f999a82013-02-22 14:44:10 +00001481#elif defined(METAG)
1482 /* setbpt/clearbpt never used: */
1483 /* Meta is only supported since linux-3.7 */
Chris Zankel8f636ed2013-03-25 10:22:07 -07001484#elif defined(XTENSA)
1485 /* setbpt/clearbpt never used: */
1486 /* Xtensa is only supported since linux 2.6.13 */
Vineet Gupta7daacbb2013-08-16 12:47:06 +05301487#elif defined(ARC)
1488 /* setbpt/clearbpt never used: */
1489 /* ARC only supported since 3.9 */
James Hogan05eb9052012-11-29 17:37:37 +00001490#else
1491#warning Do not know how to handle change_syscall for this architecture
1492#endif /* architecture */
1493 return -1;
1494}
1495
Roland McGrathd81f1d92003-01-09 06:53:34 +00001496int
Denys Vlasenko418d66a2009-01-17 01:52:54 +00001497setbpt(struct tcb *tcp)
Roland McGrathd81f1d92003-01-09 06:53:34 +00001498{
Roland McGrath3291ef22008-05-20 00:34:34 +00001499 static int clone_scno[SUPPORTED_PERSONALITIES] = { SYS_clone };
Roland McGrathd81f1d92003-01-09 06:53:34 +00001500 arg_setup_state state;
1501
1502 if (tcp->flags & TCB_BPTSET) {
1503 fprintf(stderr, "PANIC: TCB already set in pid %u\n", tcp->pid);
1504 return -1;
1505 }
1506
Roland McGrath3291ef22008-05-20 00:34:34 +00001507 /*
1508 * It's a silly kludge to initialize this with a search at runtime.
1509 * But it's better than maintaining another magic thing in the
1510 * godforsaken tables.
1511 */
1512 if (clone_scno[current_personality] == 0) {
Dmitry V. Levin3ed5d022014-09-10 13:46:04 +00001513 unsigned int i;
Roland McGrath3291ef22008-05-20 00:34:34 +00001514 for (i = 0; i < nsyscalls; ++i)
1515 if (sysent[i].sys_func == sys_clone) {
1516 clone_scno[current_personality] = i;
1517 break;
1518 }
1519 }
1520
Dmitry V. Levin65563152014-05-12 13:43:10 +00001521 if (tcp->s_ent->sys_func == sys_fork) {
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001522 if (arg_setup(tcp, &state) < 0
1523 || get_arg0(tcp, &state, &tcp->inst[0]) < 0
1524 || get_arg1(tcp, &state, &tcp->inst[1]) < 0
James Hogan05eb9052012-11-29 17:37:37 +00001525 || change_syscall(tcp, &state,
1526 clone_scno[current_personality]) < 0
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001527 || set_arg0(tcp, &state, CLONE_PTRACE|SIGCHLD) < 0
1528 || set_arg1(tcp, &state, 0) < 0
1529 || arg_finish_change(tcp, &state) < 0)
Roland McGrathd81f1d92003-01-09 06:53:34 +00001530 return -1;
Roland McGrathc9dc3c12004-03-01 20:57:09 +00001531 tcp->u_arg[arg0_index] = CLONE_PTRACE|SIGCHLD;
1532 tcp->u_arg[arg1_index] = 0;
Roland McGrathd81f1d92003-01-09 06:53:34 +00001533 tcp->flags |= TCB_BPTSET;
1534 return 0;
Dmitry V. Levin0c661512012-02-20 21:17:58 +00001535 }
Roland McGrathd81f1d92003-01-09 06:53:34 +00001536
Denys Vlasenko74ec14f2013-02-21 16:13:47 +01001537 if (tcp->s_ent->sys_func == sys_clone) {
Jan Kratochvil8fc95752008-08-06 21:43:35 +00001538 /* ia64 calls directly `clone (CLONE_VFORK | CLONE_VM)'
Dmitry V. Levin0c661512012-02-20 21:17:58 +00001539 contrary to x86 vfork above. Even on x86 we turn the
Jan Kratochvil8fc95752008-08-06 21:43:35 +00001540 vfork semantics into plain fork - each application must not
1541 depend on the vfork specifics according to POSIX. We would
1542 hang waiting for the parent resume otherwise. We need to
1543 clear also CLONE_VM but only in the CLONE_VFORK case as
1544 otherwise we would break pthread_create. */
1545
Denys Vlasenkoc133bf02011-06-23 21:57:54 +02001546 long new_arg0 = (tcp->u_arg[arg0_index] | CLONE_PTRACE);
1547 if (new_arg0 & CLONE_VFORK)
1548 new_arg0 &= ~(unsigned long)(CLONE_VFORK | CLONE_VM);
1549 if (arg_setup(tcp, &state) < 0
1550 || set_arg0(tcp, &state, new_arg0) < 0
1551 || arg_finish_change(tcp, &state) < 0)
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00001552 return -1;
Roland McGrathc9dc3c12004-03-01 20:57:09 +00001553 tcp->inst[0] = tcp->u_arg[arg0_index];
1554 tcp->inst[1] = tcp->u_arg[arg1_index];
Denys Vlasenko55980f52012-05-14 16:40:28 +02001555 tcp->flags |= TCB_BPTSET;
Roland McGrathd81f1d92003-01-09 06:53:34 +00001556 return 0;
Roland McGrathd81f1d92003-01-09 06:53:34 +00001557 }
1558
Dmitry V. Levin0c661512012-02-20 21:17:58 +00001559 fprintf(stderr, "PANIC: setbpt for syscall %ld on %u???\n",
1560 tcp->scno, tcp->pid);
Roland McGrathd81f1d92003-01-09 06:53:34 +00001561 return -1;
1562}
1563
1564int
Denys Vlasenko12014262011-05-30 14:00:14 +02001565clearbpt(struct tcb *tcp)
Roland McGrathd81f1d92003-01-09 06:53:34 +00001566{
1567 arg_setup_state state;
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001568 if (arg_setup(tcp, &state) < 0
James Hogan05eb9052012-11-29 17:37:37 +00001569 || change_syscall(tcp, &state, tcp->scno) < 0
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001570 || restore_arg0(tcp, &state, tcp->inst[0]) < 0
1571 || restore_arg1(tcp, &state, tcp->inst[1]) < 0
1572 || arg_finish_change(tcp, &state))
Denys Vlasenkoc133bf02011-06-23 21:57:54 +02001573 if (errno != ESRCH)
1574 return -1;
Roland McGrathd81f1d92003-01-09 06:53:34 +00001575 tcp->flags &= ~TCB_BPTSET;
1576 return 0;
1577}