blob: 10b873ca05c523f428f7e9cd91982eb5cfa122b5 [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>
John Hughes1d08dcf2001-07-10 13:48:44 +000038#if HAVE_SYS_UIO_H
Denys Vlasenko2d1e90f2012-02-25 02:46:14 +010039# include <sys/uio.h>
John Hughes1d08dcf2001-07-10 13:48:44 +000040#endif
Wichert Akkerman36915a11999-07-13 15:45:02 +000041
John Spencereb54c472012-12-03 00:27:22 +010042#if defined(__GLIBC__) && (__GLIBC__ < 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ < 1))
Denys Vlasenkoa6d91de2012-03-16 12:02:22 +010043# include <linux/ptrace.h>
Roland McGrath1e85cf92002-12-16 20:40:54 +000044#endif
Wichert Akkerman36915a11999-07-13 15:45:02 +000045
Denys Vlasenko84703742012-02-25 02:38:52 +010046#if defined(IA64)
Roland McGrathd81f1d92003-01-09 06:53:34 +000047# include <asm/ptrace_offsets.h>
48# include <asm/rse.h>
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +000049#endif
50
Wichert Akkerman36915a11999-07-13 15:45:02 +000051#ifdef HAVE_SYS_REG_H
Denys Vlasenko84703742012-02-25 02:38:52 +010052# include <sys/reg.h>
Wichert Akkerman76baf7c1999-02-19 00:21:36 +000053# define PTRACE_PEEKUSR PTRACE_PEEKUSER
Wichert Akkermanfaf72222000-02-19 23:59:03 +000054#elif defined(HAVE_LINUX_PTRACE_H)
Denys Vlasenko84703742012-02-25 02:38:52 +010055# undef PTRACE_SYSCALL
Roland McGrathce9f0742004-03-01 21:29:22 +000056# ifdef HAVE_STRUCT_IA64_FPREG
57# define ia64_fpreg XXX_ia64_fpreg
58# endif
59# ifdef HAVE_STRUCT_PT_ALL_USER_REGS
60# define pt_all_user_regs XXX_pt_all_user_regs
61# endif
Denys Vlasenko84703742012-02-25 02:38:52 +010062# include <linux/ptrace.h>
Roland McGrathce9f0742004-03-01 21:29:22 +000063# undef ia64_fpreg
64# undef pt_all_user_regs
Wichert Akkerman2e2553a1999-05-09 00:29:58 +000065#endif
66
Wichert Akkerman76baf7c1999-02-19 00:21:36 +000067/* macros */
68#ifndef MAX
Denys Vlasenko2d1e90f2012-02-25 02:46:14 +010069# define MAX(a,b) (((a) > (b)) ? (a) : (b))
Wichert Akkerman76baf7c1999-02-19 00:21:36 +000070#endif
71#ifndef MIN
Denys Vlasenko2d1e90f2012-02-25 02:46:14 +010072# define MIN(a,b) (((a) < (b)) ? (a) : (b))
Wichert Akkerman76baf7c1999-02-19 00:21:36 +000073#endif
74
Wichert Akkerman76baf7c1999-02-19 00:21:36 +000075int
Dmitry V. Levinccee1692012-03-25 21:49:48 +000076string_to_uint(const char *str)
77{
78 char *error;
79 long value;
80
81 if (!*str)
82 return -1;
83 errno = 0;
84 value = strtol(str, &error, 10);
85 if (errno || *error || value < 0 || (long)(int)value != value)
86 return -1;
87 return (int)value;
88}
89
90int
Denys Vlasenko12014262011-05-30 14:00:14 +020091tv_nz(struct timeval *a)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +000092{
93 return a->tv_sec || a->tv_usec;
94}
95
96int
Denys Vlasenko12014262011-05-30 14:00:14 +020097tv_cmp(struct timeval *a, struct timeval *b)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +000098{
99 if (a->tv_sec < b->tv_sec
100 || (a->tv_sec == b->tv_sec && a->tv_usec < b->tv_usec))
101 return -1;
102 if (a->tv_sec > b->tv_sec
103 || (a->tv_sec == b->tv_sec && a->tv_usec > b->tv_usec))
104 return 1;
105 return 0;
106}
107
108double
Denys Vlasenko12014262011-05-30 14:00:14 +0200109tv_float(struct timeval *tv)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000110{
111 return tv->tv_sec + tv->tv_usec/1000000.0;
112}
113
114void
Denys Vlasenko12014262011-05-30 14:00:14 +0200115tv_add(struct timeval *tv, struct timeval *a, struct timeval *b)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000116{
117 tv->tv_sec = a->tv_sec + b->tv_sec;
118 tv->tv_usec = a->tv_usec + b->tv_usec;
Roland McGrath58372f52007-07-24 01:38:22 +0000119 if (tv->tv_usec >= 1000000) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000120 tv->tv_sec++;
121 tv->tv_usec -= 1000000;
122 }
123}
124
125void
Denys Vlasenko12014262011-05-30 14:00:14 +0200126tv_sub(struct timeval *tv, struct timeval *a, struct timeval *b)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000127{
128 tv->tv_sec = a->tv_sec - b->tv_sec;
129 tv->tv_usec = a->tv_usec - b->tv_usec;
130 if (((long) tv->tv_usec) < 0) {
131 tv->tv_sec--;
132 tv->tv_usec += 1000000;
133 }
134}
135
136void
Denys Vlasenko12014262011-05-30 14:00:14 +0200137tv_div(struct timeval *tv, struct timeval *a, int n)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000138{
139 tv->tv_usec = (a->tv_sec % n * 1000000 + a->tv_usec + n / 2) / n;
140 tv->tv_sec = a->tv_sec / n + tv->tv_usec / 1000000;
141 tv->tv_usec %= 1000000;
142}
143
144void
Denys Vlasenko12014262011-05-30 14:00:14 +0200145tv_mul(struct timeval *tv, struct timeval *a, int n)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000146{
147 tv->tv_usec = a->tv_usec * n;
Dmitry V. Levinfefdd972007-06-29 21:25:56 +0000148 tv->tv_sec = a->tv_sec * n + tv->tv_usec / 1000000;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000149 tv->tv_usec %= 1000000;
150}
151
Dmitry V. Levinab9008b2007-01-11 22:05:04 +0000152const char *
153xlookup(const struct xlat *xlat, int val)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000154{
155 for (; xlat->str != NULL; xlat++)
156 if (xlat->val == val)
157 return xlat->str;
158 return NULL;
159}
160
Denys Vlasenko0a295bc2011-09-01 16:31:48 +0200161#if !defined HAVE_STPCPY
Denys Vlasenko52845572011-08-31 12:07:38 +0200162char *
163stpcpy(char *dst, const char *src)
164{
165 while ((*dst = *src++) != '\0')
166 dst++;
167 return dst;
168}
Denys Vlasenko0a295bc2011-09-01 16:31:48 +0200169#endif
Denys Vlasenko52845572011-08-31 12:07:38 +0200170
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000171/*
172 * Print entry in struct xlat table, if there.
173 */
174void
Dmitry V. Levinab9008b2007-01-11 22:05:04 +0000175printxval(const struct xlat *xlat, int val, const char *dflt)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000176{
Dmitry V. Levinab9008b2007-01-11 22:05:04 +0000177 const char *str = xlookup(xlat, val);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000178
179 if (str)
Denys Vlasenko5940e652011-09-01 09:55:05 +0200180 tprints(str);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000181 else
182 tprintf("%#x /* %s */", val, dflt);
183}
184
Andreas Schwabb5600fc2009-11-04 17:08:34 +0100185#if HAVE_LONG_LONG
186/*
187 * Print 64bit argument at position llarg and return the index of the next
188 * argument.
189 */
190int
191printllval(struct tcb *tcp, const char *format, int llarg)
192{
Denys Vlasenkoaa925db2012-02-25 15:19:02 +0100193# if defined(X86_64) || defined(POWERPC64)
Andreas Schwabb5600fc2009-11-04 17:08:34 +0100194 if (current_personality == 0) {
195 tprintf(format, tcp->u_arg[llarg]);
196 llarg++;
197 } else {
Andreas Schwabd69fa492010-07-12 21:39:57 +0200198# ifdef POWERPC64
199 /* Align 64bit argument to 64bit boundary. */
Denys Vlasenko4b08df42011-08-19 15:58:24 +0200200 llarg = (llarg + 1) & 0x1e;
Andreas Schwabd69fa492010-07-12 21:39:57 +0200201# endif
Andreas Schwabb5600fc2009-11-04 17:08:34 +0100202 tprintf(format, LONG_LONG(tcp->u_arg[llarg], tcp->u_arg[llarg + 1]));
203 llarg += 2;
204 }
Andreas Schwabd69fa492010-07-12 21:39:57 +0200205# elif defined IA64 || defined ALPHA
Andreas Schwabb5600fc2009-11-04 17:08:34 +0100206 tprintf(format, tcp->u_arg[llarg]);
207 llarg++;
H.J. Lu35be5812012-04-16 13:00:01 +0200208# elif defined LINUX_MIPSN32 || defined X32
Andreas Schwabb5600fc2009-11-04 17:08:34 +0100209 tprintf(format, tcp->ext_arg[llarg]);
210 llarg++;
211# else
212 tprintf(format, LONG_LONG(tcp->u_arg[llarg], tcp->u_arg[llarg + 1]));
213 llarg += 2;
214# endif
215 return llarg;
216}
217#endif
218
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000219/*
220 * Interpret `xlat' as an array of flags
221 * print the entries whose bits are on in `flags'
222 * return # of flags printed.
223 */
Denys Vlasenko4924dbd2011-08-19 18:06:46 +0200224void
Denys Vlasenko12014262011-05-30 14:00:14 +0200225addflags(const struct xlat *xlat, int flags)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000226{
Denys Vlasenko4924dbd2011-08-19 18:06:46 +0200227 for (; xlat->str; xlat++) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000228 if (xlat->val && (flags & xlat->val) == xlat->val) {
229 tprintf("|%s", xlat->str);
230 flags &= ~xlat->val;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000231 }
232 }
233 if (flags) {
234 tprintf("|%#x", flags);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000235 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000236}
237
Roland McGratha6c0d8c2007-11-01 21:46:22 +0000238/*
Denys Vlasenko4924dbd2011-08-19 18:06:46 +0200239 * Interpret `xlat' as an array of flags.
Roland McGratha6c0d8c2007-11-01 21:46:22 +0000240 * Print to static string the entries whose bits are on in `flags'
241 * Return static string.
242 */
243const char *
244sprintflags(const char *prefix, const struct xlat *xlat, int flags)
245{
246 static char outstr[1024];
Denys Vlasenko52845572011-08-31 12:07:38 +0200247 char *outptr;
Roland McGratha6c0d8c2007-11-01 21:46:22 +0000248 int found = 0;
249
Denys Vlasenko52845572011-08-31 12:07:38 +0200250 outptr = stpcpy(outstr, prefix);
Roland McGratha6c0d8c2007-11-01 21:46:22 +0000251
252 for (; xlat->str; xlat++) {
253 if ((flags & xlat->val) == xlat->val) {
254 if (found)
Denys Vlasenko52845572011-08-31 12:07:38 +0200255 *outptr++ = '|';
256 outptr = stpcpy(outptr, xlat->str);
Roland McGratha6c0d8c2007-11-01 21:46:22 +0000257 found = 1;
Denys Vlasenko4f3df072012-01-29 22:38:35 +0100258 flags &= ~xlat->val;
259 if (!flags)
260 break;
Roland McGratha6c0d8c2007-11-01 21:46:22 +0000261 }
262 }
263 if (flags) {
264 if (found)
Denys Vlasenko52845572011-08-31 12:07:38 +0200265 *outptr++ = '|';
266 outptr += sprintf(outptr, "%#x", flags);
Roland McGratha6c0d8c2007-11-01 21:46:22 +0000267 }
268
269 return outstr;
270}
271
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000272int
Dmitry V. Levin30145dd2010-09-06 22:08:24 +0000273printflags(const struct xlat *xlat, int flags, const char *dflt)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000274{
275 int n;
Dmitry V. Levin30145dd2010-09-06 22:08:24 +0000276 const char *sep;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000277
278 if (flags == 0 && xlat->val == 0) {
Denys Vlasenko5940e652011-09-01 09:55:05 +0200279 tprints(xlat->str);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000280 return 1;
281 }
282
283 sep = "";
284 for (n = 0; xlat->str; xlat++) {
285 if (xlat->val && (flags & xlat->val) == xlat->val) {
286 tprintf("%s%s", sep, xlat->str);
287 flags &= ~xlat->val;
288 sep = "|";
289 n++;
290 }
291 }
Roland McGrathb2dee132005-06-01 19:02:36 +0000292
293 if (n) {
294 if (flags) {
295 tprintf("%s%#x", sep, flags);
296 n++;
297 }
298 } else {
299 if (flags) {
300 tprintf("%#x", flags);
301 if (dflt)
302 tprintf(" /* %s */", dflt);
303 } else {
304 if (dflt)
Denys Vlasenko60fe8c12011-09-01 10:00:28 +0200305 tprints("0");
Roland McGrathb2dee132005-06-01 19:02:36 +0000306 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000307 }
Roland McGrathb2dee132005-06-01 19:02:36 +0000308
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000309 return n;
310}
311
312void
Dmitry V. Levin30145dd2010-09-06 22:08:24 +0000313printnum(struct tcb *tcp, long addr, const char *fmt)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000314{
Roland McGratheb285352003-01-14 09:59:00 +0000315 long num;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000316
317 if (!addr) {
Denys Vlasenko60fe8c12011-09-01 10:00:28 +0200318 tprints("NULL");
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000319 return;
320 }
321 if (umove(tcp, addr, &num) < 0) {
322 tprintf("%#lx", addr);
323 return;
324 }
Denys Vlasenko60fe8c12011-09-01 10:00:28 +0200325 tprints("[");
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000326 tprintf(fmt, num);
Denys Vlasenko60fe8c12011-09-01 10:00:28 +0200327 tprints("]");
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000328}
329
Roland McGrath6bc12202003-11-13 22:32:27 +0000330void
Dmitry V. Levin30145dd2010-09-06 22:08:24 +0000331printnum_int(struct tcb *tcp, long addr, const char *fmt)
Roland McGrath9814a942005-07-04 23:28:10 +0000332{
333 int num;
334
335 if (!addr) {
Denys Vlasenko60fe8c12011-09-01 10:00:28 +0200336 tprints("NULL");
Roland McGrath9814a942005-07-04 23:28:10 +0000337 return;
338 }
339 if (umove(tcp, addr, &num) < 0) {
340 tprintf("%#lx", addr);
341 return;
342 }
Denys Vlasenko60fe8c12011-09-01 10:00:28 +0200343 tprints("[");
Roland McGrath9814a942005-07-04 23:28:10 +0000344 tprintf(fmt, num);
Denys Vlasenko60fe8c12011-09-01 10:00:28 +0200345 tprints("]");
Roland McGrath9814a942005-07-04 23:28:10 +0000346}
347
348void
Dmitry V. Levin31382132011-03-04 05:08:02 +0300349printfd(struct tcb *tcp, int fd)
350{
Grant Edwards8a082772011-04-07 20:25:40 +0000351 const char *p;
352
353 if (show_fd_path && (p = getfdpath(tcp, fd)))
354 tprintf("%d<%s>", fd, p);
355 else
356 tprintf("%d", fd);
Dmitry V. Levin31382132011-03-04 05:08:02 +0300357}
358
359void
Denys Vlasenko12014262011-05-30 14:00:14 +0200360printuid(const char *text, unsigned long uid)
Roland McGrath6bc12202003-11-13 22:32:27 +0000361{
Denys Vlasenko5940e652011-09-01 09:55:05 +0200362 tprintf((uid == -1) ? "%s%ld" : "%s%lu", text, uid);
Roland McGrath6bc12202003-11-13 22:32:27 +0000363}
364
Dmitry V. Levina501f142008-11-10 23:19:13 +0000365/*
366 * Quote string `instr' of length `size'
367 * Write up to (3 + `size' * 4) bytes to `outstr' buffer.
Denys Vlasenkob5d43b82012-04-28 14:58:35 +0200368 * If `len' is -1, treat `instr' as a NUL-terminated string
Dmitry V. Levina501f142008-11-10 23:19:13 +0000369 * and quote at most (`size' - 1) bytes.
Denys Vlasenko6cecba52012-01-20 11:56:00 +0100370 *
Denys Vlasenkob5d43b82012-04-28 14:58:35 +0200371 * Returns 0 if len == -1 and NUL was seen, 1 otherwise.
Denys Vlasenko6cecba52012-01-20 11:56:00 +0100372 * Note that if len >= 0, always returns 1.
Dmitry V. Levina501f142008-11-10 23:19:13 +0000373 */
Mike Frysingerebee04c2012-04-17 22:19:31 -0400374int
Denys Vlasenkob5d43b82012-04-28 14:58:35 +0200375string_quote(const char *instr, char *outstr, long len, int size)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000376{
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000377 const unsigned char *ustr = (const unsigned char *) instr;
378 char *s = outstr;
Denys Vlasenko8778bff2011-08-31 12:22:56 +0200379 int usehex, c, i, eol;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000380
Denys Vlasenko8778bff2011-08-31 12:22:56 +0200381 eol = 0x100; /* this can never match a char */
Denys Vlasenkob5d43b82012-04-28 14:58:35 +0200382 if (len == -1) {
Denys Vlasenko8778bff2011-08-31 12:22:56 +0200383 size--;
384 eol = '\0';
385 }
386
387 usehex = 0;
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000388 if (xflag > 1)
389 usehex = 1;
390 else if (xflag) {
Dmitry V. Levina501f142008-11-10 23:19:13 +0000391 /* Check for presence of symbol which require
392 to hex-quote the whole string. */
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000393 for (i = 0; i < size; ++i) {
394 c = ustr[i];
Dmitry V. Levina501f142008-11-10 23:19:13 +0000395 /* Check for NUL-terminated string. */
Denys Vlasenko8778bff2011-08-31 12:22:56 +0200396 if (c == eol)
397 break;
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000398 if (!isprint(c) && !isspace(c)) {
399 usehex = 1;
400 break;
401 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000402 }
403 }
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000404
405 *s++ = '\"';
406
407 if (usehex) {
Dmitry V. Levina501f142008-11-10 23:19:13 +0000408 /* Hex-quote the whole string. */
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000409 for (i = 0; i < size; ++i) {
410 c = ustr[i];
Dmitry V. Levina501f142008-11-10 23:19:13 +0000411 /* Check for NUL-terminated string. */
Denys Vlasenko8778bff2011-08-31 12:22:56 +0200412 if (c == eol)
413 goto asciz_ended;
414 *s++ = '\\';
415 *s++ = 'x';
416 *s++ = "0123456789abcdef"[c >> 4];
417 *s++ = "0123456789abcdef"[c & 0xf];
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000418 }
419 } else {
420 for (i = 0; i < size; ++i) {
421 c = ustr[i];
Dmitry V. Levina501f142008-11-10 23:19:13 +0000422 /* Check for NUL-terminated string. */
Denys Vlasenko8778bff2011-08-31 12:22:56 +0200423 if (c == eol)
424 goto asciz_ended;
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000425 switch (c) {
426 case '\"': case '\\':
427 *s++ = '\\';
428 *s++ = c;
429 break;
430 case '\f':
431 *s++ = '\\';
432 *s++ = 'f';
433 break;
434 case '\n':
435 *s++ = '\\';
436 *s++ = 'n';
437 break;
438 case '\r':
439 *s++ = '\\';
440 *s++ = 'r';
441 break;
442 case '\t':
443 *s++ = '\\';
444 *s++ = 't';
445 break;
446 case '\v':
447 *s++ = '\\';
448 *s++ = 'v';
449 break;
450 default:
451 if (isprint(c))
452 *s++ = c;
Denys Vlasenko8778bff2011-08-31 12:22:56 +0200453 else {
454 /* Print \octal */
455 *s++ = '\\';
456 if (i + 1 < size
457 && ustr[i + 1] >= '0'
458 && ustr[i + 1] <= '9'
459 ) {
460 /* Print \ooo */
461 *s++ = '0' + (c >> 6);
462 *s++ = '0' + ((c >> 3) & 0x7);
463 } else {
464 /* Print \[[o]o]o */
465 if ((c >> 3) != 0) {
466 if ((c >> 6) != 0)
467 *s++ = '0' + (c >> 6);
468 *s++ = '0' + ((c >> 3) & 0x7);
469 }
470 }
471 *s++ = '0' + (c & 0x7);
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000472 }
473 break;
474 }
475 }
476 }
477
478 *s++ = '\"';
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000479 *s = '\0';
Roland McGrath6d970322007-11-01 23:53:59 +0000480
Denys Vlasenko8778bff2011-08-31 12:22:56 +0200481 /* Return zero if we printed entire ASCIZ string (didn't truncate it) */
Denys Vlasenkob5d43b82012-04-28 14:58:35 +0200482 if (len == -1 && ustr[i] == '\0') {
Denys Vlasenko8778bff2011-08-31 12:22:56 +0200483 /* We didn't see NUL yet (otherwise we'd jump to 'asciz_ended')
484 * but next char is NUL.
485 */
486 return 0;
487 }
488
489 return 1;
490
491 asciz_ended:
492 *s++ = '\"';
493 *s = '\0';
494 /* Return zero: we printed entire ASCIZ string (didn't truncate it) */
495 return 0;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000496}
497
Dmitry V. Levina501f142008-11-10 23:19:13 +0000498/*
499 * Print path string specified by address `addr' and length `n'.
500 * If path length exceeds `n', append `...' to the output.
501 */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000502void
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000503printpathn(struct tcb *tcp, long addr, int n)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000504{
Denys Vlasenkob3c52cf2012-01-19 17:20:23 +0100505 char path[MAXPATHLEN + 1];
Denys Vlasenko6cecba52012-01-20 11:56:00 +0100506 int nul_seen;
Denys Vlasenkob3c52cf2012-01-19 17:20:23 +0100507
Dmitry V. Levina501f142008-11-10 23:19:13 +0000508 if (!addr) {
Denys Vlasenko60fe8c12011-09-01 10:00:28 +0200509 tprints("NULL");
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000510 return;
511 }
512
Denys Vlasenko6cecba52012-01-20 11:56:00 +0100513 /* Cap path length to the path buffer size */
Dmitry V. Levina501f142008-11-10 23:19:13 +0000514 if (n > sizeof path - 1)
515 n = sizeof path - 1;
Dmitry V. Levina501f142008-11-10 23:19:13 +0000516
517 /* Fetch one byte more to find out whether path length > n. */
Denys Vlasenko6cecba52012-01-20 11:56:00 +0100518 nul_seen = umovestr(tcp, addr, n + 1, path);
519 if (nul_seen < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000520 tprintf("%#lx", addr);
521 else {
Denys Vlasenkob3c52cf2012-01-19 17:20:23 +0100522 char *outstr;
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000523
Denys Vlasenko6cecba52012-01-20 11:56:00 +0100524 path[n] = '\0';
Denys Vlasenkob3c52cf2012-01-19 17:20:23 +0100525 n++;
Denys Vlasenko6cecba52012-01-20 11:56:00 +0100526 outstr = alloca(4 * n); /* 4*(n-1) + 3 for quotes and NUL */
Denys Vlasenkob3c52cf2012-01-19 17:20:23 +0100527 string_quote(path, outstr, -1, n);
528 tprints(outstr);
Denys Vlasenko6cecba52012-01-20 11:56:00 +0100529 if (!nul_seen)
Denys Vlasenkob3c52cf2012-01-19 17:20:23 +0100530 tprints("...");
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000531 }
532}
533
534void
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000535printpath(struct tcb *tcp, long addr)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000536{
Denys Vlasenkob3c52cf2012-01-19 17:20:23 +0100537 /* Size must correspond to char path[] size in printpathn */
538 printpathn(tcp, addr, MAXPATHLEN);
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000539}
540
Dmitry V. Levina501f142008-11-10 23:19:13 +0000541/*
542 * Print string specified by address `addr' and length `len'.
543 * If `len' < 0, treat the string as a NUL-terminated string.
544 * If string length exceeds `max_strlen', append `...' to the output.
545 */
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000546void
Denys Vlasenkob5d43b82012-04-28 14:58:35 +0200547printstr(struct tcb *tcp, long addr, long len)
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000548{
549 static char *str = NULL;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000550 static char *outstr;
Roland McGrath6d970322007-11-01 23:53:59 +0000551 int size;
Denys Vlasenkob3c52cf2012-01-19 17:20:23 +0100552 int ellipsis;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000553
554 if (!addr) {
Denys Vlasenko60fe8c12011-09-01 10:00:28 +0200555 tprints("NULL");
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000556 return;
557 }
Dmitry V. Levina501f142008-11-10 23:19:13 +0000558 /* Allocate static buffers if they are not allocated yet. */
Denys Vlasenko1d46ba52011-08-31 14:00:02 +0200559 if (!str) {
Dmitry V. Levin378f9c52012-03-25 22:56:53 +0000560 unsigned int outstr_size = 4 * max_strlen + /*for quotes and NUL:*/ 3;
561
562 if (outstr_size / 4 != max_strlen)
563 die_out_of_memory();
Dmitry V. Levina501f142008-11-10 23:19:13 +0000564 str = malloc(max_strlen + 1);
Denys Vlasenko1d46ba52011-08-31 14:00:02 +0200565 if (!str)
566 die_out_of_memory();
Dmitry V. Levin378f9c52012-03-25 22:56:53 +0000567 outstr = malloc(outstr_size);
Denys Vlasenko1d46ba52011-08-31 14:00:02 +0200568 if (!outstr)
569 die_out_of_memory();
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000570 }
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000571
Denys Vlasenkob5d43b82012-04-28 14:58:35 +0200572 if (len == -1) {
Dmitry V. Levina501f142008-11-10 23:19:13 +0000573 /*
574 * Treat as a NUL-terminated string: fetch one byte more
575 * because string_quote() quotes one byte less.
576 */
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000577 size = max_strlen + 1;
578 if (umovestr(tcp, addr, size, str) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000579 tprintf("%#lx", addr);
580 return;
581 }
582 }
583 else {
Denys Vlasenkob5d43b82012-04-28 14:58:35 +0200584 size = max_strlen;
585 if (size > (unsigned long)len)
586 size = (unsigned long)len;
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000587 if (umoven(tcp, addr, size, str) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000588 tprintf("%#lx", addr);
589 return;
590 }
591 }
592
Denys Vlasenko6cecba52012-01-20 11:56:00 +0100593 /* If string_quote didn't see NUL and (it was supposed to be ASCIZ str
594 * or we were requested to print more than -s NUM chars)...
595 */
Denys Vlasenkob3c52cf2012-01-19 17:20:23 +0100596 ellipsis = (string_quote(str, outstr, len, size) &&
597 (len < 0 || len > max_strlen));
Roland McGratha503dcf2007-08-02 02:06:26 +0000598
Denys Vlasenkob3c52cf2012-01-19 17:20:23 +0100599 tprints(outstr);
600 if (ellipsis)
601 tprints("...");
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000602}
603
John Hughes1d08dcf2001-07-10 13:48:44 +0000604#if HAVE_SYS_UIO_H
605void
Denys Vlasenko12014262011-05-30 14:00:14 +0200606dumpiov(struct tcb *tcp, int len, long addr)
John Hughes1d08dcf2001-07-10 13:48:44 +0000607{
Denys Vlasenko84703742012-02-25 02:38:52 +0100608#if SUPPORTED_PERSONALITIES > 1
Dmitry V. Levin4ebb4e32006-12-13 17:08:08 +0000609 union {
610 struct { u_int32_t base; u_int32_t len; } *iov32;
611 struct { u_int64_t base; u_int64_t len; } *iov64;
612 } iovu;
613#define iov iovu.iov64
614#define sizeof_iov \
Denys Vlasenko9fd4f962012-03-19 09:36:42 +0100615 (current_wordsize == 4 ? sizeof(*iovu.iov32) : sizeof(*iovu.iov64))
Dmitry V. Levin4ebb4e32006-12-13 17:08:08 +0000616#define iov_iov_base(i) \
Denys Vlasenko9fd4f962012-03-19 09:36:42 +0100617 (current_wordsize == 4 ? (uint64_t) iovu.iov32[i].base : iovu.iov64[i].base)
Dmitry V. Levin4ebb4e32006-12-13 17:08:08 +0000618#define iov_iov_len(i) \
Denys Vlasenko9fd4f962012-03-19 09:36:42 +0100619 (current_wordsize == 4 ? (uint64_t) iovu.iov32[i].len : iovu.iov64[i].len)
Dmitry V. Levin4ebb4e32006-12-13 17:08:08 +0000620#else
John Hughes1d08dcf2001-07-10 13:48:44 +0000621 struct iovec *iov;
Dmitry V. Levin4ebb4e32006-12-13 17:08:08 +0000622#define sizeof_iov sizeof(*iov)
623#define iov_iov_base(i) iov[i].iov_base
624#define iov_iov_len(i) iov[i].iov_len
625#endif
John Hughes1d08dcf2001-07-10 13:48:44 +0000626 int i;
Denys Vlasenko79a79ea2011-09-01 16:35:44 +0200627 unsigned size;
John Hughes1d08dcf2001-07-10 13:48:44 +0000628
Denys Vlasenko79a79ea2011-09-01 16:35:44 +0200629 size = sizeof_iov * len;
630 /* Assuming no sane program has millions of iovs */
631 if ((unsigned)len > 1024*1024 /* insane or negative size? */
Dmitry V. Levin4ebb4e32006-12-13 17:08:08 +0000632 || (iov = malloc(size)) == NULL) {
Denys Vlasenko79a79ea2011-09-01 16:35:44 +0200633 fprintf(stderr, "Out of memory\n");
634 return;
John Hughes1d08dcf2001-07-10 13:48:44 +0000635 }
Roland McGrathaa524c82005-06-01 19:22:06 +0000636 if (umoven(tcp, addr, size, (char *) iov) >= 0) {
John Hughes1d08dcf2001-07-10 13:48:44 +0000637 for (i = 0; i < len; i++) {
Denys Vlasenkoadedb512008-12-30 18:47:55 +0000638 /* include the buffer number to make it easy to
639 * match up the trace with the source */
640 tprintf(" * %lu bytes in buffer %d\n",
641 (unsigned long)iov_iov_len(i), i);
642 dumpstr(tcp, (long) iov_iov_base(i),
643 iov_iov_len(i));
644 }
John Hughes1d08dcf2001-07-10 13:48:44 +0000645 }
Denys Vlasenko79a79ea2011-09-01 16:35:44 +0200646 free(iov);
Dmitry V. Levin4ebb4e32006-12-13 17:08:08 +0000647#undef sizeof_iov
648#undef iov_iov_base
649#undef iov_iov_len
650#undef iov
John Hughes1d08dcf2001-07-10 13:48:44 +0000651}
652#endif
653
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000654void
Denys Vlasenko12014262011-05-30 14:00:14 +0200655dumpstr(struct tcb *tcp, long addr, int len)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000656{
657 static int strsize = -1;
658 static unsigned char *str;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000659 char *s;
660 int i, j;
661
662 if (strsize < len) {
Denys Vlasenko5d645812011-08-20 12:48:18 +0200663 free(str);
664 str = malloc(len);
Denys Vlasenko79a79ea2011-09-01 16:35:44 +0200665 if (!str) {
666 strsize = -1;
667 fprintf(stderr, "Out of memory\n");
668 return;
669 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000670 strsize = len;
671 }
672
673 if (umoven(tcp, addr, len, (char *) str) < 0)
674 return;
675
676 for (i = 0; i < len; i += 16) {
Denys Vlasenko1d46ba52011-08-31 14:00:02 +0200677 char outstr[80];
678
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000679 s = outstr;
680 sprintf(s, " | %05x ", i);
681 s += 9;
682 for (j = 0; j < 16; j++) {
683 if (j == 8)
684 *s++ = ' ';
685 if (i + j < len) {
686 sprintf(s, " %02x", str[i + j]);
687 s += 3;
688 }
689 else {
690 *s++ = ' '; *s++ = ' '; *s++ = ' ';
691 }
692 }
693 *s++ = ' '; *s++ = ' ';
694 for (j = 0; j < 16; j++) {
695 if (j == 8)
696 *s++ = ' ';
697 if (i + j < len) {
698 if (isprint(str[i + j]))
699 *s++ = str[i + j];
700 else
701 *s++ = '.';
702 }
703 else
704 *s++ = ' ';
705 }
706 tprintf("%s |\n", outstr);
707 }
708}
709
Mike Frysinger612659e2012-02-14 14:38:28 +0100710#ifdef HAVE_PROCESS_VM_READV
711/* C library supports this, but the kernel might not. */
712static bool process_vm_readv_not_supported = 0;
713#else
714
Denys Vlasenko3af224c2012-01-28 01:46:33 +0100715/* Need to do this since process_vm_readv() is not yet available in libc.
716 * When libc is be updated, only "static bool process_vm_readv_not_supported"
717 * line should remain.
718 */
719#if !defined(__NR_process_vm_readv)
720# if defined(I386)
721# define __NR_process_vm_readv 347
722# elif defined(X86_64)
723# define __NR_process_vm_readv 310
724# elif defined(POWERPC)
725# define __NR_process_vm_readv 351
726# endif
727#endif
728
729#if defined(__NR_process_vm_readv)
730static bool process_vm_readv_not_supported = 0;
Mike Frysinger24ee60b2012-05-04 19:37:29 -0400731/* Have to avoid duplicating with the C library headers. */
732static ssize_t strace_process_vm_readv(pid_t pid,
Denys Vlasenko3af224c2012-01-28 01:46:33 +0100733 const struct iovec *lvec,
734 unsigned long liovcnt,
735 const struct iovec *rvec,
736 unsigned long riovcnt,
737 unsigned long flags)
738{
739 return syscall(__NR_process_vm_readv, (long)pid, lvec, liovcnt, rvec, riovcnt, flags);
740}
Mike Frysinger24ee60b2012-05-04 19:37:29 -0400741#define process_vm_readv strace_process_vm_readv
Denys Vlasenko3af224c2012-01-28 01:46:33 +0100742#else
743static bool process_vm_readv_not_supported = 1;
744# define process_vm_readv(...) (errno = ENOSYS, -1)
745#endif
Mike Frysinger612659e2012-02-14 14:38:28 +0100746
747#endif /* end of hack */
Denys Vlasenko3af224c2012-01-28 01:46:33 +0100748
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000749#define PAGMASK (~(PAGSIZ - 1))
750/*
751 * move `len' bytes of data from process `pid'
752 * at address `addr' to our space at `laddr'
753 */
754int
Denys Vlasenkoef2fbf82009-01-06 21:45:06 +0000755umoven(struct tcb *tcp, long addr, int len, char *laddr)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000756{
Roland McGratheb9e2e82009-06-02 16:49:22 -0700757 int pid = tcp->pid;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000758 int n, m;
Denys Vlasenkoa47e6b92012-01-21 04:01:56 +0100759 int started;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000760 union {
761 long val;
762 char x[sizeof(long)];
763 } u;
764
Denys Vlasenkod2a660f2012-02-25 00:43:22 +0100765#if SUPPORTED_PERSONALITIES > 1
Denys Vlasenko9fd4f962012-03-19 09:36:42 +0100766 if (current_wordsize < sizeof(addr))
767 addr &= (1ul << 8 * current_wordsize) - 1;
Denys Vlasenkod2a660f2012-02-25 00:43:22 +0100768#endif
769
Denys Vlasenko3af224c2012-01-28 01:46:33 +0100770 if (!process_vm_readv_not_supported) {
771 struct iovec local[1], remote[1];
772 int r;
773
774 local[0].iov_base = laddr;
775 remote[0].iov_base = (void*)addr;
776 local[0].iov_len = remote[0].iov_len = len;
777 r = process_vm_readv(pid,
778 local, 1,
779 remote, 1,
780 /*flags:*/ 0
781 );
782 if (r < 0) {
783 if (errno == ENOSYS)
784 process_vm_readv_not_supported = 1;
Dmitry V. Levin9a71bcd2012-09-17 23:20:54 +0000785 else if (errno != EINVAL && errno != ESRCH)
786 /* EINVAL or ESRCH could be seen if process is gone,
787 * all the rest is strange and should be reported. */
788 perror_msg("%s", "process_vm_readv");
Denys Vlasenko3af224c2012-01-28 01:46:33 +0100789 goto vm_readv_didnt_work;
790 }
791 return r;
792 }
793 vm_readv_didnt_work:
794
Denys Vlasenkoa47e6b92012-01-21 04:01:56 +0100795 started = 0;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000796 if (addr & (sizeof(long) - 1)) {
797 /* addr not a multiple of sizeof(long) */
798 n = addr - (addr & -sizeof(long)); /* residue */
799 addr &= -sizeof(long); /* residue */
Roland McGratheb9e2e82009-06-02 16:49:22 -0700800 errno = 0;
801 u.val = ptrace(PTRACE_PEEKDATA, pid, (char *) addr, 0);
802 if (errno) {
Roland McGratheb9e2e82009-06-02 16:49:22 -0700803 /* But if not started, we had a bogus address. */
804 if (addr != 0 && errno != EIO && errno != ESRCH)
Denys Vlasenko4c65c442012-03-08 11:54:10 +0100805 perror_msg("umoven: PTRACE_PEEKDATA pid:%d @0x%lx", pid, addr);
Roland McGratheb9e2e82009-06-02 16:49:22 -0700806 return -1;
807 }
Wichert Akkerman5daa0281999-03-15 19:49:42 +0000808 started = 1;
Denys Vlasenkoa47e6b92012-01-21 04:01:56 +0100809 m = MIN(sizeof(long) - n, len);
810 memcpy(laddr, &u.x[n], m);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000811 addr += sizeof(long), laddr += m, len -= m;
812 }
813 while (len) {
Roland McGratheb9e2e82009-06-02 16:49:22 -0700814 errno = 0;
815 u.val = ptrace(PTRACE_PEEKDATA, pid, (char *) addr, 0);
816 if (errno) {
817 if (started && (errno==EPERM || errno==EIO)) {
818 /* Ran into 'end of memory' - stupid "printpath" */
819 return 0;
820 }
821 if (addr != 0 && errno != EIO && errno != ESRCH)
Denys Vlasenko4c65c442012-03-08 11:54:10 +0100822 perror_msg("umoven: PTRACE_PEEKDATA pid:%d @0x%lx", pid, addr);
Roland McGratheb9e2e82009-06-02 16:49:22 -0700823 return -1;
824 }
Wichert Akkerman5daa0281999-03-15 19:49:42 +0000825 started = 1;
Denys Vlasenkoa47e6b92012-01-21 04:01:56 +0100826 m = MIN(sizeof(long), len);
827 memcpy(laddr, u.x, m);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000828 addr += sizeof(long), laddr += m, len -= m;
829 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000830
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000831 return 0;
832}
833
834/*
Denys Vlasenko6cecba52012-01-20 11:56:00 +0100835 * Like `umove' but make the additional effort of looking
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000836 * for a terminating zero byte.
Denys Vlasenko6cecba52012-01-20 11:56:00 +0100837 *
838 * Returns < 0 on error, > 0 if NUL was seen,
839 * (TODO if useful: return count of bytes including NUL),
840 * else 0 if len bytes were read but no NUL byte seen.
841 *
842 * Note: there is no guarantee we won't overwrite some bytes
843 * in laddr[] _after_ terminating NUL (but, of course,
844 * we never write past laddr[len-1]).
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000845 */
846int
Denys Vlasenkoef2fbf82009-01-06 21:45:06 +0000847umovestr(struct tcb *tcp, long addr, int len, char *laddr)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000848{
Denys Vlasenkoa47e6b92012-01-21 04:01:56 +0100849 int started;
Roland McGratheb9e2e82009-06-02 16:49:22 -0700850 int pid = tcp->pid;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000851 int i, n, m;
852 union {
853 long val;
854 char x[sizeof(long)];
855 } u;
856
Dmitry V. Levin856c7ed2011-12-26 20:12:02 +0000857#if SUPPORTED_PERSONALITIES > 1
Denys Vlasenko9fd4f962012-03-19 09:36:42 +0100858 if (current_wordsize < sizeof(addr))
859 addr &= (1ul << 8 * current_wordsize) - 1;
Dmitry V. Levin856c7ed2011-12-26 20:12:02 +0000860#endif
861
Denys Vlasenko3af224c2012-01-28 01:46:33 +0100862 if (!process_vm_readv_not_supported) {
863 struct iovec local[1], remote[1];
864
865 local[0].iov_base = laddr;
866 remote[0].iov_base = (void*)addr;
867
868 while (len > 0) {
869 int end_in_page;
870 int r;
871 int chunk_len;
872
873 /* Don't read kilobytes: most strings are short */
874 chunk_len = len;
875 if (chunk_len > 256)
876 chunk_len = 256;
877 /* Don't cross pages. I guess otherwise we can get EFAULT
878 * and fail to notice that terminating NUL lies
879 * in the existing (first) page.
880 * (I hope there aren't arches with pages < 4K)
881 */
882 end_in_page = ((addr + chunk_len) & 4095);
883 r = chunk_len - end_in_page;
884 if (r > 0) /* if chunk_len > end_in_page */
885 chunk_len = r; /* chunk_len -= end_in_page */
886
887 local[0].iov_len = remote[0].iov_len = chunk_len;
888 r = process_vm_readv(pid,
889 local, 1,
890 remote, 1,
891 /*flags:*/ 0
892 );
893 if (r < 0) {
894 if (errno == ENOSYS)
895 process_vm_readv_not_supported = 1;
Dmitry V. Levin9a71bcd2012-09-17 23:20:54 +0000896 else if (errno != EINVAL && errno != ESRCH)
897 /* EINVAL or ESRCH could be seen
898 * if process is gone, all the rest
899 * is strange and should be reported. */
900 perror_msg("%s", "process_vm_readv");
Denys Vlasenko3af224c2012-01-28 01:46:33 +0100901 goto vm_readv_didnt_work;
902 }
903 if (memchr(local[0].iov_base, '\0', r))
904 return 1;
905 local[0].iov_base += r;
906 remote[0].iov_base += r;
907 len -= r;
908 }
909 return 0;
910 }
911 vm_readv_didnt_work:
912
Denys Vlasenkoa47e6b92012-01-21 04:01:56 +0100913 started = 0;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000914 if (addr & (sizeof(long) - 1)) {
915 /* addr not a multiple of sizeof(long) */
916 n = addr - (addr & -sizeof(long)); /* residue */
917 addr &= -sizeof(long); /* residue */
Roland McGratheb9e2e82009-06-02 16:49:22 -0700918 errno = 0;
919 u.val = ptrace(PTRACE_PEEKDATA, pid, (char *)addr, 0);
920 if (errno) {
Roland McGratheb9e2e82009-06-02 16:49:22 -0700921 if (addr != 0 && errno != EIO && errno != ESRCH)
Denys Vlasenko4c65c442012-03-08 11:54:10 +0100922 perror_msg("umovestr: PTRACE_PEEKDATA pid:%d @0x%lx", pid, addr);
Roland McGratheb9e2e82009-06-02 16:49:22 -0700923 return -1;
924 }
Wichert Akkerman5daa0281999-03-15 19:49:42 +0000925 started = 1;
Denys Vlasenkoa47e6b92012-01-21 04:01:56 +0100926 m = MIN(sizeof(long) - n, len);
927 memcpy(laddr, &u.x[n], m);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000928 while (n & (sizeof(long) - 1))
929 if (u.x[n++] == '\0')
Denys Vlasenko6cecba52012-01-20 11:56:00 +0100930 return 1;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000931 addr += sizeof(long), laddr += m, len -= m;
932 }
933 while (len) {
Roland McGratheb9e2e82009-06-02 16:49:22 -0700934 errno = 0;
935 u.val = ptrace(PTRACE_PEEKDATA, pid, (char *)addr, 0);
936 if (errno) {
937 if (started && (errno==EPERM || errno==EIO)) {
938 /* Ran into 'end of memory' - stupid "printpath" */
939 return 0;
940 }
941 if (addr != 0 && errno != EIO && errno != ESRCH)
Denys Vlasenko4c65c442012-03-08 11:54:10 +0100942 perror_msg("umovestr: PTRACE_PEEKDATA pid:%d @0x%lx", pid, addr);
Roland McGratheb9e2e82009-06-02 16:49:22 -0700943 return -1;
944 }
Wichert Akkerman5daa0281999-03-15 19:49:42 +0000945 started = 1;
Denys Vlasenkoa47e6b92012-01-21 04:01:56 +0100946 m = MIN(sizeof(long), len);
947 memcpy(laddr, u.x, m);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000948 for (i = 0; i < sizeof(long); i++)
949 if (u.x[i] == '\0')
Denys Vlasenko6cecba52012-01-20 11:56:00 +0100950 return 1;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000951 addr += sizeof(long), laddr += m, len -= m;
952 }
John Hughesaa09c6b2001-05-15 14:53:43 +0000953 return 0;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000954}
955
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000956int
Denys Vlasenko12014262011-05-30 14:00:14 +0200957upeek(struct tcb *tcp, long off, long *res)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000958{
959 long val;
960
Roland McGratheb9e2e82009-06-02 16:49:22 -0700961 errno = 0;
Denys Vlasenko114aefd2012-03-08 12:13:44 +0100962 val = ptrace(PTRACE_PEEKUSER, tcp->pid, (char *) off, 0);
Roland McGratheb9e2e82009-06-02 16:49:22 -0700963 if (val == -1 && errno) {
964 if (errno != ESRCH) {
Denys Vlasenko4c65c442012-03-08 11:54:10 +0100965 perror_msg("upeek: PTRACE_PEEKUSER pid:%d @0x%lx)", tcp->pid, off);
Roland McGratheb9e2e82009-06-02 16:49:22 -0700966 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000967 return -1;
Roland McGratheb9e2e82009-06-02 16:49:22 -0700968 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000969 *res = val;
970 return 0;
971}
972
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +0000973/*
974 * These #if's are huge, please indent them correctly.
975 * It's easy to get confused otherwise.
976 */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000977
Denys Vlasenko2d1e90f2012-02-25 02:46:14 +0100978#include "syscall.h"
Roland McGrath3291ef22008-05-20 00:34:34 +0000979
Denys Vlasenko2d1e90f2012-02-25 02:46:14 +0100980#ifndef CLONE_PTRACE
981# define CLONE_PTRACE 0x00002000
982#endif
983#ifndef CLONE_VFORK
984# define CLONE_VFORK 0x00004000
985#endif
986#ifndef CLONE_VM
987# define CLONE_VM 0x00000100
988#endif
Roland McGrathd81f1d92003-01-09 06:53:34 +0000989
Denys Vlasenko2d1e90f2012-02-25 02:46:14 +0100990#ifdef IA64
Roland McGrathd81f1d92003-01-09 06:53:34 +0000991
992typedef unsigned long *arg_setup_state;
993
994static int
995arg_setup(struct tcb *tcp, arg_setup_state *state)
996{
Jan Kratochvil1f942712008-08-06 21:38:52 +0000997 unsigned long cfm, sof, sol;
998 long bsp;
Roland McGrathd81f1d92003-01-09 06:53:34 +0000999
Jan Kratochvil1f942712008-08-06 21:38:52 +00001000 if (ia32) {
1001 /* Satisfy a false GCC warning. */
1002 *state = NULL;
Roland McGrath08267b82004-02-20 22:56:43 +00001003 return 0;
Jan Kratochvil1f942712008-08-06 21:38:52 +00001004 }
Roland McGrath08267b82004-02-20 22:56:43 +00001005
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001006 if (upeek(tcp, PT_AR_BSP, &bsp) < 0)
Roland McGrathd81f1d92003-01-09 06:53:34 +00001007 return -1;
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001008 if (upeek(tcp, PT_CFM, (long *) &cfm) < 0)
Roland McGrathd81f1d92003-01-09 06:53:34 +00001009 return -1;
1010
1011 sof = (cfm >> 0) & 0x7f;
1012 sol = (cfm >> 7) & 0x7f;
Jan Kratochvil1f942712008-08-06 21:38:52 +00001013 bsp = (long) ia64_rse_skip_regs((unsigned long *) bsp, -sof + sol);
Roland McGrathd81f1d92003-01-09 06:53:34 +00001014
Jan Kratochvil1f942712008-08-06 21:38:52 +00001015 *state = (unsigned long *) bsp;
Roland McGrathd81f1d92003-01-09 06:53:34 +00001016 return 0;
1017}
1018
Denys Vlasenko2d1e90f2012-02-25 02:46:14 +01001019# define arg_finish_change(tcp, state) 0
Roland McGrathd81f1d92003-01-09 06:53:34 +00001020
Roland McGrathd81f1d92003-01-09 06:53:34 +00001021static int
Denys Vlasenko12014262011-05-30 14:00:14 +02001022get_arg0(struct tcb *tcp, arg_setup_state *state, long *valp)
Roland McGrathd81f1d92003-01-09 06:53:34 +00001023{
Roland McGrath08267b82004-02-20 22:56:43 +00001024 int ret;
1025
1026 if (ia32)
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001027 ret = upeek(tcp, PT_R11, valp);
Roland McGrath08267b82004-02-20 22:56:43 +00001028 else
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001029 ret = umoven(tcp,
Roland McGrath08267b82004-02-20 22:56:43 +00001030 (unsigned long) ia64_rse_skip_regs(*state, 0),
1031 sizeof(long), (void *) valp);
1032 return ret;
Roland McGrathd81f1d92003-01-09 06:53:34 +00001033}
1034
1035static int
Denys Vlasenko12014262011-05-30 14:00:14 +02001036get_arg1(struct tcb *tcp, arg_setup_state *state, long *valp)
Roland McGrathd81f1d92003-01-09 06:53:34 +00001037{
Roland McGrath08267b82004-02-20 22:56:43 +00001038 int ret;
1039
1040 if (ia32)
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001041 ret = upeek(tcp, PT_R9, valp);
Roland McGrath08267b82004-02-20 22:56:43 +00001042 else
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001043 ret = umoven(tcp,
Roland McGrath08267b82004-02-20 22:56:43 +00001044 (unsigned long) ia64_rse_skip_regs(*state, 1),
1045 sizeof(long), (void *) valp);
1046 return ret;
Roland McGrathd81f1d92003-01-09 06:53:34 +00001047}
Roland McGrathd81f1d92003-01-09 06:53:34 +00001048
1049static int
Denys Vlasenko12014262011-05-30 14:00:14 +02001050set_arg0(struct tcb *tcp, arg_setup_state *state, long val)
Roland McGrathd81f1d92003-01-09 06:53:34 +00001051{
Roland McGrath08267b82004-02-20 22:56:43 +00001052 int req = PTRACE_POKEDATA;
1053 void *ap;
1054
1055 if (ia32) {
1056 ap = (void *) (intptr_t) PT_R11; /* r11 == EBX */
1057 req = PTRACE_POKEUSER;
1058 } else
1059 ap = ia64_rse_skip_regs(*state, 0);
Roland McGratheb9e2e82009-06-02 16:49:22 -07001060 errno = 0;
1061 ptrace(req, tcp->pid, ap, val);
1062 return errno ? -1 : 0;
Roland McGrathd81f1d92003-01-09 06:53:34 +00001063}
1064
1065static int
Denys Vlasenko12014262011-05-30 14:00:14 +02001066set_arg1(struct tcb *tcp, arg_setup_state *state, long val)
Roland McGrathd81f1d92003-01-09 06:53:34 +00001067{
Roland McGrath08267b82004-02-20 22:56:43 +00001068 int req = PTRACE_POKEDATA;
1069 void *ap;
1070
1071 if (ia32) {
1072 ap = (void *) (intptr_t) PT_R9; /* r9 == ECX */
1073 req = PTRACE_POKEUSER;
1074 } else
1075 ap = ia64_rse_skip_regs(*state, 1);
Roland McGratheb9e2e82009-06-02 16:49:22 -07001076 errno = 0;
1077 ptrace(req, tcp->pid, ap, val);
1078 return errno ? -1 : 0;
Roland McGrathd81f1d92003-01-09 06:53:34 +00001079}
1080
Roland McGrathb659f872008-07-18 01:19:36 +00001081/* ia64 does not return the input arguments from functions (and syscalls)
1082 according to ia64 RSE (Register Stack Engine) behavior. */
1083
Denys Vlasenko2d1e90f2012-02-25 02:46:14 +01001084# define restore_arg0(tcp, state, val) ((void) (state), 0)
1085# define restore_arg1(tcp, state, val) ((void) (state), 0)
Roland McGrathb659f872008-07-18 01:19:36 +00001086
Denys Vlasenko2d1e90f2012-02-25 02:46:14 +01001087#elif defined(SPARC) || defined(SPARC64)
Roland McGrathd81f1d92003-01-09 06:53:34 +00001088
Denys Vlasenkoce7d9532013-02-05 16:36:13 +01001089# if defined(SPARC64)
1090# undef PTRACE_GETREGS
1091# define PTRACE_GETREGS PTRACE_GETREGS64
1092# undef PTRACE_SETREGS
1093# define PTRACE_SETREGS PTRACE_SETREGS64
1094# endif
1095
Mike Frysinger8566c502009-10-12 11:05:14 -04001096typedef struct pt_regs arg_setup_state;
Roland McGrathd81f1d92003-01-09 06:53:34 +00001097
Denys Vlasenko2d1e90f2012-02-25 02:46:14 +01001098# define arg_setup(tcp, state) \
1099 (ptrace(PTRACE_GETREGS, (tcp)->pid, (char *) (state), 0))
1100# define arg_finish_change(tcp, state) \
1101 (ptrace(PTRACE_SETREGS, (tcp)->pid, (char *) (state), 0))
Roland McGrathd81f1d92003-01-09 06:53:34 +00001102
Denys Vlasenko2d1e90f2012-02-25 02:46:14 +01001103# define get_arg0(tcp, state, valp) (*(valp) = (state)->u_regs[U_REG_O0], 0)
1104# define get_arg1(tcp, state, valp) (*(valp) = (state)->u_regs[U_REG_O1], 0)
1105# define set_arg0(tcp, state, val) ((state)->u_regs[U_REG_O0] = (val), 0)
1106# define set_arg1(tcp, state, val) ((state)->u_regs[U_REG_O1] = (val), 0)
1107# define restore_arg0(tcp, state, val) 0
Roland McGrathd81f1d92003-01-09 06:53:34 +00001108
Denys Vlasenko2d1e90f2012-02-25 02:46:14 +01001109#else /* other architectures */
Roland McGrathd81f1d92003-01-09 06:53:34 +00001110
Denys Vlasenko2d1e90f2012-02-25 02:46:14 +01001111# if defined S390 || defined S390X
Roland McGrath7b308222003-01-20 09:04:36 +00001112/* Note: this is only true for the `clone' system call, which handles
1113 arguments specially. We could as well say that its first two arguments
1114 are swapped relative to other architectures, but that would just be
1115 another #ifdef in the calls. */
Denys Vlasenko2d1e90f2012-02-25 02:46:14 +01001116# define arg0_offset PT_GPR3
1117# define arg1_offset PT_ORIGGPR2
1118# define restore_arg0(tcp, state, val) ((void) (state), 0)
1119# define restore_arg1(tcp, state, val) ((void) (state), 0)
1120# define arg0_index 1
1121# define arg1_index 0
1122# elif defined(ALPHA) || defined(MIPS)
1123# define arg0_offset REG_A0
1124# define arg1_offset (REG_A0+1)
1125# elif defined(AVR32)
1126# define arg0_offset (REG_R12)
1127# define arg1_offset (REG_R11)
1128# elif defined(POWERPC)
1129# define arg0_offset (sizeof(unsigned long)*PT_R3)
1130# define arg1_offset (sizeof(unsigned long)*PT_R4)
1131# define restore_arg0(tcp, state, val) ((void) (state), 0)
1132# elif defined(HPPA)
1133# define arg0_offset PT_GR26
1134# define arg1_offset (PT_GR26-4)
H.J. Lu35be5812012-04-16 13:00:01 +02001135# elif defined(X86_64) || defined(X32)
Denys Vlasenko2d1e90f2012-02-25 02:46:14 +01001136# define arg0_offset ((long)(8*(current_personality ? RBX : RDI)))
1137# define arg1_offset ((long)(8*(current_personality ? RCX : RSI)))
1138# elif defined(SH)
1139# define arg0_offset (4*(REG_REG0+4))
1140# define arg1_offset (4*(REG_REG0+5))
1141# elif defined(SH64)
1142 /* ABI defines arg0 & 1 in r2 & r3 */
1143# define arg0_offset (REG_OFFSET+16)
1144# define arg1_offset (REG_OFFSET+24)
1145# define restore_arg0(tcp, state, val) 0
1146# elif defined CRISV10 || defined CRISV32
1147# define arg0_offset (4*PT_R11)
1148# define arg1_offset (4*PT_ORIG_R10)
1149# define restore_arg0(tcp, state, val) 0
1150# define restore_arg1(tcp, state, val) 0
1151# define arg0_index 1
1152# define arg1_index 0
1153# else
1154# define arg0_offset 0
1155# define arg1_offset 4
1156# if defined ARM
1157# define restore_arg0(tcp, state, val) 0
1158# endif
1159# endif
Roland McGrathd81f1d92003-01-09 06:53:34 +00001160
1161typedef int arg_setup_state;
1162
Denys Vlasenko2d1e90f2012-02-25 02:46:14 +01001163# define arg_setup(tcp, state) (0)
1164# define arg_finish_change(tcp, state) 0
1165# define get_arg0(tcp, cookie, valp) (upeek((tcp), arg0_offset, (valp)))
1166# define get_arg1(tcp, cookie, valp) (upeek((tcp), arg1_offset, (valp)))
Roland McGrathd81f1d92003-01-09 06:53:34 +00001167
1168static int
Denys Vlasenko12014262011-05-30 14:00:14 +02001169set_arg0(struct tcb *tcp, void *cookie, long val)
Roland McGrathd81f1d92003-01-09 06:53:34 +00001170{
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001171 return ptrace(PTRACE_POKEUSER, tcp->pid, (char*)arg0_offset, val);
Roland McGrathd81f1d92003-01-09 06:53:34 +00001172}
1173
1174static int
Denys Vlasenko12014262011-05-30 14:00:14 +02001175set_arg1(struct tcb *tcp, void *cookie, long val)
Roland McGrathd81f1d92003-01-09 06:53:34 +00001176{
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001177 return ptrace(PTRACE_POKEUSER, tcp->pid, (char*)arg1_offset, val);
Roland McGrathd81f1d92003-01-09 06:53:34 +00001178}
1179
Denys Vlasenko2d1e90f2012-02-25 02:46:14 +01001180#endif /* architectures */
Roland McGrathd81f1d92003-01-09 06:53:34 +00001181
Denys Vlasenko2d1e90f2012-02-25 02:46:14 +01001182#ifndef restore_arg0
1183# define restore_arg0(tcp, state, val) set_arg0((tcp), (state), (val))
1184#endif
1185#ifndef restore_arg1
1186# define restore_arg1(tcp, state, val) set_arg1((tcp), (state), (val))
1187#endif
Roland McGrathd81f1d92003-01-09 06:53:34 +00001188
Denys Vlasenko2d1e90f2012-02-25 02:46:14 +01001189#ifndef arg0_index
1190# define arg0_index 0
1191# define arg1_index 1
1192#endif
Roland McGrath90d0afd2004-03-01 21:05:16 +00001193
James Hogan05eb9052012-11-29 17:37:37 +00001194static int
1195change_syscall(struct tcb *tcp, arg_setup_state *state, int new)
1196{
1197#if defined(I386)
1198 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(ORIG_EAX * 4), new) < 0)
1199 return -1;
1200 return 0;
1201#elif defined(X86_64) || defined(X32)
1202 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(ORIG_RAX * 8), new) < 0)
1203 return -1;
1204 return 0;
1205#elif defined(POWERPC)
1206 if (ptrace(PTRACE_POKEUSER, tcp->pid,
1207 (char*)(sizeof(unsigned long)*PT_R0), new) < 0)
1208 return -1;
1209 return 0;
1210#elif defined(S390) || defined(S390X)
1211 /* s390 linux after 2.4.7 has a hook in entry.S to allow this */
1212 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(PT_GPR2), new) < 0)
1213 return -1;
1214 return 0;
1215#elif defined(M68K)
1216 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(4*PT_ORIG_D0), new) < 0)
1217 return -1;
1218 return 0;
1219#elif defined(SPARC) || defined(SPARC64)
1220 state->u_regs[U_REG_G1] = new;
1221 return 0;
1222#elif defined(MIPS)
1223 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(REG_V0), new) < 0)
1224 return -1;
1225 return 0;
1226#elif defined(ALPHA)
1227 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(REG_A3), new) < 0)
1228 return -1;
1229 return 0;
1230#elif defined(AVR32)
1231 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(REG_R8), new) < 0)
1232 return -1;
1233 return 0;
1234#elif defined(BFIN)
1235 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(REG_P0), new) < 0)
1236 return -1;
1237 return 0;
1238#elif defined(IA64)
1239 if (ia32) {
1240 switch (new) {
1241 case 2:
1242 break; /* x86 SYS_fork */
1243 case SYS_clone:
1244 new = 120;
1245 break;
1246 default:
1247 fprintf(stderr, "%s: unexpected syscall %d\n",
1248 __FUNCTION__, new);
1249 return -1;
1250 }
1251 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(PT_R1), new) < 0)
1252 return -1;
1253 } else if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(PT_R15), new) < 0)
1254 return -1;
1255 return 0;
1256#elif defined(HPPA)
1257 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(PT_GR20), new) < 0)
1258 return -1;
1259 return 0;
1260#elif defined(SH)
1261 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(4*(REG_REG0+3)), new) < 0)
1262 return -1;
1263 return 0;
1264#elif defined(SH64)
1265 /* Top half of reg encodes the no. of args n as 0x1n.
1266 Assume 0 args as kernel never actually checks... */
1267 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(REG_SYSCALL),
1268 0x100000 | new) < 0)
1269 return -1;
1270 return 0;
1271#elif defined(CRISV10) || defined(CRISV32)
1272 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(4*PT_R9), new) < 0)
1273 return -1;
1274 return 0;
1275#elif defined(ARM)
1276 /* Some kernels support this, some (pre-2.6.16 or so) don't. */
1277# ifndef PTRACE_SET_SYSCALL
1278# define PTRACE_SET_SYSCALL 23
1279# endif
1280 if (ptrace(PTRACE_SET_SYSCALL, tcp->pid, 0, new & 0xffff) != 0)
1281 return -1;
1282 return 0;
1283#elif defined(TILE)
1284 if (ptrace(PTRACE_POKEUSER, tcp->pid,
1285 (char*)PTREGS_OFFSET_REG(0),
1286 new) != 0)
1287 return -1;
1288 return 0;
1289#elif defined(MICROBLAZE)
1290 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(PT_GPR(0)), new) < 0)
1291 return -1;
1292 return 0;
1293#else
1294#warning Do not know how to handle change_syscall for this architecture
1295#endif /* architecture */
1296 return -1;
1297}
1298
Roland McGrathd81f1d92003-01-09 06:53:34 +00001299int
Denys Vlasenko418d66a2009-01-17 01:52:54 +00001300setbpt(struct tcb *tcp)
Roland McGrathd81f1d92003-01-09 06:53:34 +00001301{
Roland McGrath3291ef22008-05-20 00:34:34 +00001302 static int clone_scno[SUPPORTED_PERSONALITIES] = { SYS_clone };
Roland McGrathd81f1d92003-01-09 06:53:34 +00001303 arg_setup_state state;
1304
1305 if (tcp->flags & TCB_BPTSET) {
1306 fprintf(stderr, "PANIC: TCB already set in pid %u\n", tcp->pid);
1307 return -1;
1308 }
1309
Roland McGrath3291ef22008-05-20 00:34:34 +00001310 /*
1311 * It's a silly kludge to initialize this with a search at runtime.
1312 * But it's better than maintaining another magic thing in the
1313 * godforsaken tables.
1314 */
1315 if (clone_scno[current_personality] == 0) {
1316 int i;
1317 for (i = 0; i < nsyscalls; ++i)
1318 if (sysent[i].sys_func == sys_clone) {
1319 clone_scno[current_personality] = i;
1320 break;
1321 }
1322 }
1323
Dmitry V. Levin0c661512012-02-20 21:17:58 +00001324 if (sysent[tcp->scno].sys_func == sys_fork ||
1325 sysent[tcp->scno].sys_func == sys_vfork) {
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001326 if (arg_setup(tcp, &state) < 0
1327 || get_arg0(tcp, &state, &tcp->inst[0]) < 0
1328 || get_arg1(tcp, &state, &tcp->inst[1]) < 0
James Hogan05eb9052012-11-29 17:37:37 +00001329 || change_syscall(tcp, &state,
1330 clone_scno[current_personality]) < 0
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001331 || set_arg0(tcp, &state, CLONE_PTRACE|SIGCHLD) < 0
1332 || set_arg1(tcp, &state, 0) < 0
1333 || arg_finish_change(tcp, &state) < 0)
Roland McGrathd81f1d92003-01-09 06:53:34 +00001334 return -1;
Roland McGrathc9dc3c12004-03-01 20:57:09 +00001335 tcp->u_arg[arg0_index] = CLONE_PTRACE|SIGCHLD;
1336 tcp->u_arg[arg1_index] = 0;
Roland McGrathd81f1d92003-01-09 06:53:34 +00001337 tcp->flags |= TCB_BPTSET;
1338 return 0;
Dmitry V. Levin0c661512012-02-20 21:17:58 +00001339 }
Roland McGrathd81f1d92003-01-09 06:53:34 +00001340
Dmitry V. Levin0c661512012-02-20 21:17:58 +00001341 if (sysent[tcp->scno].sys_func == sys_clone) {
Jan Kratochvil8fc95752008-08-06 21:43:35 +00001342 /* ia64 calls directly `clone (CLONE_VFORK | CLONE_VM)'
Dmitry V. Levin0c661512012-02-20 21:17:58 +00001343 contrary to x86 vfork above. Even on x86 we turn the
Jan Kratochvil8fc95752008-08-06 21:43:35 +00001344 vfork semantics into plain fork - each application must not
1345 depend on the vfork specifics according to POSIX. We would
1346 hang waiting for the parent resume otherwise. We need to
1347 clear also CLONE_VM but only in the CLONE_VFORK case as
1348 otherwise we would break pthread_create. */
1349
Denys Vlasenkoc133bf02011-06-23 21:57:54 +02001350 long new_arg0 = (tcp->u_arg[arg0_index] | CLONE_PTRACE);
1351 if (new_arg0 & CLONE_VFORK)
1352 new_arg0 &= ~(unsigned long)(CLONE_VFORK | CLONE_VM);
1353 if (arg_setup(tcp, &state) < 0
1354 || set_arg0(tcp, &state, new_arg0) < 0
1355 || arg_finish_change(tcp, &state) < 0)
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00001356 return -1;
Roland McGrathc9dc3c12004-03-01 20:57:09 +00001357 tcp->inst[0] = tcp->u_arg[arg0_index];
1358 tcp->inst[1] = tcp->u_arg[arg1_index];
Denys Vlasenko55980f52012-05-14 16:40:28 +02001359 tcp->flags |= TCB_BPTSET;
Roland McGrathd81f1d92003-01-09 06:53:34 +00001360 return 0;
Roland McGrathd81f1d92003-01-09 06:53:34 +00001361 }
1362
Dmitry V. Levin0c661512012-02-20 21:17:58 +00001363 fprintf(stderr, "PANIC: setbpt for syscall %ld on %u???\n",
1364 tcp->scno, tcp->pid);
Roland McGrathd81f1d92003-01-09 06:53:34 +00001365 return -1;
1366}
1367
1368int
Denys Vlasenko12014262011-05-30 14:00:14 +02001369clearbpt(struct tcb *tcp)
Roland McGrathd81f1d92003-01-09 06:53:34 +00001370{
1371 arg_setup_state state;
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001372 if (arg_setup(tcp, &state) < 0
James Hogan05eb9052012-11-29 17:37:37 +00001373 || change_syscall(tcp, &state, tcp->scno) < 0
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001374 || restore_arg0(tcp, &state, tcp->inst[0]) < 0
1375 || restore_arg1(tcp, &state, tcp->inst[1]) < 0
1376 || arg_finish_change(tcp, &state))
Denys Vlasenkoc133bf02011-06-23 21:57:54 +02001377 if (errno != ESRCH)
1378 return -1;
Roland McGrathd81f1d92003-01-09 06:53:34 +00001379 tcp->flags &= ~TCB_BPTSET;
1380 return 0;
1381}