blob: 8254677f29732fc6a01a7d9e69e0e70ab760c8ed [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
Denys Vlasenko84703742012-02-25 02:38:52 +010042#if __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 Vlasenko081533c2012-03-17 02:17:51 +01001154static int
1155change_syscall(struct tcb *tcp, int new)
1156{
1157#if defined(I386)
1158 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(ORIG_EAX * 4), new) < 0)
1159 return -1;
1160 return 0;
H.J. Lu35be5812012-04-16 13:00:01 +02001161#elif defined(X86_64) || defined(X32)
Denys Vlasenko081533c2012-03-17 02:17:51 +01001162 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(ORIG_RAX * 8), new) < 0)
1163 return -1;
1164 return 0;
1165#elif defined(POWERPC)
1166 if (ptrace(PTRACE_POKEUSER, tcp->pid,
1167 (char*)(sizeof(unsigned long)*PT_R0), new) < 0)
1168 return -1;
1169 return 0;
1170#elif defined(S390) || defined(S390X)
1171 /* s390 linux after 2.4.7 has a hook in entry.S to allow this */
1172 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(PT_GPR2), new) < 0)
1173 return -1;
1174 return 0;
1175#elif defined(M68K)
1176 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(4*PT_ORIG_D0), new) < 0)
1177 return -1;
1178 return 0;
1179#elif defined(SPARC) || defined(SPARC64)
1180 struct pt_regs regs;
1181 if (ptrace(PTRACE_GETREGS, tcp->pid, (char*)&regs, 0) < 0)
1182 return -1;
1183 regs.u_regs[U_REG_G1] = new;
1184 if (ptrace(PTRACE_SETREGS, tcp->pid, (char*)&regs, 0) < 0)
1185 return -1;
1186 return 0;
1187#elif defined(MIPS)
1188 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(REG_V0), new) < 0)
1189 return -1;
1190 return 0;
1191#elif defined(ALPHA)
1192 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(REG_A3), new) < 0)
1193 return -1;
1194 return 0;
1195#elif defined(AVR32)
1196 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(REG_R8), new) < 0)
1197 return -1;
1198 return 0;
1199#elif defined(BFIN)
1200 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(REG_P0), new) < 0)
1201 return -1;
1202 return 0;
1203#elif defined(IA64)
1204 if (ia32) {
1205 switch (new) {
1206 case 2:
1207 break; /* x86 SYS_fork */
1208 case SYS_clone:
1209 new = 120;
1210 break;
1211 default:
1212 fprintf(stderr, "%s: unexpected syscall %d\n",
1213 __FUNCTION__, new);
1214 return -1;
1215 }
1216 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(PT_R1), new) < 0)
1217 return -1;
1218 } else if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(PT_R15), new) < 0)
1219 return -1;
1220 return 0;
1221#elif defined(HPPA)
1222 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(PT_GR20), new) < 0)
1223 return -1;
1224 return 0;
1225#elif defined(SH)
1226 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(4*(REG_REG0+3)), new) < 0)
1227 return -1;
1228 return 0;
1229#elif defined(SH64)
1230 /* Top half of reg encodes the no. of args n as 0x1n.
1231 Assume 0 args as kernel never actually checks... */
1232 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(REG_SYSCALL),
1233 0x100000 | new) < 0)
1234 return -1;
1235 return 0;
1236#elif defined(CRISV10) || defined(CRISV32)
1237 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(4*PT_R9), new) < 0)
1238 return -1;
1239 return 0;
1240#elif defined(ARM)
1241 /* Some kernels support this, some (pre-2.6.16 or so) don't. */
1242# ifndef PTRACE_SET_SYSCALL
1243# define PTRACE_SET_SYSCALL 23
1244# endif
1245 if (ptrace(PTRACE_SET_SYSCALL, tcp->pid, 0, new & 0xffff) != 0)
1246 return -1;
1247 return 0;
1248#elif defined(TILE)
1249 if (ptrace(PTRACE_POKEUSER, tcp->pid,
1250 (char*)PTREGS_OFFSET_REG(0),
1251 new) != 0)
1252 return -1;
1253 return 0;
1254#elif defined(MICROBLAZE)
1255 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(PT_GPR(0)), new) < 0)
1256 return -1;
1257 return 0;
1258#else
1259#warning Do not know how to handle change_syscall for this architecture
1260#endif /* architecture */
1261 return -1;
1262}
1263
Denys Vlasenko2d1e90f2012-02-25 02:46:14 +01001264#ifdef IA64
Roland McGrathd81f1d92003-01-09 06:53:34 +00001265
1266typedef unsigned long *arg_setup_state;
1267
1268static int
1269arg_setup(struct tcb *tcp, arg_setup_state *state)
1270{
Jan Kratochvil1f942712008-08-06 21:38:52 +00001271 unsigned long cfm, sof, sol;
1272 long bsp;
Roland McGrathd81f1d92003-01-09 06:53:34 +00001273
Jan Kratochvil1f942712008-08-06 21:38:52 +00001274 if (ia32) {
1275 /* Satisfy a false GCC warning. */
1276 *state = NULL;
Roland McGrath08267b82004-02-20 22:56:43 +00001277 return 0;
Jan Kratochvil1f942712008-08-06 21:38:52 +00001278 }
Roland McGrath08267b82004-02-20 22:56:43 +00001279
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001280 if (upeek(tcp, PT_AR_BSP, &bsp) < 0)
Roland McGrathd81f1d92003-01-09 06:53:34 +00001281 return -1;
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001282 if (upeek(tcp, PT_CFM, (long *) &cfm) < 0)
Roland McGrathd81f1d92003-01-09 06:53:34 +00001283 return -1;
1284
1285 sof = (cfm >> 0) & 0x7f;
1286 sol = (cfm >> 7) & 0x7f;
Jan Kratochvil1f942712008-08-06 21:38:52 +00001287 bsp = (long) ia64_rse_skip_regs((unsigned long *) bsp, -sof + sol);
Roland McGrathd81f1d92003-01-09 06:53:34 +00001288
Jan Kratochvil1f942712008-08-06 21:38:52 +00001289 *state = (unsigned long *) bsp;
Roland McGrathd81f1d92003-01-09 06:53:34 +00001290 return 0;
1291}
1292
Denys Vlasenko2d1e90f2012-02-25 02:46:14 +01001293# define arg_finish_change(tcp, state) 0
Roland McGrathd81f1d92003-01-09 06:53:34 +00001294
Roland McGrathd81f1d92003-01-09 06:53:34 +00001295static int
Denys Vlasenko12014262011-05-30 14:00:14 +02001296get_arg0(struct tcb *tcp, arg_setup_state *state, long *valp)
Roland McGrathd81f1d92003-01-09 06:53:34 +00001297{
Roland McGrath08267b82004-02-20 22:56:43 +00001298 int ret;
1299
1300 if (ia32)
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001301 ret = upeek(tcp, PT_R11, valp);
Roland McGrath08267b82004-02-20 22:56:43 +00001302 else
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001303 ret = umoven(tcp,
Roland McGrath08267b82004-02-20 22:56:43 +00001304 (unsigned long) ia64_rse_skip_regs(*state, 0),
1305 sizeof(long), (void *) valp);
1306 return ret;
Roland McGrathd81f1d92003-01-09 06:53:34 +00001307}
1308
1309static int
Denys Vlasenko12014262011-05-30 14:00:14 +02001310get_arg1(struct tcb *tcp, arg_setup_state *state, long *valp)
Roland McGrathd81f1d92003-01-09 06:53:34 +00001311{
Roland McGrath08267b82004-02-20 22:56:43 +00001312 int ret;
1313
1314 if (ia32)
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001315 ret = upeek(tcp, PT_R9, valp);
Roland McGrath08267b82004-02-20 22:56:43 +00001316 else
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001317 ret = umoven(tcp,
Roland McGrath08267b82004-02-20 22:56:43 +00001318 (unsigned long) ia64_rse_skip_regs(*state, 1),
1319 sizeof(long), (void *) valp);
1320 return ret;
Roland McGrathd81f1d92003-01-09 06:53:34 +00001321}
Roland McGrathd81f1d92003-01-09 06:53:34 +00001322
1323static int
Denys Vlasenko12014262011-05-30 14:00:14 +02001324set_arg0(struct tcb *tcp, arg_setup_state *state, long val)
Roland McGrathd81f1d92003-01-09 06:53:34 +00001325{
Roland McGrath08267b82004-02-20 22:56:43 +00001326 int req = PTRACE_POKEDATA;
1327 void *ap;
1328
1329 if (ia32) {
1330 ap = (void *) (intptr_t) PT_R11; /* r11 == EBX */
1331 req = PTRACE_POKEUSER;
1332 } else
1333 ap = ia64_rse_skip_regs(*state, 0);
Roland McGratheb9e2e82009-06-02 16:49:22 -07001334 errno = 0;
1335 ptrace(req, tcp->pid, ap, val);
1336 return errno ? -1 : 0;
Roland McGrathd81f1d92003-01-09 06:53:34 +00001337}
1338
1339static int
Denys Vlasenko12014262011-05-30 14:00:14 +02001340set_arg1(struct tcb *tcp, arg_setup_state *state, long val)
Roland McGrathd81f1d92003-01-09 06:53:34 +00001341{
Roland McGrath08267b82004-02-20 22:56:43 +00001342 int req = PTRACE_POKEDATA;
1343 void *ap;
1344
1345 if (ia32) {
1346 ap = (void *) (intptr_t) PT_R9; /* r9 == ECX */
1347 req = PTRACE_POKEUSER;
1348 } else
1349 ap = ia64_rse_skip_regs(*state, 1);
Roland McGratheb9e2e82009-06-02 16:49:22 -07001350 errno = 0;
1351 ptrace(req, tcp->pid, ap, val);
1352 return errno ? -1 : 0;
Roland McGrathd81f1d92003-01-09 06:53:34 +00001353}
1354
Roland McGrathb659f872008-07-18 01:19:36 +00001355/* ia64 does not return the input arguments from functions (and syscalls)
1356 according to ia64 RSE (Register Stack Engine) behavior. */
1357
Denys Vlasenko2d1e90f2012-02-25 02:46:14 +01001358# define restore_arg0(tcp, state, val) ((void) (state), 0)
1359# define restore_arg1(tcp, state, val) ((void) (state), 0)
Roland McGrathb659f872008-07-18 01:19:36 +00001360
Denys Vlasenko2d1e90f2012-02-25 02:46:14 +01001361#elif defined(SPARC) || defined(SPARC64)
Roland McGrathd81f1d92003-01-09 06:53:34 +00001362
Mike Frysinger8566c502009-10-12 11:05:14 -04001363typedef struct pt_regs arg_setup_state;
Roland McGrathd81f1d92003-01-09 06:53:34 +00001364
Denys Vlasenko2d1e90f2012-02-25 02:46:14 +01001365# define arg_setup(tcp, state) \
1366 (ptrace(PTRACE_GETREGS, (tcp)->pid, (char *) (state), 0))
1367# define arg_finish_change(tcp, state) \
1368 (ptrace(PTRACE_SETREGS, (tcp)->pid, (char *) (state), 0))
Roland McGrathd81f1d92003-01-09 06:53:34 +00001369
Denys Vlasenko2d1e90f2012-02-25 02:46:14 +01001370# define get_arg0(tcp, state, valp) (*(valp) = (state)->u_regs[U_REG_O0], 0)
1371# define get_arg1(tcp, state, valp) (*(valp) = (state)->u_regs[U_REG_O1], 0)
1372# define set_arg0(tcp, state, val) ((state)->u_regs[U_REG_O0] = (val), 0)
1373# define set_arg1(tcp, state, val) ((state)->u_regs[U_REG_O1] = (val), 0)
1374# define restore_arg0(tcp, state, val) 0
Roland McGrathd81f1d92003-01-09 06:53:34 +00001375
Denys Vlasenko2d1e90f2012-02-25 02:46:14 +01001376#else /* other architectures */
Roland McGrathd81f1d92003-01-09 06:53:34 +00001377
Denys Vlasenko2d1e90f2012-02-25 02:46:14 +01001378# if defined S390 || defined S390X
Roland McGrath7b308222003-01-20 09:04:36 +00001379/* Note: this is only true for the `clone' system call, which handles
1380 arguments specially. We could as well say that its first two arguments
1381 are swapped relative to other architectures, but that would just be
1382 another #ifdef in the calls. */
Denys Vlasenko2d1e90f2012-02-25 02:46:14 +01001383# define arg0_offset PT_GPR3
1384# define arg1_offset PT_ORIGGPR2
1385# define restore_arg0(tcp, state, val) ((void) (state), 0)
1386# define restore_arg1(tcp, state, val) ((void) (state), 0)
1387# define arg0_index 1
1388# define arg1_index 0
1389# elif defined(ALPHA) || defined(MIPS)
1390# define arg0_offset REG_A0
1391# define arg1_offset (REG_A0+1)
1392# elif defined(AVR32)
1393# define arg0_offset (REG_R12)
1394# define arg1_offset (REG_R11)
1395# elif defined(POWERPC)
1396# define arg0_offset (sizeof(unsigned long)*PT_R3)
1397# define arg1_offset (sizeof(unsigned long)*PT_R4)
1398# define restore_arg0(tcp, state, val) ((void) (state), 0)
1399# elif defined(HPPA)
1400# define arg0_offset PT_GR26
1401# define arg1_offset (PT_GR26-4)
H.J. Lu35be5812012-04-16 13:00:01 +02001402# elif defined(X86_64) || defined(X32)
Denys Vlasenko2d1e90f2012-02-25 02:46:14 +01001403# define arg0_offset ((long)(8*(current_personality ? RBX : RDI)))
1404# define arg1_offset ((long)(8*(current_personality ? RCX : RSI)))
1405# elif defined(SH)
1406# define arg0_offset (4*(REG_REG0+4))
1407# define arg1_offset (4*(REG_REG0+5))
1408# elif defined(SH64)
1409 /* ABI defines arg0 & 1 in r2 & r3 */
1410# define arg0_offset (REG_OFFSET+16)
1411# define arg1_offset (REG_OFFSET+24)
1412# define restore_arg0(tcp, state, val) 0
1413# elif defined CRISV10 || defined CRISV32
1414# define arg0_offset (4*PT_R11)
1415# define arg1_offset (4*PT_ORIG_R10)
1416# define restore_arg0(tcp, state, val) 0
1417# define restore_arg1(tcp, state, val) 0
1418# define arg0_index 1
1419# define arg1_index 0
1420# else
1421# define arg0_offset 0
1422# define arg1_offset 4
1423# if defined ARM
1424# define restore_arg0(tcp, state, val) 0
1425# endif
1426# endif
Roland McGrathd81f1d92003-01-09 06:53:34 +00001427
1428typedef int arg_setup_state;
1429
Denys Vlasenko2d1e90f2012-02-25 02:46:14 +01001430# define arg_setup(tcp, state) (0)
1431# define arg_finish_change(tcp, state) 0
1432# define get_arg0(tcp, cookie, valp) (upeek((tcp), arg0_offset, (valp)))
1433# define get_arg1(tcp, cookie, valp) (upeek((tcp), arg1_offset, (valp)))
Roland McGrathd81f1d92003-01-09 06:53:34 +00001434
1435static int
Denys Vlasenko12014262011-05-30 14:00:14 +02001436set_arg0(struct tcb *tcp, void *cookie, long val)
Roland McGrathd81f1d92003-01-09 06:53:34 +00001437{
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001438 return ptrace(PTRACE_POKEUSER, tcp->pid, (char*)arg0_offset, val);
Roland McGrathd81f1d92003-01-09 06:53:34 +00001439}
1440
1441static int
Denys Vlasenko12014262011-05-30 14:00:14 +02001442set_arg1(struct tcb *tcp, void *cookie, long val)
Roland McGrathd81f1d92003-01-09 06:53:34 +00001443{
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001444 return ptrace(PTRACE_POKEUSER, tcp->pid, (char*)arg1_offset, val);
Roland McGrathd81f1d92003-01-09 06:53:34 +00001445}
1446
Denys Vlasenko2d1e90f2012-02-25 02:46:14 +01001447#endif /* architectures */
Roland McGrathd81f1d92003-01-09 06:53:34 +00001448
Denys Vlasenko2d1e90f2012-02-25 02:46:14 +01001449#ifndef restore_arg0
1450# define restore_arg0(tcp, state, val) set_arg0((tcp), (state), (val))
1451#endif
1452#ifndef restore_arg1
1453# define restore_arg1(tcp, state, val) set_arg1((tcp), (state), (val))
1454#endif
Roland McGrathd81f1d92003-01-09 06:53:34 +00001455
Denys Vlasenko2d1e90f2012-02-25 02:46:14 +01001456#ifndef arg0_index
1457# define arg0_index 0
1458# define arg1_index 1
1459#endif
Roland McGrath90d0afd2004-03-01 21:05:16 +00001460
Roland McGrathd81f1d92003-01-09 06:53:34 +00001461int
Denys Vlasenko418d66a2009-01-17 01:52:54 +00001462setbpt(struct tcb *tcp)
Roland McGrathd81f1d92003-01-09 06:53:34 +00001463{
Roland McGrath3291ef22008-05-20 00:34:34 +00001464 static int clone_scno[SUPPORTED_PERSONALITIES] = { SYS_clone };
Roland McGrathd81f1d92003-01-09 06:53:34 +00001465 arg_setup_state state;
1466
1467 if (tcp->flags & TCB_BPTSET) {
1468 fprintf(stderr, "PANIC: TCB already set in pid %u\n", tcp->pid);
1469 return -1;
1470 }
1471
Roland McGrath3291ef22008-05-20 00:34:34 +00001472 /*
1473 * It's a silly kludge to initialize this with a search at runtime.
1474 * But it's better than maintaining another magic thing in the
1475 * godforsaken tables.
1476 */
1477 if (clone_scno[current_personality] == 0) {
1478 int i;
1479 for (i = 0; i < nsyscalls; ++i)
1480 if (sysent[i].sys_func == sys_clone) {
1481 clone_scno[current_personality] = i;
1482 break;
1483 }
1484 }
1485
Dmitry V. Levin0c661512012-02-20 21:17:58 +00001486 if (sysent[tcp->scno].sys_func == sys_fork ||
1487 sysent[tcp->scno].sys_func == sys_vfork) {
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001488 if (arg_setup(tcp, &state) < 0
1489 || get_arg0(tcp, &state, &tcp->inst[0]) < 0
1490 || get_arg1(tcp, &state, &tcp->inst[1]) < 0
Roland McGrath3291ef22008-05-20 00:34:34 +00001491 || change_syscall(tcp, clone_scno[current_personality]) < 0
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001492 || set_arg0(tcp, &state, CLONE_PTRACE|SIGCHLD) < 0
1493 || set_arg1(tcp, &state, 0) < 0
1494 || arg_finish_change(tcp, &state) < 0)
Roland McGrathd81f1d92003-01-09 06:53:34 +00001495 return -1;
Roland McGrathc9dc3c12004-03-01 20:57:09 +00001496 tcp->u_arg[arg0_index] = CLONE_PTRACE|SIGCHLD;
1497 tcp->u_arg[arg1_index] = 0;
Roland McGrathd81f1d92003-01-09 06:53:34 +00001498 tcp->flags |= TCB_BPTSET;
1499 return 0;
Dmitry V. Levin0c661512012-02-20 21:17:58 +00001500 }
Roland McGrathd81f1d92003-01-09 06:53:34 +00001501
Dmitry V. Levin0c661512012-02-20 21:17:58 +00001502 if (sysent[tcp->scno].sys_func == sys_clone) {
Jan Kratochvil8fc95752008-08-06 21:43:35 +00001503 /* ia64 calls directly `clone (CLONE_VFORK | CLONE_VM)'
Dmitry V. Levin0c661512012-02-20 21:17:58 +00001504 contrary to x86 vfork above. Even on x86 we turn the
Jan Kratochvil8fc95752008-08-06 21:43:35 +00001505 vfork semantics into plain fork - each application must not
1506 depend on the vfork specifics according to POSIX. We would
1507 hang waiting for the parent resume otherwise. We need to
1508 clear also CLONE_VM but only in the CLONE_VFORK case as
1509 otherwise we would break pthread_create. */
1510
Denys Vlasenkoc133bf02011-06-23 21:57:54 +02001511 long new_arg0 = (tcp->u_arg[arg0_index] | CLONE_PTRACE);
1512 if (new_arg0 & CLONE_VFORK)
1513 new_arg0 &= ~(unsigned long)(CLONE_VFORK | CLONE_VM);
1514 if (arg_setup(tcp, &state) < 0
1515 || set_arg0(tcp, &state, new_arg0) < 0
1516 || arg_finish_change(tcp, &state) < 0)
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00001517 return -1;
Roland McGrathc9dc3c12004-03-01 20:57:09 +00001518 tcp->inst[0] = tcp->u_arg[arg0_index];
1519 tcp->inst[1] = tcp->u_arg[arg1_index];
Denys Vlasenko55980f52012-05-14 16:40:28 +02001520 tcp->flags |= TCB_BPTSET;
Roland McGrathd81f1d92003-01-09 06:53:34 +00001521 return 0;
Roland McGrathd81f1d92003-01-09 06:53:34 +00001522 }
1523
Dmitry V. Levin0c661512012-02-20 21:17:58 +00001524 fprintf(stderr, "PANIC: setbpt for syscall %ld on %u???\n",
1525 tcp->scno, tcp->pid);
Roland McGrathd81f1d92003-01-09 06:53:34 +00001526 return -1;
1527}
1528
1529int
Denys Vlasenko12014262011-05-30 14:00:14 +02001530clearbpt(struct tcb *tcp)
Roland McGrathd81f1d92003-01-09 06:53:34 +00001531{
1532 arg_setup_state state;
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001533 if (arg_setup(tcp, &state) < 0
Denys Vlasenko55980f52012-05-14 16:40:28 +02001534 || change_syscall(tcp, tcp->scno) < 0
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001535 || restore_arg0(tcp, &state, tcp->inst[0]) < 0
1536 || restore_arg1(tcp, &state, tcp->inst[1]) < 0
1537 || arg_finish_change(tcp, &state))
Denys Vlasenkoc133bf02011-06-23 21:57:54 +02001538 if (errno != ESRCH)
1539 return -1;
Roland McGrathd81f1d92003-01-09 06:53:34 +00001540 tcp->flags &= ~TCB_BPTSET;
1541 return 0;
1542}