blob: f42024d82f0540ad043ba48f033a956e5fe53527 [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
Denys Vlasenko2d1e90f2012-02-25 02:46:14 +010067#if defined(SPARC64)
Roland McGrath6d1a65c2004-07-12 07:44:08 +000068# undef PTRACE_GETREGS
69# define PTRACE_GETREGS PTRACE_GETREGS64
70# undef PTRACE_SETREGS
71# define PTRACE_SETREGS PTRACE_SETREGS64
Wichert Akkerman9ce1a631999-08-29 23:15:07 +000072#endif
73
Wichert Akkerman76baf7c1999-02-19 00:21:36 +000074/* macros */
75#ifndef MAX
Denys Vlasenko2d1e90f2012-02-25 02:46:14 +010076# define MAX(a,b) (((a) > (b)) ? (a) : (b))
Wichert Akkerman76baf7c1999-02-19 00:21:36 +000077#endif
78#ifndef MIN
Denys Vlasenko2d1e90f2012-02-25 02:46:14 +010079# define MIN(a,b) (((a) < (b)) ? (a) : (b))
Wichert Akkerman76baf7c1999-02-19 00:21:36 +000080#endif
81
Wichert Akkerman76baf7c1999-02-19 00:21:36 +000082int
Dmitry V. Levinccee1692012-03-25 21:49:48 +000083string_to_uint(const char *str)
84{
85 char *error;
86 long value;
87
88 if (!*str)
89 return -1;
90 errno = 0;
91 value = strtol(str, &error, 10);
92 if (errno || *error || value < 0 || (long)(int)value != value)
93 return -1;
94 return (int)value;
95}
96
97int
Denys Vlasenko12014262011-05-30 14:00:14 +020098tv_nz(struct timeval *a)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +000099{
100 return a->tv_sec || a->tv_usec;
101}
102
103int
Denys Vlasenko12014262011-05-30 14:00:14 +0200104tv_cmp(struct timeval *a, struct timeval *b)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000105{
106 if (a->tv_sec < b->tv_sec
107 || (a->tv_sec == b->tv_sec && a->tv_usec < b->tv_usec))
108 return -1;
109 if (a->tv_sec > b->tv_sec
110 || (a->tv_sec == b->tv_sec && a->tv_usec > b->tv_usec))
111 return 1;
112 return 0;
113}
114
115double
Denys Vlasenko12014262011-05-30 14:00:14 +0200116tv_float(struct timeval *tv)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000117{
118 return tv->tv_sec + tv->tv_usec/1000000.0;
119}
120
121void
Denys Vlasenko12014262011-05-30 14:00:14 +0200122tv_add(struct timeval *tv, struct timeval *a, struct timeval *b)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000123{
124 tv->tv_sec = a->tv_sec + b->tv_sec;
125 tv->tv_usec = a->tv_usec + b->tv_usec;
Roland McGrath58372f52007-07-24 01:38:22 +0000126 if (tv->tv_usec >= 1000000) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000127 tv->tv_sec++;
128 tv->tv_usec -= 1000000;
129 }
130}
131
132void
Denys Vlasenko12014262011-05-30 14:00:14 +0200133tv_sub(struct timeval *tv, struct timeval *a, struct timeval *b)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000134{
135 tv->tv_sec = a->tv_sec - b->tv_sec;
136 tv->tv_usec = a->tv_usec - b->tv_usec;
137 if (((long) tv->tv_usec) < 0) {
138 tv->tv_sec--;
139 tv->tv_usec += 1000000;
140 }
141}
142
143void
Denys Vlasenko12014262011-05-30 14:00:14 +0200144tv_div(struct timeval *tv, struct timeval *a, int n)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000145{
146 tv->tv_usec = (a->tv_sec % n * 1000000 + a->tv_usec + n / 2) / n;
147 tv->tv_sec = a->tv_sec / n + tv->tv_usec / 1000000;
148 tv->tv_usec %= 1000000;
149}
150
151void
Denys Vlasenko12014262011-05-30 14:00:14 +0200152tv_mul(struct timeval *tv, struct timeval *a, int n)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000153{
154 tv->tv_usec = a->tv_usec * n;
Dmitry V. Levinfefdd972007-06-29 21:25:56 +0000155 tv->tv_sec = a->tv_sec * n + tv->tv_usec / 1000000;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000156 tv->tv_usec %= 1000000;
157}
158
Dmitry V. Levinab9008b2007-01-11 22:05:04 +0000159const char *
160xlookup(const struct xlat *xlat, int val)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000161{
162 for (; xlat->str != NULL; xlat++)
163 if (xlat->val == val)
164 return xlat->str;
165 return NULL;
166}
167
Denys Vlasenko0a295bc2011-09-01 16:31:48 +0200168#if !defined HAVE_STPCPY
Denys Vlasenko52845572011-08-31 12:07:38 +0200169char *
170stpcpy(char *dst, const char *src)
171{
172 while ((*dst = *src++) != '\0')
173 dst++;
174 return dst;
175}
Denys Vlasenko0a295bc2011-09-01 16:31:48 +0200176#endif
Denys Vlasenko52845572011-08-31 12:07:38 +0200177
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000178/*
179 * Print entry in struct xlat table, if there.
180 */
181void
Dmitry V. Levinab9008b2007-01-11 22:05:04 +0000182printxval(const struct xlat *xlat, int val, const char *dflt)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000183{
Dmitry V. Levinab9008b2007-01-11 22:05:04 +0000184 const char *str = xlookup(xlat, val);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000185
186 if (str)
Denys Vlasenko5940e652011-09-01 09:55:05 +0200187 tprints(str);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000188 else
189 tprintf("%#x /* %s */", val, dflt);
190}
191
Andreas Schwabb5600fc2009-11-04 17:08:34 +0100192#if HAVE_LONG_LONG
193/*
194 * Print 64bit argument at position llarg and return the index of the next
195 * argument.
196 */
197int
198printllval(struct tcb *tcp, const char *format, int llarg)
199{
Denys Vlasenkoaa925db2012-02-25 15:19:02 +0100200# if defined(X86_64) || defined(POWERPC64)
Andreas Schwabb5600fc2009-11-04 17:08:34 +0100201 if (current_personality == 0) {
202 tprintf(format, tcp->u_arg[llarg]);
203 llarg++;
204 } else {
Andreas Schwabd69fa492010-07-12 21:39:57 +0200205# ifdef POWERPC64
206 /* Align 64bit argument to 64bit boundary. */
Denys Vlasenko4b08df42011-08-19 15:58:24 +0200207 llarg = (llarg + 1) & 0x1e;
Andreas Schwabd69fa492010-07-12 21:39:57 +0200208# endif
Andreas Schwabb5600fc2009-11-04 17:08:34 +0100209 tprintf(format, LONG_LONG(tcp->u_arg[llarg], tcp->u_arg[llarg + 1]));
210 llarg += 2;
211 }
Andreas Schwabd69fa492010-07-12 21:39:57 +0200212# elif defined IA64 || defined ALPHA
Andreas Schwabb5600fc2009-11-04 17:08:34 +0100213 tprintf(format, tcp->u_arg[llarg]);
214 llarg++;
H.J. Lu35be5812012-04-16 13:00:01 +0200215# elif defined LINUX_MIPSN32 || defined X32
Andreas Schwabb5600fc2009-11-04 17:08:34 +0100216 tprintf(format, tcp->ext_arg[llarg]);
217 llarg++;
218# else
219 tprintf(format, LONG_LONG(tcp->u_arg[llarg], tcp->u_arg[llarg + 1]));
220 llarg += 2;
221# endif
222 return llarg;
223}
224#endif
225
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000226/*
227 * Interpret `xlat' as an array of flags
228 * print the entries whose bits are on in `flags'
229 * return # of flags printed.
230 */
Denys Vlasenko4924dbd2011-08-19 18:06:46 +0200231void
Denys Vlasenko12014262011-05-30 14:00:14 +0200232addflags(const struct xlat *xlat, int flags)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000233{
Denys Vlasenko4924dbd2011-08-19 18:06:46 +0200234 for (; xlat->str; xlat++) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000235 if (xlat->val && (flags & xlat->val) == xlat->val) {
236 tprintf("|%s", xlat->str);
237 flags &= ~xlat->val;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000238 }
239 }
240 if (flags) {
241 tprintf("|%#x", flags);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000242 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000243}
244
Roland McGratha6c0d8c2007-11-01 21:46:22 +0000245/*
Denys Vlasenko4924dbd2011-08-19 18:06:46 +0200246 * Interpret `xlat' as an array of flags.
Roland McGratha6c0d8c2007-11-01 21:46:22 +0000247 * Print to static string the entries whose bits are on in `flags'
248 * Return static string.
249 */
250const char *
251sprintflags(const char *prefix, const struct xlat *xlat, int flags)
252{
253 static char outstr[1024];
Denys Vlasenko52845572011-08-31 12:07:38 +0200254 char *outptr;
Roland McGratha6c0d8c2007-11-01 21:46:22 +0000255 int found = 0;
256
Denys Vlasenko52845572011-08-31 12:07:38 +0200257 outptr = stpcpy(outstr, prefix);
Roland McGratha6c0d8c2007-11-01 21:46:22 +0000258
259 for (; xlat->str; xlat++) {
260 if ((flags & xlat->val) == xlat->val) {
261 if (found)
Denys Vlasenko52845572011-08-31 12:07:38 +0200262 *outptr++ = '|';
263 outptr = stpcpy(outptr, xlat->str);
Roland McGratha6c0d8c2007-11-01 21:46:22 +0000264 found = 1;
Denys Vlasenko4f3df072012-01-29 22:38:35 +0100265 flags &= ~xlat->val;
266 if (!flags)
267 break;
Roland McGratha6c0d8c2007-11-01 21:46:22 +0000268 }
269 }
270 if (flags) {
271 if (found)
Denys Vlasenko52845572011-08-31 12:07:38 +0200272 *outptr++ = '|';
273 outptr += sprintf(outptr, "%#x", flags);
Roland McGratha6c0d8c2007-11-01 21:46:22 +0000274 }
275
276 return outstr;
277}
278
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000279int
Dmitry V. Levin30145dd2010-09-06 22:08:24 +0000280printflags(const struct xlat *xlat, int flags, const char *dflt)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000281{
282 int n;
Dmitry V. Levin30145dd2010-09-06 22:08:24 +0000283 const char *sep;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000284
285 if (flags == 0 && xlat->val == 0) {
Denys Vlasenko5940e652011-09-01 09:55:05 +0200286 tprints(xlat->str);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000287 return 1;
288 }
289
290 sep = "";
291 for (n = 0; xlat->str; xlat++) {
292 if (xlat->val && (flags & xlat->val) == xlat->val) {
293 tprintf("%s%s", sep, xlat->str);
294 flags &= ~xlat->val;
295 sep = "|";
296 n++;
297 }
298 }
Roland McGrathb2dee132005-06-01 19:02:36 +0000299
300 if (n) {
301 if (flags) {
302 tprintf("%s%#x", sep, flags);
303 n++;
304 }
305 } else {
306 if (flags) {
307 tprintf("%#x", flags);
308 if (dflt)
309 tprintf(" /* %s */", dflt);
310 } else {
311 if (dflt)
Denys Vlasenko60fe8c12011-09-01 10:00:28 +0200312 tprints("0");
Roland McGrathb2dee132005-06-01 19:02:36 +0000313 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000314 }
Roland McGrathb2dee132005-06-01 19:02:36 +0000315
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000316 return n;
317}
318
319void
Dmitry V. Levin30145dd2010-09-06 22:08:24 +0000320printnum(struct tcb *tcp, long addr, const char *fmt)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000321{
Roland McGratheb285352003-01-14 09:59:00 +0000322 long num;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000323
324 if (!addr) {
Denys Vlasenko60fe8c12011-09-01 10:00:28 +0200325 tprints("NULL");
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000326 return;
327 }
328 if (umove(tcp, addr, &num) < 0) {
329 tprintf("%#lx", addr);
330 return;
331 }
Denys Vlasenko60fe8c12011-09-01 10:00:28 +0200332 tprints("[");
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000333 tprintf(fmt, num);
Denys Vlasenko60fe8c12011-09-01 10:00:28 +0200334 tprints("]");
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000335}
336
Roland McGrath6bc12202003-11-13 22:32:27 +0000337void
Dmitry V. Levin30145dd2010-09-06 22:08:24 +0000338printnum_int(struct tcb *tcp, long addr, const char *fmt)
Roland McGrath9814a942005-07-04 23:28:10 +0000339{
340 int num;
341
342 if (!addr) {
Denys Vlasenko60fe8c12011-09-01 10:00:28 +0200343 tprints("NULL");
Roland McGrath9814a942005-07-04 23:28:10 +0000344 return;
345 }
346 if (umove(tcp, addr, &num) < 0) {
347 tprintf("%#lx", addr);
348 return;
349 }
Denys Vlasenko60fe8c12011-09-01 10:00:28 +0200350 tprints("[");
Roland McGrath9814a942005-07-04 23:28:10 +0000351 tprintf(fmt, num);
Denys Vlasenko60fe8c12011-09-01 10:00:28 +0200352 tprints("]");
Roland McGrath9814a942005-07-04 23:28:10 +0000353}
354
355void
Dmitry V. Levin31382132011-03-04 05:08:02 +0300356printfd(struct tcb *tcp, int fd)
357{
Grant Edwards8a082772011-04-07 20:25:40 +0000358 const char *p;
359
360 if (show_fd_path && (p = getfdpath(tcp, fd)))
361 tprintf("%d<%s>", fd, p);
362 else
363 tprintf("%d", fd);
Dmitry V. Levin31382132011-03-04 05:08:02 +0300364}
365
366void
Denys Vlasenko12014262011-05-30 14:00:14 +0200367printuid(const char *text, unsigned long uid)
Roland McGrath6bc12202003-11-13 22:32:27 +0000368{
Denys Vlasenko5940e652011-09-01 09:55:05 +0200369 tprintf((uid == -1) ? "%s%ld" : "%s%lu", text, uid);
Roland McGrath6bc12202003-11-13 22:32:27 +0000370}
371
Dmitry V. Levina501f142008-11-10 23:19:13 +0000372/*
373 * Quote string `instr' of length `size'
374 * Write up to (3 + `size' * 4) bytes to `outstr' buffer.
Denys Vlasenkob5d43b82012-04-28 14:58:35 +0200375 * If `len' is -1, treat `instr' as a NUL-terminated string
Dmitry V. Levina501f142008-11-10 23:19:13 +0000376 * and quote at most (`size' - 1) bytes.
Denys Vlasenko6cecba52012-01-20 11:56:00 +0100377 *
Denys Vlasenkob5d43b82012-04-28 14:58:35 +0200378 * Returns 0 if len == -1 and NUL was seen, 1 otherwise.
Denys Vlasenko6cecba52012-01-20 11:56:00 +0100379 * Note that if len >= 0, always returns 1.
Dmitry V. Levina501f142008-11-10 23:19:13 +0000380 */
Mike Frysingerebee04c2012-04-17 22:19:31 -0400381int
Denys Vlasenkob5d43b82012-04-28 14:58:35 +0200382string_quote(const char *instr, char *outstr, long len, int size)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000383{
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000384 const unsigned char *ustr = (const unsigned char *) instr;
385 char *s = outstr;
Denys Vlasenko8778bff2011-08-31 12:22:56 +0200386 int usehex, c, i, eol;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000387
Denys Vlasenko8778bff2011-08-31 12:22:56 +0200388 eol = 0x100; /* this can never match a char */
Denys Vlasenkob5d43b82012-04-28 14:58:35 +0200389 if (len == -1) {
Denys Vlasenko8778bff2011-08-31 12:22:56 +0200390 size--;
391 eol = '\0';
392 }
393
394 usehex = 0;
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000395 if (xflag > 1)
396 usehex = 1;
397 else if (xflag) {
Dmitry V. Levina501f142008-11-10 23:19:13 +0000398 /* Check for presence of symbol which require
399 to hex-quote the whole string. */
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000400 for (i = 0; i < size; ++i) {
401 c = ustr[i];
Dmitry V. Levina501f142008-11-10 23:19:13 +0000402 /* Check for NUL-terminated string. */
Denys Vlasenko8778bff2011-08-31 12:22:56 +0200403 if (c == eol)
404 break;
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000405 if (!isprint(c) && !isspace(c)) {
406 usehex = 1;
407 break;
408 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000409 }
410 }
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000411
412 *s++ = '\"';
413
414 if (usehex) {
Dmitry V. Levina501f142008-11-10 23:19:13 +0000415 /* Hex-quote the whole string. */
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000416 for (i = 0; i < size; ++i) {
417 c = ustr[i];
Dmitry V. Levina501f142008-11-10 23:19:13 +0000418 /* Check for NUL-terminated string. */
Denys Vlasenko8778bff2011-08-31 12:22:56 +0200419 if (c == eol)
420 goto asciz_ended;
421 *s++ = '\\';
422 *s++ = 'x';
423 *s++ = "0123456789abcdef"[c >> 4];
424 *s++ = "0123456789abcdef"[c & 0xf];
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000425 }
426 } else {
427 for (i = 0; i < size; ++i) {
428 c = ustr[i];
Dmitry V. Levina501f142008-11-10 23:19:13 +0000429 /* Check for NUL-terminated string. */
Denys Vlasenko8778bff2011-08-31 12:22:56 +0200430 if (c == eol)
431 goto asciz_ended;
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000432 switch (c) {
433 case '\"': case '\\':
434 *s++ = '\\';
435 *s++ = c;
436 break;
437 case '\f':
438 *s++ = '\\';
439 *s++ = 'f';
440 break;
441 case '\n':
442 *s++ = '\\';
443 *s++ = 'n';
444 break;
445 case '\r':
446 *s++ = '\\';
447 *s++ = 'r';
448 break;
449 case '\t':
450 *s++ = '\\';
451 *s++ = 't';
452 break;
453 case '\v':
454 *s++ = '\\';
455 *s++ = 'v';
456 break;
457 default:
458 if (isprint(c))
459 *s++ = c;
Denys Vlasenko8778bff2011-08-31 12:22:56 +0200460 else {
461 /* Print \octal */
462 *s++ = '\\';
463 if (i + 1 < size
464 && ustr[i + 1] >= '0'
465 && ustr[i + 1] <= '9'
466 ) {
467 /* Print \ooo */
468 *s++ = '0' + (c >> 6);
469 *s++ = '0' + ((c >> 3) & 0x7);
470 } else {
471 /* Print \[[o]o]o */
472 if ((c >> 3) != 0) {
473 if ((c >> 6) != 0)
474 *s++ = '0' + (c >> 6);
475 *s++ = '0' + ((c >> 3) & 0x7);
476 }
477 }
478 *s++ = '0' + (c & 0x7);
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000479 }
480 break;
481 }
482 }
483 }
484
485 *s++ = '\"';
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000486 *s = '\0';
Roland McGrath6d970322007-11-01 23:53:59 +0000487
Denys Vlasenko8778bff2011-08-31 12:22:56 +0200488 /* Return zero if we printed entire ASCIZ string (didn't truncate it) */
Denys Vlasenkob5d43b82012-04-28 14:58:35 +0200489 if (len == -1 && ustr[i] == '\0') {
Denys Vlasenko8778bff2011-08-31 12:22:56 +0200490 /* We didn't see NUL yet (otherwise we'd jump to 'asciz_ended')
491 * but next char is NUL.
492 */
493 return 0;
494 }
495
496 return 1;
497
498 asciz_ended:
499 *s++ = '\"';
500 *s = '\0';
501 /* Return zero: we printed entire ASCIZ string (didn't truncate it) */
502 return 0;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000503}
504
Dmitry V. Levina501f142008-11-10 23:19:13 +0000505/*
506 * Print path string specified by address `addr' and length `n'.
507 * If path length exceeds `n', append `...' to the output.
508 */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000509void
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000510printpathn(struct tcb *tcp, long addr, int n)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000511{
Denys Vlasenkob3c52cf2012-01-19 17:20:23 +0100512 char path[MAXPATHLEN + 1];
Denys Vlasenko6cecba52012-01-20 11:56:00 +0100513 int nul_seen;
Denys Vlasenkob3c52cf2012-01-19 17:20:23 +0100514
Dmitry V. Levina501f142008-11-10 23:19:13 +0000515 if (!addr) {
Denys Vlasenko60fe8c12011-09-01 10:00:28 +0200516 tprints("NULL");
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000517 return;
518 }
519
Denys Vlasenko6cecba52012-01-20 11:56:00 +0100520 /* Cap path length to the path buffer size */
Dmitry V. Levina501f142008-11-10 23:19:13 +0000521 if (n > sizeof path - 1)
522 n = sizeof path - 1;
Dmitry V. Levina501f142008-11-10 23:19:13 +0000523
524 /* Fetch one byte more to find out whether path length > n. */
Denys Vlasenko6cecba52012-01-20 11:56:00 +0100525 nul_seen = umovestr(tcp, addr, n + 1, path);
526 if (nul_seen < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000527 tprintf("%#lx", addr);
528 else {
Denys Vlasenkob3c52cf2012-01-19 17:20:23 +0100529 char *outstr;
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000530
Denys Vlasenko6cecba52012-01-20 11:56:00 +0100531 path[n] = '\0';
Denys Vlasenkob3c52cf2012-01-19 17:20:23 +0100532 n++;
Denys Vlasenko6cecba52012-01-20 11:56:00 +0100533 outstr = alloca(4 * n); /* 4*(n-1) + 3 for quotes and NUL */
Denys Vlasenkob3c52cf2012-01-19 17:20:23 +0100534 string_quote(path, outstr, -1, n);
535 tprints(outstr);
Denys Vlasenko6cecba52012-01-20 11:56:00 +0100536 if (!nul_seen)
Denys Vlasenkob3c52cf2012-01-19 17:20:23 +0100537 tprints("...");
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000538 }
539}
540
541void
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000542printpath(struct tcb *tcp, long addr)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000543{
Denys Vlasenkob3c52cf2012-01-19 17:20:23 +0100544 /* Size must correspond to char path[] size in printpathn */
545 printpathn(tcp, addr, MAXPATHLEN);
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000546}
547
Dmitry V. Levina501f142008-11-10 23:19:13 +0000548/*
549 * Print string specified by address `addr' and length `len'.
550 * If `len' < 0, treat the string as a NUL-terminated string.
551 * If string length exceeds `max_strlen', append `...' to the output.
552 */
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000553void
Denys Vlasenkob5d43b82012-04-28 14:58:35 +0200554printstr(struct tcb *tcp, long addr, long len)
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000555{
556 static char *str = NULL;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000557 static char *outstr;
Roland McGrath6d970322007-11-01 23:53:59 +0000558 int size;
Denys Vlasenkob3c52cf2012-01-19 17:20:23 +0100559 int ellipsis;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000560
561 if (!addr) {
Denys Vlasenko60fe8c12011-09-01 10:00:28 +0200562 tprints("NULL");
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000563 return;
564 }
Dmitry V. Levina501f142008-11-10 23:19:13 +0000565 /* Allocate static buffers if they are not allocated yet. */
Denys Vlasenko1d46ba52011-08-31 14:00:02 +0200566 if (!str) {
Dmitry V. Levin378f9c52012-03-25 22:56:53 +0000567 unsigned int outstr_size = 4 * max_strlen + /*for quotes and NUL:*/ 3;
568
569 if (outstr_size / 4 != max_strlen)
570 die_out_of_memory();
Dmitry V. Levina501f142008-11-10 23:19:13 +0000571 str = malloc(max_strlen + 1);
Denys Vlasenko1d46ba52011-08-31 14:00:02 +0200572 if (!str)
573 die_out_of_memory();
Dmitry V. Levin378f9c52012-03-25 22:56:53 +0000574 outstr = malloc(outstr_size);
Denys Vlasenko1d46ba52011-08-31 14:00:02 +0200575 if (!outstr)
576 die_out_of_memory();
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000577 }
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000578
Denys Vlasenkob5d43b82012-04-28 14:58:35 +0200579 if (len == -1) {
Dmitry V. Levina501f142008-11-10 23:19:13 +0000580 /*
581 * Treat as a NUL-terminated string: fetch one byte more
582 * because string_quote() quotes one byte less.
583 */
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000584 size = max_strlen + 1;
585 if (umovestr(tcp, addr, size, str) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000586 tprintf("%#lx", addr);
587 return;
588 }
589 }
590 else {
Denys Vlasenkob5d43b82012-04-28 14:58:35 +0200591 size = max_strlen;
592 if (size > (unsigned long)len)
593 size = (unsigned long)len;
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000594 if (umoven(tcp, addr, size, str) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000595 tprintf("%#lx", addr);
596 return;
597 }
598 }
599
Denys Vlasenko6cecba52012-01-20 11:56:00 +0100600 /* If string_quote didn't see NUL and (it was supposed to be ASCIZ str
601 * or we were requested to print more than -s NUM chars)...
602 */
Denys Vlasenkob3c52cf2012-01-19 17:20:23 +0100603 ellipsis = (string_quote(str, outstr, len, size) &&
604 (len < 0 || len > max_strlen));
Roland McGratha503dcf2007-08-02 02:06:26 +0000605
Denys Vlasenkob3c52cf2012-01-19 17:20:23 +0100606 tprints(outstr);
607 if (ellipsis)
608 tprints("...");
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000609}
610
John Hughes1d08dcf2001-07-10 13:48:44 +0000611#if HAVE_SYS_UIO_H
612void
Denys Vlasenko12014262011-05-30 14:00:14 +0200613dumpiov(struct tcb *tcp, int len, long addr)
John Hughes1d08dcf2001-07-10 13:48:44 +0000614{
Denys Vlasenko84703742012-02-25 02:38:52 +0100615#if SUPPORTED_PERSONALITIES > 1
Dmitry V. Levin4ebb4e32006-12-13 17:08:08 +0000616 union {
617 struct { u_int32_t base; u_int32_t len; } *iov32;
618 struct { u_int64_t base; u_int64_t len; } *iov64;
619 } iovu;
620#define iov iovu.iov64
621#define sizeof_iov \
Denys Vlasenko9fd4f962012-03-19 09:36:42 +0100622 (current_wordsize == 4 ? sizeof(*iovu.iov32) : sizeof(*iovu.iov64))
Dmitry V. Levin4ebb4e32006-12-13 17:08:08 +0000623#define iov_iov_base(i) \
Denys Vlasenko9fd4f962012-03-19 09:36:42 +0100624 (current_wordsize == 4 ? (uint64_t) iovu.iov32[i].base : iovu.iov64[i].base)
Dmitry V. Levin4ebb4e32006-12-13 17:08:08 +0000625#define iov_iov_len(i) \
Denys Vlasenko9fd4f962012-03-19 09:36:42 +0100626 (current_wordsize == 4 ? (uint64_t) iovu.iov32[i].len : iovu.iov64[i].len)
Dmitry V. Levin4ebb4e32006-12-13 17:08:08 +0000627#else
John Hughes1d08dcf2001-07-10 13:48:44 +0000628 struct iovec *iov;
Dmitry V. Levin4ebb4e32006-12-13 17:08:08 +0000629#define sizeof_iov sizeof(*iov)
630#define iov_iov_base(i) iov[i].iov_base
631#define iov_iov_len(i) iov[i].iov_len
632#endif
John Hughes1d08dcf2001-07-10 13:48:44 +0000633 int i;
Denys Vlasenko79a79ea2011-09-01 16:35:44 +0200634 unsigned size;
John Hughes1d08dcf2001-07-10 13:48:44 +0000635
Denys Vlasenko79a79ea2011-09-01 16:35:44 +0200636 size = sizeof_iov * len;
637 /* Assuming no sane program has millions of iovs */
638 if ((unsigned)len > 1024*1024 /* insane or negative size? */
Dmitry V. Levin4ebb4e32006-12-13 17:08:08 +0000639 || (iov = malloc(size)) == NULL) {
Denys Vlasenko79a79ea2011-09-01 16:35:44 +0200640 fprintf(stderr, "Out of memory\n");
641 return;
John Hughes1d08dcf2001-07-10 13:48:44 +0000642 }
Roland McGrathaa524c82005-06-01 19:22:06 +0000643 if (umoven(tcp, addr, size, (char *) iov) >= 0) {
John Hughes1d08dcf2001-07-10 13:48:44 +0000644 for (i = 0; i < len; i++) {
Denys Vlasenkoadedb512008-12-30 18:47:55 +0000645 /* include the buffer number to make it easy to
646 * match up the trace with the source */
647 tprintf(" * %lu bytes in buffer %d\n",
648 (unsigned long)iov_iov_len(i), i);
649 dumpstr(tcp, (long) iov_iov_base(i),
650 iov_iov_len(i));
651 }
John Hughes1d08dcf2001-07-10 13:48:44 +0000652 }
Denys Vlasenko79a79ea2011-09-01 16:35:44 +0200653 free(iov);
Dmitry V. Levin4ebb4e32006-12-13 17:08:08 +0000654#undef sizeof_iov
655#undef iov_iov_base
656#undef iov_iov_len
657#undef iov
John Hughes1d08dcf2001-07-10 13:48:44 +0000658}
659#endif
660
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000661void
Denys Vlasenko12014262011-05-30 14:00:14 +0200662dumpstr(struct tcb *tcp, long addr, int len)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000663{
664 static int strsize = -1;
665 static unsigned char *str;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000666 char *s;
667 int i, j;
668
669 if (strsize < len) {
Denys Vlasenko5d645812011-08-20 12:48:18 +0200670 free(str);
671 str = malloc(len);
Denys Vlasenko79a79ea2011-09-01 16:35:44 +0200672 if (!str) {
673 strsize = -1;
674 fprintf(stderr, "Out of memory\n");
675 return;
676 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000677 strsize = len;
678 }
679
680 if (umoven(tcp, addr, len, (char *) str) < 0)
681 return;
682
683 for (i = 0; i < len; i += 16) {
Denys Vlasenko1d46ba52011-08-31 14:00:02 +0200684 char outstr[80];
685
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000686 s = outstr;
687 sprintf(s, " | %05x ", i);
688 s += 9;
689 for (j = 0; j < 16; j++) {
690 if (j == 8)
691 *s++ = ' ';
692 if (i + j < len) {
693 sprintf(s, " %02x", str[i + j]);
694 s += 3;
695 }
696 else {
697 *s++ = ' '; *s++ = ' '; *s++ = ' ';
698 }
699 }
700 *s++ = ' '; *s++ = ' ';
701 for (j = 0; j < 16; j++) {
702 if (j == 8)
703 *s++ = ' ';
704 if (i + j < len) {
705 if (isprint(str[i + j]))
706 *s++ = str[i + j];
707 else
708 *s++ = '.';
709 }
710 else
711 *s++ = ' ';
712 }
713 tprintf("%s |\n", outstr);
714 }
715}
716
Mike Frysinger612659e2012-02-14 14:38:28 +0100717#ifdef HAVE_PROCESS_VM_READV
718/* C library supports this, but the kernel might not. */
719static bool process_vm_readv_not_supported = 0;
720#else
721
Denys Vlasenko3af224c2012-01-28 01:46:33 +0100722/* Need to do this since process_vm_readv() is not yet available in libc.
723 * When libc is be updated, only "static bool process_vm_readv_not_supported"
724 * line should remain.
725 */
726#if !defined(__NR_process_vm_readv)
727# if defined(I386)
728# define __NR_process_vm_readv 347
729# elif defined(X86_64)
730# define __NR_process_vm_readv 310
731# elif defined(POWERPC)
732# define __NR_process_vm_readv 351
733# endif
734#endif
735
736#if defined(__NR_process_vm_readv)
737static bool process_vm_readv_not_supported = 0;
Mike Frysinger24ee60b2012-05-04 19:37:29 -0400738/* Have to avoid duplicating with the C library headers. */
739static ssize_t strace_process_vm_readv(pid_t pid,
Denys Vlasenko3af224c2012-01-28 01:46:33 +0100740 const struct iovec *lvec,
741 unsigned long liovcnt,
742 const struct iovec *rvec,
743 unsigned long riovcnt,
744 unsigned long flags)
745{
746 return syscall(__NR_process_vm_readv, (long)pid, lvec, liovcnt, rvec, riovcnt, flags);
747}
Mike Frysinger24ee60b2012-05-04 19:37:29 -0400748#define process_vm_readv strace_process_vm_readv
Denys Vlasenko3af224c2012-01-28 01:46:33 +0100749#else
750static bool process_vm_readv_not_supported = 1;
751# define process_vm_readv(...) (errno = ENOSYS, -1)
752#endif
Mike Frysinger612659e2012-02-14 14:38:28 +0100753
754#endif /* end of hack */
Denys Vlasenko3af224c2012-01-28 01:46:33 +0100755
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000756#define PAGMASK (~(PAGSIZ - 1))
757/*
758 * move `len' bytes of data from process `pid'
759 * at address `addr' to our space at `laddr'
760 */
761int
Denys Vlasenkoef2fbf82009-01-06 21:45:06 +0000762umoven(struct tcb *tcp, long addr, int len, char *laddr)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000763{
Roland McGratheb9e2e82009-06-02 16:49:22 -0700764 int pid = tcp->pid;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000765 int n, m;
Denys Vlasenkoa47e6b92012-01-21 04:01:56 +0100766 int started;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000767 union {
768 long val;
769 char x[sizeof(long)];
770 } u;
771
Denys Vlasenkod2a660f2012-02-25 00:43:22 +0100772#if SUPPORTED_PERSONALITIES > 1
Denys Vlasenko9fd4f962012-03-19 09:36:42 +0100773 if (current_wordsize < sizeof(addr))
774 addr &= (1ul << 8 * current_wordsize) - 1;
Denys Vlasenkod2a660f2012-02-25 00:43:22 +0100775#endif
776
Denys Vlasenko3af224c2012-01-28 01:46:33 +0100777 if (!process_vm_readv_not_supported) {
778 struct iovec local[1], remote[1];
779 int r;
780
781 local[0].iov_base = laddr;
782 remote[0].iov_base = (void*)addr;
783 local[0].iov_len = remote[0].iov_len = len;
784 r = process_vm_readv(pid,
785 local, 1,
786 remote, 1,
787 /*flags:*/ 0
788 );
789 if (r < 0) {
790 if (errno == ENOSYS)
791 process_vm_readv_not_supported = 1;
Dmitry V. Levin9a71bcd2012-09-17 23:20:54 +0000792 else if (errno != EINVAL && errno != ESRCH)
793 /* EINVAL or ESRCH could be seen if process is gone,
794 * all the rest is strange and should be reported. */
795 perror_msg("%s", "process_vm_readv");
Denys Vlasenko3af224c2012-01-28 01:46:33 +0100796 goto vm_readv_didnt_work;
797 }
798 return r;
799 }
800 vm_readv_didnt_work:
801
Denys Vlasenkoa47e6b92012-01-21 04:01:56 +0100802 started = 0;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000803 if (addr & (sizeof(long) - 1)) {
804 /* addr not a multiple of sizeof(long) */
805 n = addr - (addr & -sizeof(long)); /* residue */
806 addr &= -sizeof(long); /* residue */
Roland McGratheb9e2e82009-06-02 16:49:22 -0700807 errno = 0;
808 u.val = ptrace(PTRACE_PEEKDATA, pid, (char *) addr, 0);
809 if (errno) {
Roland McGratheb9e2e82009-06-02 16:49:22 -0700810 /* But if not started, we had a bogus address. */
811 if (addr != 0 && errno != EIO && errno != ESRCH)
Denys Vlasenko4c65c442012-03-08 11:54:10 +0100812 perror_msg("umoven: PTRACE_PEEKDATA pid:%d @0x%lx", pid, addr);
Roland McGratheb9e2e82009-06-02 16:49:22 -0700813 return -1;
814 }
Wichert Akkerman5daa0281999-03-15 19:49:42 +0000815 started = 1;
Denys Vlasenkoa47e6b92012-01-21 04:01:56 +0100816 m = MIN(sizeof(long) - n, len);
817 memcpy(laddr, &u.x[n], m);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000818 addr += sizeof(long), laddr += m, len -= m;
819 }
820 while (len) {
Roland McGratheb9e2e82009-06-02 16:49:22 -0700821 errno = 0;
822 u.val = ptrace(PTRACE_PEEKDATA, pid, (char *) addr, 0);
823 if (errno) {
824 if (started && (errno==EPERM || errno==EIO)) {
825 /* Ran into 'end of memory' - stupid "printpath" */
826 return 0;
827 }
828 if (addr != 0 && errno != EIO && errno != ESRCH)
Denys Vlasenko4c65c442012-03-08 11:54:10 +0100829 perror_msg("umoven: PTRACE_PEEKDATA pid:%d @0x%lx", pid, addr);
Roland McGratheb9e2e82009-06-02 16:49:22 -0700830 return -1;
831 }
Wichert Akkerman5daa0281999-03-15 19:49:42 +0000832 started = 1;
Denys Vlasenkoa47e6b92012-01-21 04:01:56 +0100833 m = MIN(sizeof(long), len);
834 memcpy(laddr, u.x, m);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000835 addr += sizeof(long), laddr += m, len -= m;
836 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000837
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000838 return 0;
839}
840
841/*
Denys Vlasenko6cecba52012-01-20 11:56:00 +0100842 * Like `umove' but make the additional effort of looking
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000843 * for a terminating zero byte.
Denys Vlasenko6cecba52012-01-20 11:56:00 +0100844 *
845 * Returns < 0 on error, > 0 if NUL was seen,
846 * (TODO if useful: return count of bytes including NUL),
847 * else 0 if len bytes were read but no NUL byte seen.
848 *
849 * Note: there is no guarantee we won't overwrite some bytes
850 * in laddr[] _after_ terminating NUL (but, of course,
851 * we never write past laddr[len-1]).
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000852 */
853int
Denys Vlasenkoef2fbf82009-01-06 21:45:06 +0000854umovestr(struct tcb *tcp, long addr, int len, char *laddr)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000855{
Denys Vlasenkoa47e6b92012-01-21 04:01:56 +0100856 int started;
Roland McGratheb9e2e82009-06-02 16:49:22 -0700857 int pid = tcp->pid;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000858 int i, n, m;
859 union {
860 long val;
861 char x[sizeof(long)];
862 } u;
863
Dmitry V. Levin856c7ed2011-12-26 20:12:02 +0000864#if SUPPORTED_PERSONALITIES > 1
Denys Vlasenko9fd4f962012-03-19 09:36:42 +0100865 if (current_wordsize < sizeof(addr))
866 addr &= (1ul << 8 * current_wordsize) - 1;
Dmitry V. Levin856c7ed2011-12-26 20:12:02 +0000867#endif
868
Denys Vlasenko3af224c2012-01-28 01:46:33 +0100869 if (!process_vm_readv_not_supported) {
870 struct iovec local[1], remote[1];
871
872 local[0].iov_base = laddr;
873 remote[0].iov_base = (void*)addr;
874
875 while (len > 0) {
876 int end_in_page;
877 int r;
878 int chunk_len;
879
880 /* Don't read kilobytes: most strings are short */
881 chunk_len = len;
882 if (chunk_len > 256)
883 chunk_len = 256;
884 /* Don't cross pages. I guess otherwise we can get EFAULT
885 * and fail to notice that terminating NUL lies
886 * in the existing (first) page.
887 * (I hope there aren't arches with pages < 4K)
888 */
889 end_in_page = ((addr + chunk_len) & 4095);
890 r = chunk_len - end_in_page;
891 if (r > 0) /* if chunk_len > end_in_page */
892 chunk_len = r; /* chunk_len -= end_in_page */
893
894 local[0].iov_len = remote[0].iov_len = chunk_len;
895 r = process_vm_readv(pid,
896 local, 1,
897 remote, 1,
898 /*flags:*/ 0
899 );
900 if (r < 0) {
901 if (errno == ENOSYS)
902 process_vm_readv_not_supported = 1;
Dmitry V. Levin9a71bcd2012-09-17 23:20:54 +0000903 else if (errno != EINVAL && errno != ESRCH)
904 /* EINVAL or ESRCH could be seen
905 * if process is gone, all the rest
906 * is strange and should be reported. */
907 perror_msg("%s", "process_vm_readv");
Denys Vlasenko3af224c2012-01-28 01:46:33 +0100908 goto vm_readv_didnt_work;
909 }
910 if (memchr(local[0].iov_base, '\0', r))
911 return 1;
912 local[0].iov_base += r;
913 remote[0].iov_base += r;
914 len -= r;
915 }
916 return 0;
917 }
918 vm_readv_didnt_work:
919
Denys Vlasenkoa47e6b92012-01-21 04:01:56 +0100920 started = 0;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000921 if (addr & (sizeof(long) - 1)) {
922 /* addr not a multiple of sizeof(long) */
923 n = addr - (addr & -sizeof(long)); /* residue */
924 addr &= -sizeof(long); /* residue */
Roland McGratheb9e2e82009-06-02 16:49:22 -0700925 errno = 0;
926 u.val = ptrace(PTRACE_PEEKDATA, pid, (char *)addr, 0);
927 if (errno) {
Roland McGratheb9e2e82009-06-02 16:49:22 -0700928 if (addr != 0 && errno != EIO && errno != ESRCH)
Denys Vlasenko4c65c442012-03-08 11:54:10 +0100929 perror_msg("umovestr: PTRACE_PEEKDATA pid:%d @0x%lx", pid, addr);
Roland McGratheb9e2e82009-06-02 16:49:22 -0700930 return -1;
931 }
Wichert Akkerman5daa0281999-03-15 19:49:42 +0000932 started = 1;
Denys Vlasenkoa47e6b92012-01-21 04:01:56 +0100933 m = MIN(sizeof(long) - n, len);
934 memcpy(laddr, &u.x[n], m);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000935 while (n & (sizeof(long) - 1))
936 if (u.x[n++] == '\0')
Denys Vlasenko6cecba52012-01-20 11:56:00 +0100937 return 1;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000938 addr += sizeof(long), laddr += m, len -= m;
939 }
940 while (len) {
Roland McGratheb9e2e82009-06-02 16:49:22 -0700941 errno = 0;
942 u.val = ptrace(PTRACE_PEEKDATA, pid, (char *)addr, 0);
943 if (errno) {
944 if (started && (errno==EPERM || errno==EIO)) {
945 /* Ran into 'end of memory' - stupid "printpath" */
946 return 0;
947 }
948 if (addr != 0 && errno != EIO && errno != ESRCH)
Denys Vlasenko4c65c442012-03-08 11:54:10 +0100949 perror_msg("umovestr: PTRACE_PEEKDATA pid:%d @0x%lx", pid, addr);
Roland McGratheb9e2e82009-06-02 16:49:22 -0700950 return -1;
951 }
Wichert Akkerman5daa0281999-03-15 19:49:42 +0000952 started = 1;
Denys Vlasenkoa47e6b92012-01-21 04:01:56 +0100953 m = MIN(sizeof(long), len);
954 memcpy(laddr, u.x, m);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000955 for (i = 0; i < sizeof(long); i++)
956 if (u.x[i] == '\0')
Denys Vlasenko6cecba52012-01-20 11:56:00 +0100957 return 1;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000958 addr += sizeof(long), laddr += m, len -= m;
959 }
John Hughesaa09c6b2001-05-15 14:53:43 +0000960 return 0;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000961}
962
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000963int
Denys Vlasenko12014262011-05-30 14:00:14 +0200964upeek(struct tcb *tcp, long off, long *res)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000965{
966 long val;
967
Roland McGratheb9e2e82009-06-02 16:49:22 -0700968 errno = 0;
Denys Vlasenko114aefd2012-03-08 12:13:44 +0100969 val = ptrace(PTRACE_PEEKUSER, tcp->pid, (char *) off, 0);
Roland McGratheb9e2e82009-06-02 16:49:22 -0700970 if (val == -1 && errno) {
971 if (errno != ESRCH) {
Denys Vlasenko4c65c442012-03-08 11:54:10 +0100972 perror_msg("upeek: PTRACE_PEEKUSER pid:%d @0x%lx)", tcp->pid, off);
Roland McGratheb9e2e82009-06-02 16:49:22 -0700973 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000974 return -1;
Roland McGratheb9e2e82009-06-02 16:49:22 -0700975 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000976 *res = val;
977 return 0;
978}
979
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000980void
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +0000981printcall(struct tcb *tcp)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000982{
Roland McGrath7a918832005-02-02 20:55:23 +0000983#define PRINTBADPC tprintf(sizeof(long) == 4 ? "[????????] " : \
984 sizeof(long) == 8 ? "[????????????????] " : \
985 NULL /* crash */)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000986
Denys Vlasenko2d1e90f2012-02-25 02:46:14 +0100987#if defined(I386)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000988 long eip;
989
Denys Vlasenko932fc7d2008-12-16 18:18:40 +0000990 if (upeek(tcp, 4*EIP, &eip) < 0) {
Roland McGrath7a918832005-02-02 20:55:23 +0000991 PRINTBADPC;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000992 return;
993 }
994 tprintf("[%08lx] ", eip);
Denys Vlasenko2d1e90f2012-02-25 02:46:14 +0100995#elif defined(S390) || defined(S390X)
Denys Vlasenkoadedb512008-12-30 18:47:55 +0000996 long psw;
Denys Vlasenkob63256e2011-06-07 12:13:24 +0200997 if (upeek(tcp, PT_PSWADDR, &psw) < 0) {
Denys Vlasenkoadedb512008-12-30 18:47:55 +0000998 PRINTBADPC;
999 return;
1000 }
Denys Vlasenko2d1e90f2012-02-25 02:46:14 +01001001# ifdef S390
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001002 tprintf("[%08lx] ", psw);
Denys Vlasenko2d1e90f2012-02-25 02:46:14 +01001003# elif S390X
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001004 tprintf("[%16lx] ", psw);
Denys Vlasenko2d1e90f2012-02-25 02:46:14 +01001005# endif
Roland McGratheac26fc2005-02-02 02:48:53 +00001006
H.J. Lu35be5812012-04-16 13:00:01 +02001007#elif defined(X86_64) || defined(X32)
Michal Ludvig0e035502002-09-23 15:41:01 +00001008 long rip;
1009
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001010 if (upeek(tcp, 8*RIP, &rip) < 0) {
Roland McGrath7a918832005-02-02 20:55:23 +00001011 PRINTBADPC;
Michal Ludvig0e035502002-09-23 15:41:01 +00001012 return;
1013 }
1014 tprintf("[%16lx] ", rip);
Denys Vlasenko2d1e90f2012-02-25 02:46:14 +01001015#elif defined(IA64)
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00001016 long ip;
1017
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001018 if (upeek(tcp, PT_B0, &ip) < 0) {
Roland McGrath7a918832005-02-02 20:55:23 +00001019 PRINTBADPC;
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00001020 return;
1021 }
1022 tprintf("[%08lx] ", ip);
Denys Vlasenko2d1e90f2012-02-25 02:46:14 +01001023#elif defined(POWERPC)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001024 long pc;
1025
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001026 if (upeek(tcp, sizeof(unsigned long)*PT_NIP, &pc) < 0) {
Andreas Schwabd69fa492010-07-12 21:39:57 +02001027 PRINTBADPC;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001028 return;
1029 }
Denys Vlasenko2d1e90f2012-02-25 02:46:14 +01001030# ifdef POWERPC64
Andreas Schwabd69fa492010-07-12 21:39:57 +02001031 tprintf("[%016lx] ", pc);
Denys Vlasenko2d1e90f2012-02-25 02:46:14 +01001032# else
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001033 tprintf("[%08lx] ", pc);
Denys Vlasenko2d1e90f2012-02-25 02:46:14 +01001034# endif
1035#elif defined(M68K)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001036 long pc;
1037
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001038 if (upeek(tcp, 4*PT_PC, &pc) < 0) {
Denys Vlasenko60fe8c12011-09-01 10:00:28 +02001039 tprints("[????????] ");
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001040 return;
1041 }
1042 tprintf("[%08lx] ", pc);
Denys Vlasenko2d1e90f2012-02-25 02:46:14 +01001043#elif defined(ALPHA)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001044 long pc;
1045
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001046 if (upeek(tcp, REG_PC, &pc) < 0) {
Denys Vlasenko60fe8c12011-09-01 10:00:28 +02001047 tprints("[????????????????] ");
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001048 return;
1049 }
1050 tprintf("[%08lx] ", pc);
Denys Vlasenko2d1e90f2012-02-25 02:46:14 +01001051#elif defined(SPARC) || defined(SPARC64)
Mike Frysinger8566c502009-10-12 11:05:14 -04001052 struct pt_regs regs;
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001053 if (ptrace(PTRACE_GETREGS, tcp->pid, (char *)&regs, 0) < 0) {
Roland McGrath7a918832005-02-02 20:55:23 +00001054 PRINTBADPC;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001055 return;
1056 }
Denys Vlasenko2d1e90f2012-02-25 02:46:14 +01001057# if defined(SPARC64)
Mike Frysinger8566c502009-10-12 11:05:14 -04001058 tprintf("[%08lx] ", regs.tpc);
Denys Vlasenko2d1e90f2012-02-25 02:46:14 +01001059# else
Mike Frysinger8566c502009-10-12 11:05:14 -04001060 tprintf("[%08lx] ", regs.pc);
Denys Vlasenko2d1e90f2012-02-25 02:46:14 +01001061# endif
1062#elif defined(HPPA)
Wichert Akkermanc1652e22001-03-27 12:17:16 +00001063 long pc;
1064
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001065 if (upeek(tcp, PT_IAOQ0, &pc) < 0) {
Denys Vlasenko60fe8c12011-09-01 10:00:28 +02001066 tprints("[????????] ");
Wichert Akkermanc1652e22001-03-27 12:17:16 +00001067 return;
1068 }
1069 tprintf("[%08lx] ", pc);
Denys Vlasenko2d1e90f2012-02-25 02:46:14 +01001070#elif defined(MIPS)
Wichert Akkerman75c422b2001-04-10 10:22:50 +00001071 long pc;
1072
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001073 if (upeek(tcp, REG_EPC, &pc) < 0) {
Denys Vlasenko60fe8c12011-09-01 10:00:28 +02001074 tprints("[????????] ");
Wichert Akkerman75c422b2001-04-10 10:22:50 +00001075 return;
1076 }
1077 tprintf("[%08lx] ", pc);
Denys Vlasenko2d1e90f2012-02-25 02:46:14 +01001078#elif defined(SH)
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001079 long pc;
Wichert Akkermanccef6372002-05-01 16:39:22 +00001080
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001081 if (upeek(tcp, 4*REG_PC, &pc) < 0) {
Denys Vlasenko60fe8c12011-09-01 10:00:28 +02001082 tprints("[????????] ");
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001083 return;
1084 }
1085 tprintf("[%08lx] ", pc);
Denys Vlasenko2d1e90f2012-02-25 02:46:14 +01001086#elif defined(SH64)
Roland McGrathe1e584b2003-06-02 19:18:58 +00001087 long pc;
1088
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001089 if (upeek(tcp, REG_PC, &pc) < 0) {
Denys Vlasenko60fe8c12011-09-01 10:00:28 +02001090 tprints("[????????????????] ");
Roland McGrathe1e584b2003-06-02 19:18:58 +00001091 return;
1092 }
1093 tprintf("[%08lx] ", pc);
Denys Vlasenko2d1e90f2012-02-25 02:46:14 +01001094#elif defined(ARM)
Roland McGrathef388682003-06-03 23:28:59 +00001095 long pc;
Roland McGrathe1e584b2003-06-02 19:18:58 +00001096
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001097 if (upeek(tcp, 4*15, &pc) < 0) {
Roland McGrath7a918832005-02-02 20:55:23 +00001098 PRINTBADPC;
Roland McGrathef388682003-06-03 23:28:59 +00001099 return;
1100 }
1101 tprintf("[%08lx] ", pc);
Denys Vlasenko2d1e90f2012-02-25 02:46:14 +01001102#elif defined(AVR32)
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00001103 long pc;
1104
1105 if (upeek(tcp, REG_PC, &pc) < 0) {
Denys Vlasenko60fe8c12011-09-01 10:00:28 +02001106 tprints("[????????] ");
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00001107 return;
1108 }
1109 tprintf("[%08lx] ", pc);
Denys Vlasenko2d1e90f2012-02-25 02:46:14 +01001110#elif defined(BFIN)
Dmitry V. Levin87ea1f42008-11-10 22:21:41 +00001111 long pc;
1112
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001113 if (upeek(tcp, PT_PC, &pc) < 0) {
Dmitry V. Levin87ea1f42008-11-10 22:21:41 +00001114 PRINTBADPC;
1115 return;
1116 }
1117 tprintf("[%08lx] ", pc);
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001118#elif defined(CRISV10)
1119 long pc;
1120
Edgar E. Iglesiaseeb9ce32009-10-05 14:41:02 +00001121 if (upeek(tcp, 4*PT_IRP, &pc) < 0) {
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001122 PRINTBADPC;
1123 return;
1124 }
1125 tprintf("[%08lx] ", pc);
1126#elif defined(CRISV32)
1127 long pc;
1128
Edgar E. Iglesiaseeb9ce32009-10-05 14:41:02 +00001129 if (upeek(tcp, 4*PT_ERP, &pc) < 0) {
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001130 PRINTBADPC;
1131 return;
1132 }
1133 tprintf("[%08lx] ", pc);
Denys Vlasenko2d1e90f2012-02-25 02:46:14 +01001134#endif /* architecture */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001135}
1136
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001137/*
1138 * These #if's are huge, please indent them correctly.
1139 * It's easy to get confused otherwise.
1140 */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001141
Denys Vlasenko2d1e90f2012-02-25 02:46:14 +01001142#include "syscall.h"
Roland McGrath3291ef22008-05-20 00:34:34 +00001143
Denys Vlasenko2d1e90f2012-02-25 02:46:14 +01001144#ifndef CLONE_PTRACE
1145# define CLONE_PTRACE 0x00002000
1146#endif
1147#ifndef CLONE_VFORK
1148# define CLONE_VFORK 0x00004000
1149#endif
1150#ifndef CLONE_VM
1151# define CLONE_VM 0x00000100
1152#endif
Roland McGrathd81f1d92003-01-09 06:53:34 +00001153
Denys Vlasenko2d1e90f2012-02-25 02:46:14 +01001154#ifdef IA64
Roland McGrathd81f1d92003-01-09 06:53:34 +00001155
1156typedef unsigned long *arg_setup_state;
1157
1158static int
1159arg_setup(struct tcb *tcp, arg_setup_state *state)
1160{
Jan Kratochvil1f942712008-08-06 21:38:52 +00001161 unsigned long cfm, sof, sol;
1162 long bsp;
Roland McGrathd81f1d92003-01-09 06:53:34 +00001163
Jan Kratochvil1f942712008-08-06 21:38:52 +00001164 if (ia32) {
1165 /* Satisfy a false GCC warning. */
1166 *state = NULL;
Roland McGrath08267b82004-02-20 22:56:43 +00001167 return 0;
Jan Kratochvil1f942712008-08-06 21:38:52 +00001168 }
Roland McGrath08267b82004-02-20 22:56:43 +00001169
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001170 if (upeek(tcp, PT_AR_BSP, &bsp) < 0)
Roland McGrathd81f1d92003-01-09 06:53:34 +00001171 return -1;
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001172 if (upeek(tcp, PT_CFM, (long *) &cfm) < 0)
Roland McGrathd81f1d92003-01-09 06:53:34 +00001173 return -1;
1174
1175 sof = (cfm >> 0) & 0x7f;
1176 sol = (cfm >> 7) & 0x7f;
Jan Kratochvil1f942712008-08-06 21:38:52 +00001177 bsp = (long) ia64_rse_skip_regs((unsigned long *) bsp, -sof + sol);
Roland McGrathd81f1d92003-01-09 06:53:34 +00001178
Jan Kratochvil1f942712008-08-06 21:38:52 +00001179 *state = (unsigned long *) bsp;
Roland McGrathd81f1d92003-01-09 06:53:34 +00001180 return 0;
1181}
1182
Denys Vlasenko2d1e90f2012-02-25 02:46:14 +01001183# define arg_finish_change(tcp, state) 0
Roland McGrathd81f1d92003-01-09 06:53:34 +00001184
Roland McGrathd81f1d92003-01-09 06:53:34 +00001185static int
Denys Vlasenko12014262011-05-30 14:00:14 +02001186get_arg0(struct tcb *tcp, arg_setup_state *state, long *valp)
Roland McGrathd81f1d92003-01-09 06:53:34 +00001187{
Roland McGrath08267b82004-02-20 22:56:43 +00001188 int ret;
1189
1190 if (ia32)
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001191 ret = upeek(tcp, PT_R11, valp);
Roland McGrath08267b82004-02-20 22:56:43 +00001192 else
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001193 ret = umoven(tcp,
Roland McGrath08267b82004-02-20 22:56:43 +00001194 (unsigned long) ia64_rse_skip_regs(*state, 0),
1195 sizeof(long), (void *) valp);
1196 return ret;
Roland McGrathd81f1d92003-01-09 06:53:34 +00001197}
1198
1199static int
Denys Vlasenko12014262011-05-30 14:00:14 +02001200get_arg1(struct tcb *tcp, arg_setup_state *state, long *valp)
Roland McGrathd81f1d92003-01-09 06:53:34 +00001201{
Roland McGrath08267b82004-02-20 22:56:43 +00001202 int ret;
1203
1204 if (ia32)
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001205 ret = upeek(tcp, PT_R9, valp);
Roland McGrath08267b82004-02-20 22:56:43 +00001206 else
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001207 ret = umoven(tcp,
Roland McGrath08267b82004-02-20 22:56:43 +00001208 (unsigned long) ia64_rse_skip_regs(*state, 1),
1209 sizeof(long), (void *) valp);
1210 return ret;
Roland McGrathd81f1d92003-01-09 06:53:34 +00001211}
Roland McGrathd81f1d92003-01-09 06:53:34 +00001212
1213static int
Denys Vlasenko12014262011-05-30 14:00:14 +02001214set_arg0(struct tcb *tcp, arg_setup_state *state, long val)
Roland McGrathd81f1d92003-01-09 06:53:34 +00001215{
Roland McGrath08267b82004-02-20 22:56:43 +00001216 int req = PTRACE_POKEDATA;
1217 void *ap;
1218
1219 if (ia32) {
1220 ap = (void *) (intptr_t) PT_R11; /* r11 == EBX */
1221 req = PTRACE_POKEUSER;
1222 } else
1223 ap = ia64_rse_skip_regs(*state, 0);
Roland McGratheb9e2e82009-06-02 16:49:22 -07001224 errno = 0;
1225 ptrace(req, tcp->pid, ap, val);
1226 return errno ? -1 : 0;
Roland McGrathd81f1d92003-01-09 06:53:34 +00001227}
1228
1229static int
Denys Vlasenko12014262011-05-30 14:00:14 +02001230set_arg1(struct tcb *tcp, arg_setup_state *state, long val)
Roland McGrathd81f1d92003-01-09 06:53:34 +00001231{
Roland McGrath08267b82004-02-20 22:56:43 +00001232 int req = PTRACE_POKEDATA;
1233 void *ap;
1234
1235 if (ia32) {
1236 ap = (void *) (intptr_t) PT_R9; /* r9 == ECX */
1237 req = PTRACE_POKEUSER;
1238 } else
1239 ap = ia64_rse_skip_regs(*state, 1);
Roland McGratheb9e2e82009-06-02 16:49:22 -07001240 errno = 0;
1241 ptrace(req, tcp->pid, ap, val);
1242 return errno ? -1 : 0;
Roland McGrathd81f1d92003-01-09 06:53:34 +00001243}
1244
Roland McGrathb659f872008-07-18 01:19:36 +00001245/* ia64 does not return the input arguments from functions (and syscalls)
1246 according to ia64 RSE (Register Stack Engine) behavior. */
1247
Denys Vlasenko2d1e90f2012-02-25 02:46:14 +01001248# define restore_arg0(tcp, state, val) ((void) (state), 0)
1249# define restore_arg1(tcp, state, val) ((void) (state), 0)
Roland McGrathb659f872008-07-18 01:19:36 +00001250
Denys Vlasenko2d1e90f2012-02-25 02:46:14 +01001251#elif defined(SPARC) || defined(SPARC64)
Roland McGrathd81f1d92003-01-09 06:53:34 +00001252
Mike Frysinger8566c502009-10-12 11:05:14 -04001253typedef struct pt_regs arg_setup_state;
Roland McGrathd81f1d92003-01-09 06:53:34 +00001254
Denys Vlasenko2d1e90f2012-02-25 02:46:14 +01001255# define arg_setup(tcp, state) \
1256 (ptrace(PTRACE_GETREGS, (tcp)->pid, (char *) (state), 0))
1257# define arg_finish_change(tcp, state) \
1258 (ptrace(PTRACE_SETREGS, (tcp)->pid, (char *) (state), 0))
Roland McGrathd81f1d92003-01-09 06:53:34 +00001259
Denys Vlasenko2d1e90f2012-02-25 02:46:14 +01001260# define get_arg0(tcp, state, valp) (*(valp) = (state)->u_regs[U_REG_O0], 0)
1261# define get_arg1(tcp, state, valp) (*(valp) = (state)->u_regs[U_REG_O1], 0)
1262# define set_arg0(tcp, state, val) ((state)->u_regs[U_REG_O0] = (val), 0)
1263# define set_arg1(tcp, state, val) ((state)->u_regs[U_REG_O1] = (val), 0)
1264# define restore_arg0(tcp, state, val) 0
Roland McGrathd81f1d92003-01-09 06:53:34 +00001265
Denys Vlasenko2d1e90f2012-02-25 02:46:14 +01001266#else /* other architectures */
Roland McGrathd81f1d92003-01-09 06:53:34 +00001267
Denys Vlasenko2d1e90f2012-02-25 02:46:14 +01001268# if defined S390 || defined S390X
Roland McGrath7b308222003-01-20 09:04:36 +00001269/* Note: this is only true for the `clone' system call, which handles
1270 arguments specially. We could as well say that its first two arguments
1271 are swapped relative to other architectures, but that would just be
1272 another #ifdef in the calls. */
Denys Vlasenko2d1e90f2012-02-25 02:46:14 +01001273# define arg0_offset PT_GPR3
1274# define arg1_offset PT_ORIGGPR2
1275# define restore_arg0(tcp, state, val) ((void) (state), 0)
1276# define restore_arg1(tcp, state, val) ((void) (state), 0)
1277# define arg0_index 1
1278# define arg1_index 0
1279# elif defined(ALPHA) || defined(MIPS)
1280# define arg0_offset REG_A0
1281# define arg1_offset (REG_A0+1)
1282# elif defined(AVR32)
1283# define arg0_offset (REG_R12)
1284# define arg1_offset (REG_R11)
1285# elif defined(POWERPC)
1286# define arg0_offset (sizeof(unsigned long)*PT_R3)
1287# define arg1_offset (sizeof(unsigned long)*PT_R4)
1288# define restore_arg0(tcp, state, val) ((void) (state), 0)
1289# elif defined(HPPA)
1290# define arg0_offset PT_GR26
1291# define arg1_offset (PT_GR26-4)
H.J. Lu35be5812012-04-16 13:00:01 +02001292# elif defined(X86_64) || defined(X32)
Denys Vlasenko2d1e90f2012-02-25 02:46:14 +01001293# define arg0_offset ((long)(8*(current_personality ? RBX : RDI)))
1294# define arg1_offset ((long)(8*(current_personality ? RCX : RSI)))
1295# elif defined(SH)
1296# define arg0_offset (4*(REG_REG0+4))
1297# define arg1_offset (4*(REG_REG0+5))
1298# elif defined(SH64)
1299 /* ABI defines arg0 & 1 in r2 & r3 */
1300# define arg0_offset (REG_OFFSET+16)
1301# define arg1_offset (REG_OFFSET+24)
1302# define restore_arg0(tcp, state, val) 0
1303# elif defined CRISV10 || defined CRISV32
1304# define arg0_offset (4*PT_R11)
1305# define arg1_offset (4*PT_ORIG_R10)
1306# define restore_arg0(tcp, state, val) 0
1307# define restore_arg1(tcp, state, val) 0
1308# define arg0_index 1
1309# define arg1_index 0
1310# else
1311# define arg0_offset 0
1312# define arg1_offset 4
1313# if defined ARM
1314# define restore_arg0(tcp, state, val) 0
1315# endif
1316# endif
Roland McGrathd81f1d92003-01-09 06:53:34 +00001317
1318typedef int arg_setup_state;
1319
Denys Vlasenko2d1e90f2012-02-25 02:46:14 +01001320# define arg_setup(tcp, state) (0)
1321# define arg_finish_change(tcp, state) 0
1322# define get_arg0(tcp, cookie, valp) (upeek((tcp), arg0_offset, (valp)))
1323# define get_arg1(tcp, cookie, valp) (upeek((tcp), arg1_offset, (valp)))
Roland McGrathd81f1d92003-01-09 06:53:34 +00001324
1325static int
Denys Vlasenko12014262011-05-30 14:00:14 +02001326set_arg0(struct tcb *tcp, void *cookie, long val)
Roland McGrathd81f1d92003-01-09 06:53:34 +00001327{
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001328 return ptrace(PTRACE_POKEUSER, tcp->pid, (char*)arg0_offset, val);
Roland McGrathd81f1d92003-01-09 06:53:34 +00001329}
1330
1331static int
Denys Vlasenko12014262011-05-30 14:00:14 +02001332set_arg1(struct tcb *tcp, void *cookie, long val)
Roland McGrathd81f1d92003-01-09 06:53:34 +00001333{
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001334 return ptrace(PTRACE_POKEUSER, tcp->pid, (char*)arg1_offset, val);
Roland McGrathd81f1d92003-01-09 06:53:34 +00001335}
1336
Denys Vlasenko2d1e90f2012-02-25 02:46:14 +01001337#endif /* architectures */
Roland McGrathd81f1d92003-01-09 06:53:34 +00001338
Denys Vlasenko2d1e90f2012-02-25 02:46:14 +01001339#ifndef restore_arg0
1340# define restore_arg0(tcp, state, val) set_arg0((tcp), (state), (val))
1341#endif
1342#ifndef restore_arg1
1343# define restore_arg1(tcp, state, val) set_arg1((tcp), (state), (val))
1344#endif
Roland McGrathd81f1d92003-01-09 06:53:34 +00001345
Denys Vlasenko2d1e90f2012-02-25 02:46:14 +01001346#ifndef arg0_index
1347# define arg0_index 0
1348# define arg1_index 1
1349#endif
Roland McGrath90d0afd2004-03-01 21:05:16 +00001350
James Hogan05eb9052012-11-29 17:37:37 +00001351static int
1352change_syscall(struct tcb *tcp, arg_setup_state *state, int new)
1353{
1354#if defined(I386)
1355 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(ORIG_EAX * 4), new) < 0)
1356 return -1;
1357 return 0;
1358#elif defined(X86_64) || defined(X32)
1359 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(ORIG_RAX * 8), new) < 0)
1360 return -1;
1361 return 0;
1362#elif defined(POWERPC)
1363 if (ptrace(PTRACE_POKEUSER, tcp->pid,
1364 (char*)(sizeof(unsigned long)*PT_R0), new) < 0)
1365 return -1;
1366 return 0;
1367#elif defined(S390) || defined(S390X)
1368 /* s390 linux after 2.4.7 has a hook in entry.S to allow this */
1369 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(PT_GPR2), new) < 0)
1370 return -1;
1371 return 0;
1372#elif defined(M68K)
1373 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(4*PT_ORIG_D0), new) < 0)
1374 return -1;
1375 return 0;
1376#elif defined(SPARC) || defined(SPARC64)
1377 state->u_regs[U_REG_G1] = new;
1378 return 0;
1379#elif defined(MIPS)
1380 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(REG_V0), new) < 0)
1381 return -1;
1382 return 0;
1383#elif defined(ALPHA)
1384 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(REG_A3), new) < 0)
1385 return -1;
1386 return 0;
1387#elif defined(AVR32)
1388 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(REG_R8), new) < 0)
1389 return -1;
1390 return 0;
1391#elif defined(BFIN)
1392 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(REG_P0), new) < 0)
1393 return -1;
1394 return 0;
1395#elif defined(IA64)
1396 if (ia32) {
1397 switch (new) {
1398 case 2:
1399 break; /* x86 SYS_fork */
1400 case SYS_clone:
1401 new = 120;
1402 break;
1403 default:
1404 fprintf(stderr, "%s: unexpected syscall %d\n",
1405 __FUNCTION__, new);
1406 return -1;
1407 }
1408 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(PT_R1), new) < 0)
1409 return -1;
1410 } else if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(PT_R15), new) < 0)
1411 return -1;
1412 return 0;
1413#elif defined(HPPA)
1414 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(PT_GR20), new) < 0)
1415 return -1;
1416 return 0;
1417#elif defined(SH)
1418 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(4*(REG_REG0+3)), new) < 0)
1419 return -1;
1420 return 0;
1421#elif defined(SH64)
1422 /* Top half of reg encodes the no. of args n as 0x1n.
1423 Assume 0 args as kernel never actually checks... */
1424 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(REG_SYSCALL),
1425 0x100000 | new) < 0)
1426 return -1;
1427 return 0;
1428#elif defined(CRISV10) || defined(CRISV32)
1429 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(4*PT_R9), new) < 0)
1430 return -1;
1431 return 0;
1432#elif defined(ARM)
1433 /* Some kernels support this, some (pre-2.6.16 or so) don't. */
1434# ifndef PTRACE_SET_SYSCALL
1435# define PTRACE_SET_SYSCALL 23
1436# endif
1437 if (ptrace(PTRACE_SET_SYSCALL, tcp->pid, 0, new & 0xffff) != 0)
1438 return -1;
1439 return 0;
1440#elif defined(TILE)
1441 if (ptrace(PTRACE_POKEUSER, tcp->pid,
1442 (char*)PTREGS_OFFSET_REG(0),
1443 new) != 0)
1444 return -1;
1445 return 0;
1446#elif defined(MICROBLAZE)
1447 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(PT_GPR(0)), new) < 0)
1448 return -1;
1449 return 0;
1450#else
1451#warning Do not know how to handle change_syscall for this architecture
1452#endif /* architecture */
1453 return -1;
1454}
1455
Roland McGrathd81f1d92003-01-09 06:53:34 +00001456int
Denys Vlasenko418d66a2009-01-17 01:52:54 +00001457setbpt(struct tcb *tcp)
Roland McGrathd81f1d92003-01-09 06:53:34 +00001458{
Roland McGrath3291ef22008-05-20 00:34:34 +00001459 static int clone_scno[SUPPORTED_PERSONALITIES] = { SYS_clone };
Roland McGrathd81f1d92003-01-09 06:53:34 +00001460 arg_setup_state state;
1461
1462 if (tcp->flags & TCB_BPTSET) {
1463 fprintf(stderr, "PANIC: TCB already set in pid %u\n", tcp->pid);
1464 return -1;
1465 }
1466
Roland McGrath3291ef22008-05-20 00:34:34 +00001467 /*
1468 * It's a silly kludge to initialize this with a search at runtime.
1469 * But it's better than maintaining another magic thing in the
1470 * godforsaken tables.
1471 */
1472 if (clone_scno[current_personality] == 0) {
1473 int i;
1474 for (i = 0; i < nsyscalls; ++i)
1475 if (sysent[i].sys_func == sys_clone) {
1476 clone_scno[current_personality] = i;
1477 break;
1478 }
1479 }
1480
Dmitry V. Levin0c661512012-02-20 21:17:58 +00001481 if (sysent[tcp->scno].sys_func == sys_fork ||
1482 sysent[tcp->scno].sys_func == sys_vfork) {
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001483 if (arg_setup(tcp, &state) < 0
1484 || get_arg0(tcp, &state, &tcp->inst[0]) < 0
1485 || get_arg1(tcp, &state, &tcp->inst[1]) < 0
James Hogan05eb9052012-11-29 17:37:37 +00001486 || change_syscall(tcp, &state,
1487 clone_scno[current_personality]) < 0
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001488 || set_arg0(tcp, &state, CLONE_PTRACE|SIGCHLD) < 0
1489 || set_arg1(tcp, &state, 0) < 0
1490 || arg_finish_change(tcp, &state) < 0)
Roland McGrathd81f1d92003-01-09 06:53:34 +00001491 return -1;
Roland McGrathc9dc3c12004-03-01 20:57:09 +00001492 tcp->u_arg[arg0_index] = CLONE_PTRACE|SIGCHLD;
1493 tcp->u_arg[arg1_index] = 0;
Roland McGrathd81f1d92003-01-09 06:53:34 +00001494 tcp->flags |= TCB_BPTSET;
1495 return 0;
Dmitry V. Levin0c661512012-02-20 21:17:58 +00001496 }
Roland McGrathd81f1d92003-01-09 06:53:34 +00001497
Dmitry V. Levin0c661512012-02-20 21:17:58 +00001498 if (sysent[tcp->scno].sys_func == sys_clone) {
Jan Kratochvil8fc95752008-08-06 21:43:35 +00001499 /* ia64 calls directly `clone (CLONE_VFORK | CLONE_VM)'
Dmitry V. Levin0c661512012-02-20 21:17:58 +00001500 contrary to x86 vfork above. Even on x86 we turn the
Jan Kratochvil8fc95752008-08-06 21:43:35 +00001501 vfork semantics into plain fork - each application must not
1502 depend on the vfork specifics according to POSIX. We would
1503 hang waiting for the parent resume otherwise. We need to
1504 clear also CLONE_VM but only in the CLONE_VFORK case as
1505 otherwise we would break pthread_create. */
1506
Denys Vlasenkoc133bf02011-06-23 21:57:54 +02001507 long new_arg0 = (tcp->u_arg[arg0_index] | CLONE_PTRACE);
1508 if (new_arg0 & CLONE_VFORK)
1509 new_arg0 &= ~(unsigned long)(CLONE_VFORK | CLONE_VM);
1510 if (arg_setup(tcp, &state) < 0
1511 || set_arg0(tcp, &state, new_arg0) < 0
1512 || arg_finish_change(tcp, &state) < 0)
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00001513 return -1;
Roland McGrathc9dc3c12004-03-01 20:57:09 +00001514 tcp->inst[0] = tcp->u_arg[arg0_index];
1515 tcp->inst[1] = tcp->u_arg[arg1_index];
Denys Vlasenko55980f52012-05-14 16:40:28 +02001516 tcp->flags |= TCB_BPTSET;
Roland McGrathd81f1d92003-01-09 06:53:34 +00001517 return 0;
Roland McGrathd81f1d92003-01-09 06:53:34 +00001518 }
1519
Dmitry V. Levin0c661512012-02-20 21:17:58 +00001520 fprintf(stderr, "PANIC: setbpt for syscall %ld on %u???\n",
1521 tcp->scno, tcp->pid);
Roland McGrathd81f1d92003-01-09 06:53:34 +00001522 return -1;
1523}
1524
1525int
Denys Vlasenko12014262011-05-30 14:00:14 +02001526clearbpt(struct tcb *tcp)
Roland McGrathd81f1d92003-01-09 06:53:34 +00001527{
1528 arg_setup_state state;
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001529 if (arg_setup(tcp, &state) < 0
James Hogan05eb9052012-11-29 17:37:37 +00001530 || change_syscall(tcp, &state, tcp->scno) < 0
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001531 || restore_arg0(tcp, &state, tcp->inst[0]) < 0
1532 || restore_arg1(tcp, &state, tcp->inst[1]) < 0
1533 || arg_finish_change(tcp, &state))
Denys Vlasenkoc133bf02011-06-23 21:57:54 +02001534 if (errno != ESRCH)
1535 return -1;
Roland McGrathd81f1d92003-01-09 06:53:34 +00001536 tcp->flags &= ~TCB_BPTSET;
1537 return 0;
1538}