blob: 348d77f498fdd3314f7ac3ab7a8d921e21dad487 [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++;
215# elif defined LINUX_MIPSN32
216 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.
375 * If `len' < 0, treat `instr' as a NUL-terminated string
376 * and quote at most (`size' - 1) bytes.
Denys Vlasenko6cecba52012-01-20 11:56:00 +0100377 *
378 * Returns 0 if len < 0 and NUL was seen, 1 otherwise.
379 * Note that if len >= 0, always returns 1.
Dmitry V. Levina501f142008-11-10 23:19:13 +0000380 */
Roland McGrath6d970322007-11-01 23:53:59 +0000381static int
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000382string_quote(const char *instr, char *outstr, int 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 */
389 if (len < 0) {
390 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) */
489 if (len < 0 && ustr[i] == '\0') {
490 /* 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
554printstr(struct tcb *tcp, long addr, int len)
555{
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
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000579 if (len < 0) {
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 {
Dmitry V. Levina501f142008-11-10 23:19:13 +0000591 size = MIN(len, max_strlen);
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000592 if (umoven(tcp, addr, size, str) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000593 tprintf("%#lx", addr);
594 return;
595 }
596 }
597
Denys Vlasenko6cecba52012-01-20 11:56:00 +0100598 /* If string_quote didn't see NUL and (it was supposed to be ASCIZ str
599 * or we were requested to print more than -s NUM chars)...
600 */
Denys Vlasenkob3c52cf2012-01-19 17:20:23 +0100601 ellipsis = (string_quote(str, outstr, len, size) &&
602 (len < 0 || len > max_strlen));
Roland McGratha503dcf2007-08-02 02:06:26 +0000603
Denys Vlasenkob3c52cf2012-01-19 17:20:23 +0100604 tprints(outstr);
605 if (ellipsis)
606 tprints("...");
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000607}
608
John Hughes1d08dcf2001-07-10 13:48:44 +0000609#if HAVE_SYS_UIO_H
610void
Denys Vlasenko12014262011-05-30 14:00:14 +0200611dumpiov(struct tcb *tcp, int len, long addr)
John Hughes1d08dcf2001-07-10 13:48:44 +0000612{
Denys Vlasenko84703742012-02-25 02:38:52 +0100613#if SUPPORTED_PERSONALITIES > 1
Dmitry V. Levin4ebb4e32006-12-13 17:08:08 +0000614 union {
615 struct { u_int32_t base; u_int32_t len; } *iov32;
616 struct { u_int64_t base; u_int64_t len; } *iov64;
617 } iovu;
618#define iov iovu.iov64
619#define sizeof_iov \
Denys Vlasenko9fd4f962012-03-19 09:36:42 +0100620 (current_wordsize == 4 ? sizeof(*iovu.iov32) : sizeof(*iovu.iov64))
Dmitry V. Levin4ebb4e32006-12-13 17:08:08 +0000621#define iov_iov_base(i) \
Denys Vlasenko9fd4f962012-03-19 09:36:42 +0100622 (current_wordsize == 4 ? (uint64_t) iovu.iov32[i].base : iovu.iov64[i].base)
Dmitry V. Levin4ebb4e32006-12-13 17:08:08 +0000623#define iov_iov_len(i) \
Denys Vlasenko9fd4f962012-03-19 09:36:42 +0100624 (current_wordsize == 4 ? (uint64_t) iovu.iov32[i].len : iovu.iov64[i].len)
Dmitry V. Levin4ebb4e32006-12-13 17:08:08 +0000625#else
John Hughes1d08dcf2001-07-10 13:48:44 +0000626 struct iovec *iov;
Dmitry V. Levin4ebb4e32006-12-13 17:08:08 +0000627#define sizeof_iov sizeof(*iov)
628#define iov_iov_base(i) iov[i].iov_base
629#define iov_iov_len(i) iov[i].iov_len
630#endif
John Hughes1d08dcf2001-07-10 13:48:44 +0000631 int i;
Denys Vlasenko79a79ea2011-09-01 16:35:44 +0200632 unsigned size;
John Hughes1d08dcf2001-07-10 13:48:44 +0000633
Denys Vlasenko79a79ea2011-09-01 16:35:44 +0200634 size = sizeof_iov * len;
635 /* Assuming no sane program has millions of iovs */
636 if ((unsigned)len > 1024*1024 /* insane or negative size? */
Dmitry V. Levin4ebb4e32006-12-13 17:08:08 +0000637 || (iov = malloc(size)) == NULL) {
Denys Vlasenko79a79ea2011-09-01 16:35:44 +0200638 fprintf(stderr, "Out of memory\n");
639 return;
John Hughes1d08dcf2001-07-10 13:48:44 +0000640 }
Roland McGrathaa524c82005-06-01 19:22:06 +0000641 if (umoven(tcp, addr, size, (char *) iov) >= 0) {
John Hughes1d08dcf2001-07-10 13:48:44 +0000642 for (i = 0; i < len; i++) {
Denys Vlasenkoadedb512008-12-30 18:47:55 +0000643 /* include the buffer number to make it easy to
644 * match up the trace with the source */
645 tprintf(" * %lu bytes in buffer %d\n",
646 (unsigned long)iov_iov_len(i), i);
647 dumpstr(tcp, (long) iov_iov_base(i),
648 iov_iov_len(i));
649 }
John Hughes1d08dcf2001-07-10 13:48:44 +0000650 }
Denys Vlasenko79a79ea2011-09-01 16:35:44 +0200651 free(iov);
Dmitry V. Levin4ebb4e32006-12-13 17:08:08 +0000652#undef sizeof_iov
653#undef iov_iov_base
654#undef iov_iov_len
655#undef iov
John Hughes1d08dcf2001-07-10 13:48:44 +0000656}
657#endif
658
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000659void
Denys Vlasenko12014262011-05-30 14:00:14 +0200660dumpstr(struct tcb *tcp, long addr, int len)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000661{
662 static int strsize = -1;
663 static unsigned char *str;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000664 char *s;
665 int i, j;
666
667 if (strsize < len) {
Denys Vlasenko5d645812011-08-20 12:48:18 +0200668 free(str);
669 str = malloc(len);
Denys Vlasenko79a79ea2011-09-01 16:35:44 +0200670 if (!str) {
671 strsize = -1;
672 fprintf(stderr, "Out of memory\n");
673 return;
674 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000675 strsize = len;
676 }
677
678 if (umoven(tcp, addr, len, (char *) str) < 0)
679 return;
680
681 for (i = 0; i < len; i += 16) {
Denys Vlasenko1d46ba52011-08-31 14:00:02 +0200682 char outstr[80];
683
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000684 s = outstr;
685 sprintf(s, " | %05x ", i);
686 s += 9;
687 for (j = 0; j < 16; j++) {
688 if (j == 8)
689 *s++ = ' ';
690 if (i + j < len) {
691 sprintf(s, " %02x", str[i + j]);
692 s += 3;
693 }
694 else {
695 *s++ = ' '; *s++ = ' '; *s++ = ' ';
696 }
697 }
698 *s++ = ' '; *s++ = ' ';
699 for (j = 0; j < 16; j++) {
700 if (j == 8)
701 *s++ = ' ';
702 if (i + j < len) {
703 if (isprint(str[i + j]))
704 *s++ = str[i + j];
705 else
706 *s++ = '.';
707 }
708 else
709 *s++ = ' ';
710 }
711 tprintf("%s |\n", outstr);
712 }
713}
714
Mike Frysinger612659e2012-02-14 14:38:28 +0100715#ifdef HAVE_PROCESS_VM_READV
716/* C library supports this, but the kernel might not. */
717static bool process_vm_readv_not_supported = 0;
718#else
719
Denys Vlasenko3af224c2012-01-28 01:46:33 +0100720/* Need to do this since process_vm_readv() is not yet available in libc.
721 * When libc is be updated, only "static bool process_vm_readv_not_supported"
722 * line should remain.
723 */
724#if !defined(__NR_process_vm_readv)
725# if defined(I386)
726# define __NR_process_vm_readv 347
727# elif defined(X86_64)
728# define __NR_process_vm_readv 310
729# elif defined(POWERPC)
730# define __NR_process_vm_readv 351
731# endif
732#endif
733
734#if defined(__NR_process_vm_readv)
735static bool process_vm_readv_not_supported = 0;
736static ssize_t process_vm_readv(pid_t pid,
737 const struct iovec *lvec,
738 unsigned long liovcnt,
739 const struct iovec *rvec,
740 unsigned long riovcnt,
741 unsigned long flags)
742{
743 return syscall(__NR_process_vm_readv, (long)pid, lvec, liovcnt, rvec, riovcnt, flags);
744}
745#else
746static bool process_vm_readv_not_supported = 1;
747# define process_vm_readv(...) (errno = ENOSYS, -1)
748#endif
Mike Frysinger612659e2012-02-14 14:38:28 +0100749
750#endif /* end of hack */
Denys Vlasenko3af224c2012-01-28 01:46:33 +0100751
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000752#define PAGMASK (~(PAGSIZ - 1))
753/*
754 * move `len' bytes of data from process `pid'
755 * at address `addr' to our space at `laddr'
756 */
757int
Denys Vlasenkoef2fbf82009-01-06 21:45:06 +0000758umoven(struct tcb *tcp, long addr, int len, char *laddr)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000759{
Roland McGratheb9e2e82009-06-02 16:49:22 -0700760 int pid = tcp->pid;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000761 int n, m;
Denys Vlasenkoa47e6b92012-01-21 04:01:56 +0100762 int started;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000763 union {
764 long val;
765 char x[sizeof(long)];
766 } u;
767
Denys Vlasenkod2a660f2012-02-25 00:43:22 +0100768#if SUPPORTED_PERSONALITIES > 1
Denys Vlasenko9fd4f962012-03-19 09:36:42 +0100769 if (current_wordsize < sizeof(addr))
770 addr &= (1ul << 8 * current_wordsize) - 1;
Denys Vlasenkod2a660f2012-02-25 00:43:22 +0100771#endif
772
Denys Vlasenko3af224c2012-01-28 01:46:33 +0100773 if (!process_vm_readv_not_supported) {
774 struct iovec local[1], remote[1];
775 int r;
776
777 local[0].iov_base = laddr;
778 remote[0].iov_base = (void*)addr;
779 local[0].iov_len = remote[0].iov_len = len;
780 r = process_vm_readv(pid,
781 local, 1,
782 remote, 1,
783 /*flags:*/ 0
784 );
785 if (r < 0) {
786 if (errno == ENOSYS)
787 process_vm_readv_not_supported = 1;
Denys Vlasenko29456392012-01-28 02:49:48 +0100788 else if (errno != EINVAL) /* EINVAL is seen if process is gone */
789 /* strange... */
Denys Vlasenko3af224c2012-01-28 01:46:33 +0100790 perror("process_vm_readv");
791 goto vm_readv_didnt_work;
792 }
793 return r;
794 }
795 vm_readv_didnt_work:
796
Denys Vlasenkoa47e6b92012-01-21 04:01:56 +0100797 started = 0;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000798 if (addr & (sizeof(long) - 1)) {
799 /* addr not a multiple of sizeof(long) */
800 n = addr - (addr & -sizeof(long)); /* residue */
801 addr &= -sizeof(long); /* residue */
Roland McGratheb9e2e82009-06-02 16:49:22 -0700802 errno = 0;
803 u.val = ptrace(PTRACE_PEEKDATA, pid, (char *) addr, 0);
804 if (errno) {
Roland McGratheb9e2e82009-06-02 16:49:22 -0700805 /* But if not started, we had a bogus address. */
806 if (addr != 0 && errno != EIO && errno != ESRCH)
Denys Vlasenko4c65c442012-03-08 11:54:10 +0100807 perror_msg("umoven: PTRACE_PEEKDATA pid:%d @0x%lx", pid, addr);
Roland McGratheb9e2e82009-06-02 16:49:22 -0700808 return -1;
809 }
Wichert Akkerman5daa0281999-03-15 19:49:42 +0000810 started = 1;
Denys Vlasenkoa47e6b92012-01-21 04:01:56 +0100811 m = MIN(sizeof(long) - n, len);
812 memcpy(laddr, &u.x[n], m);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000813 addr += sizeof(long), laddr += m, len -= m;
814 }
815 while (len) {
Roland McGratheb9e2e82009-06-02 16:49:22 -0700816 errno = 0;
817 u.val = ptrace(PTRACE_PEEKDATA, pid, (char *) addr, 0);
818 if (errno) {
819 if (started && (errno==EPERM || errno==EIO)) {
820 /* Ran into 'end of memory' - stupid "printpath" */
821 return 0;
822 }
823 if (addr != 0 && errno != EIO && errno != ESRCH)
Denys Vlasenko4c65c442012-03-08 11:54:10 +0100824 perror_msg("umoven: PTRACE_PEEKDATA pid:%d @0x%lx", pid, addr);
Roland McGratheb9e2e82009-06-02 16:49:22 -0700825 return -1;
826 }
Wichert Akkerman5daa0281999-03-15 19:49:42 +0000827 started = 1;
Denys Vlasenkoa47e6b92012-01-21 04:01:56 +0100828 m = MIN(sizeof(long), len);
829 memcpy(laddr, u.x, m);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000830 addr += sizeof(long), laddr += m, len -= m;
831 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000832
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000833 return 0;
834}
835
836/*
Denys Vlasenko6cecba52012-01-20 11:56:00 +0100837 * Like `umove' but make the additional effort of looking
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000838 * for a terminating zero byte.
Denys Vlasenko6cecba52012-01-20 11:56:00 +0100839 *
840 * Returns < 0 on error, > 0 if NUL was seen,
841 * (TODO if useful: return count of bytes including NUL),
842 * else 0 if len bytes were read but no NUL byte seen.
843 *
844 * Note: there is no guarantee we won't overwrite some bytes
845 * in laddr[] _after_ terminating NUL (but, of course,
846 * we never write past laddr[len-1]).
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000847 */
848int
Denys Vlasenkoef2fbf82009-01-06 21:45:06 +0000849umovestr(struct tcb *tcp, long addr, int len, char *laddr)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000850{
Denys Vlasenkoa47e6b92012-01-21 04:01:56 +0100851 int started;
Roland McGratheb9e2e82009-06-02 16:49:22 -0700852 int pid = tcp->pid;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000853 int i, n, m;
854 union {
855 long val;
856 char x[sizeof(long)];
857 } u;
858
Dmitry V. Levin856c7ed2011-12-26 20:12:02 +0000859#if SUPPORTED_PERSONALITIES > 1
Denys Vlasenko9fd4f962012-03-19 09:36:42 +0100860 if (current_wordsize < sizeof(addr))
861 addr &= (1ul << 8 * current_wordsize) - 1;
Dmitry V. Levin856c7ed2011-12-26 20:12:02 +0000862#endif
863
Denys Vlasenko3af224c2012-01-28 01:46:33 +0100864 if (!process_vm_readv_not_supported) {
865 struct iovec local[1], remote[1];
866
867 local[0].iov_base = laddr;
868 remote[0].iov_base = (void*)addr;
869
870 while (len > 0) {
871 int end_in_page;
872 int r;
873 int chunk_len;
874
875 /* Don't read kilobytes: most strings are short */
876 chunk_len = len;
877 if (chunk_len > 256)
878 chunk_len = 256;
879 /* Don't cross pages. I guess otherwise we can get EFAULT
880 * and fail to notice that terminating NUL lies
881 * in the existing (first) page.
882 * (I hope there aren't arches with pages < 4K)
883 */
884 end_in_page = ((addr + chunk_len) & 4095);
885 r = chunk_len - end_in_page;
886 if (r > 0) /* if chunk_len > end_in_page */
887 chunk_len = r; /* chunk_len -= end_in_page */
888
889 local[0].iov_len = remote[0].iov_len = chunk_len;
890 r = process_vm_readv(pid,
891 local, 1,
892 remote, 1,
893 /*flags:*/ 0
894 );
895 if (r < 0) {
896 if (errno == ENOSYS)
897 process_vm_readv_not_supported = 1;
Denys Vlasenko29456392012-01-28 02:49:48 +0100898 else if (errno != EINVAL) /* EINVAL is seen if process is gone */
899 /* strange... */
Denys Vlasenko3af224c2012-01-28 01:46:33 +0100900 perror("process_vm_readv");
901 goto vm_readv_didnt_work;
902 }
903 if (memchr(local[0].iov_base, '\0', r))
904 return 1;
905 local[0].iov_base += r;
906 remote[0].iov_base += r;
907 len -= r;
908 }
909 return 0;
910 }
911 vm_readv_didnt_work:
912
Denys Vlasenkoa47e6b92012-01-21 04:01:56 +0100913 started = 0;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000914 if (addr & (sizeof(long) - 1)) {
915 /* addr not a multiple of sizeof(long) */
916 n = addr - (addr & -sizeof(long)); /* residue */
917 addr &= -sizeof(long); /* residue */
Roland McGratheb9e2e82009-06-02 16:49:22 -0700918 errno = 0;
919 u.val = ptrace(PTRACE_PEEKDATA, pid, (char *)addr, 0);
920 if (errno) {
Roland McGratheb9e2e82009-06-02 16:49:22 -0700921 if (addr != 0 && errno != EIO && errno != ESRCH)
Denys Vlasenko4c65c442012-03-08 11:54:10 +0100922 perror_msg("umovestr: PTRACE_PEEKDATA pid:%d @0x%lx", pid, addr);
Roland McGratheb9e2e82009-06-02 16:49:22 -0700923 return -1;
924 }
Wichert Akkerman5daa0281999-03-15 19:49:42 +0000925 started = 1;
Denys Vlasenkoa47e6b92012-01-21 04:01:56 +0100926 m = MIN(sizeof(long) - n, len);
927 memcpy(laddr, &u.x[n], m);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000928 while (n & (sizeof(long) - 1))
929 if (u.x[n++] == '\0')
Denys Vlasenko6cecba52012-01-20 11:56:00 +0100930 return 1;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000931 addr += sizeof(long), laddr += m, len -= m;
932 }
933 while (len) {
Roland McGratheb9e2e82009-06-02 16:49:22 -0700934 errno = 0;
935 u.val = ptrace(PTRACE_PEEKDATA, pid, (char *)addr, 0);
936 if (errno) {
937 if (started && (errno==EPERM || errno==EIO)) {
938 /* Ran into 'end of memory' - stupid "printpath" */
939 return 0;
940 }
941 if (addr != 0 && errno != EIO && errno != ESRCH)
Denys Vlasenko4c65c442012-03-08 11:54:10 +0100942 perror_msg("umovestr: PTRACE_PEEKDATA pid:%d @0x%lx", pid, addr);
Roland McGratheb9e2e82009-06-02 16:49:22 -0700943 return -1;
944 }
Wichert Akkerman5daa0281999-03-15 19:49:42 +0000945 started = 1;
Denys Vlasenkoa47e6b92012-01-21 04:01:56 +0100946 m = MIN(sizeof(long), len);
947 memcpy(laddr, u.x, m);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000948 for (i = 0; i < sizeof(long); i++)
949 if (u.x[i] == '\0')
Denys Vlasenko6cecba52012-01-20 11:56:00 +0100950 return 1;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000951 addr += sizeof(long), laddr += m, len -= m;
952 }
John Hughesaa09c6b2001-05-15 14:53:43 +0000953 return 0;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000954}
955
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000956int
Denys Vlasenko12014262011-05-30 14:00:14 +0200957upeek(struct tcb *tcp, long off, long *res)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000958{
959 long val;
960
Roland McGratheb9e2e82009-06-02 16:49:22 -0700961 errno = 0;
Denys Vlasenko114aefd2012-03-08 12:13:44 +0100962 val = ptrace(PTRACE_PEEKUSER, tcp->pid, (char *) off, 0);
Roland McGratheb9e2e82009-06-02 16:49:22 -0700963 if (val == -1 && errno) {
964 if (errno != ESRCH) {
Denys Vlasenko4c65c442012-03-08 11:54:10 +0100965 perror_msg("upeek: PTRACE_PEEKUSER pid:%d @0x%lx)", tcp->pid, off);
Roland McGratheb9e2e82009-06-02 16:49:22 -0700966 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000967 return -1;
Roland McGratheb9e2e82009-06-02 16:49:22 -0700968 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000969 *res = val;
970 return 0;
971}
972
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000973void
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +0000974printcall(struct tcb *tcp)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000975{
Roland McGrath7a918832005-02-02 20:55:23 +0000976#define PRINTBADPC tprintf(sizeof(long) == 4 ? "[????????] " : \
977 sizeof(long) == 8 ? "[????????????????] " : \
978 NULL /* crash */)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000979
Denys Vlasenko2d1e90f2012-02-25 02:46:14 +0100980#if defined(I386)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000981 long eip;
982
Denys Vlasenko932fc7d2008-12-16 18:18:40 +0000983 if (upeek(tcp, 4*EIP, &eip) < 0) {
Roland McGrath7a918832005-02-02 20:55:23 +0000984 PRINTBADPC;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000985 return;
986 }
987 tprintf("[%08lx] ", eip);
Denys Vlasenko2d1e90f2012-02-25 02:46:14 +0100988#elif defined(S390) || defined(S390X)
Denys Vlasenkoadedb512008-12-30 18:47:55 +0000989 long psw;
Denys Vlasenkob63256e2011-06-07 12:13:24 +0200990 if (upeek(tcp, PT_PSWADDR, &psw) < 0) {
Denys Vlasenkoadedb512008-12-30 18:47:55 +0000991 PRINTBADPC;
992 return;
993 }
Denys Vlasenko2d1e90f2012-02-25 02:46:14 +0100994# ifdef S390
Denys Vlasenkoadedb512008-12-30 18:47:55 +0000995 tprintf("[%08lx] ", psw);
Denys Vlasenko2d1e90f2012-02-25 02:46:14 +0100996# elif S390X
Denys Vlasenkoadedb512008-12-30 18:47:55 +0000997 tprintf("[%16lx] ", psw);
Denys Vlasenko2d1e90f2012-02-25 02:46:14 +0100998# endif
Roland McGratheac26fc2005-02-02 02:48:53 +0000999
Denys Vlasenko2d1e90f2012-02-25 02:46:14 +01001000#elif defined(X86_64)
Michal Ludvig0e035502002-09-23 15:41:01 +00001001 long rip;
1002
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001003 if (upeek(tcp, 8*RIP, &rip) < 0) {
Roland McGrath7a918832005-02-02 20:55:23 +00001004 PRINTBADPC;
Michal Ludvig0e035502002-09-23 15:41:01 +00001005 return;
1006 }
1007 tprintf("[%16lx] ", rip);
Denys Vlasenko2d1e90f2012-02-25 02:46:14 +01001008#elif defined(IA64)
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00001009 long ip;
1010
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001011 if (upeek(tcp, PT_B0, &ip) < 0) {
Roland McGrath7a918832005-02-02 20:55:23 +00001012 PRINTBADPC;
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00001013 return;
1014 }
1015 tprintf("[%08lx] ", ip);
Denys Vlasenko2d1e90f2012-02-25 02:46:14 +01001016#elif defined(POWERPC)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001017 long pc;
1018
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001019 if (upeek(tcp, sizeof(unsigned long)*PT_NIP, &pc) < 0) {
Andreas Schwabd69fa492010-07-12 21:39:57 +02001020 PRINTBADPC;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001021 return;
1022 }
Denys Vlasenko2d1e90f2012-02-25 02:46:14 +01001023# ifdef POWERPC64
Andreas Schwabd69fa492010-07-12 21:39:57 +02001024 tprintf("[%016lx] ", pc);
Denys Vlasenko2d1e90f2012-02-25 02:46:14 +01001025# else
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001026 tprintf("[%08lx] ", pc);
Denys Vlasenko2d1e90f2012-02-25 02:46:14 +01001027# endif
1028#elif defined(M68K)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001029 long pc;
1030
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001031 if (upeek(tcp, 4*PT_PC, &pc) < 0) {
Denys Vlasenko60fe8c12011-09-01 10:00:28 +02001032 tprints("[????????] ");
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001033 return;
1034 }
1035 tprintf("[%08lx] ", pc);
Denys Vlasenko2d1e90f2012-02-25 02:46:14 +01001036#elif defined(ALPHA)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001037 long pc;
1038
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001039 if (upeek(tcp, REG_PC, &pc) < 0) {
Denys Vlasenko60fe8c12011-09-01 10:00:28 +02001040 tprints("[????????????????] ");
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001041 return;
1042 }
1043 tprintf("[%08lx] ", pc);
Denys Vlasenko2d1e90f2012-02-25 02:46:14 +01001044#elif defined(SPARC) || defined(SPARC64)
Mike Frysinger8566c502009-10-12 11:05:14 -04001045 struct pt_regs regs;
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001046 if (ptrace(PTRACE_GETREGS, tcp->pid, (char *)&regs, 0) < 0) {
Roland McGrath7a918832005-02-02 20:55:23 +00001047 PRINTBADPC;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001048 return;
1049 }
Denys Vlasenko2d1e90f2012-02-25 02:46:14 +01001050# if defined(SPARC64)
Mike Frysinger8566c502009-10-12 11:05:14 -04001051 tprintf("[%08lx] ", regs.tpc);
Denys Vlasenko2d1e90f2012-02-25 02:46:14 +01001052# else
Mike Frysinger8566c502009-10-12 11:05:14 -04001053 tprintf("[%08lx] ", regs.pc);
Denys Vlasenko2d1e90f2012-02-25 02:46:14 +01001054# endif
1055#elif defined(HPPA)
Wichert Akkermanc1652e22001-03-27 12:17:16 +00001056 long pc;
1057
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001058 if (upeek(tcp, PT_IAOQ0, &pc) < 0) {
Denys Vlasenko60fe8c12011-09-01 10:00:28 +02001059 tprints("[????????] ");
Wichert Akkermanc1652e22001-03-27 12:17:16 +00001060 return;
1061 }
1062 tprintf("[%08lx] ", pc);
Denys Vlasenko2d1e90f2012-02-25 02:46:14 +01001063#elif defined(MIPS)
Wichert Akkerman75c422b2001-04-10 10:22:50 +00001064 long pc;
1065
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001066 if (upeek(tcp, REG_EPC, &pc) < 0) {
Denys Vlasenko60fe8c12011-09-01 10:00:28 +02001067 tprints("[????????] ");
Wichert Akkerman75c422b2001-04-10 10:22:50 +00001068 return;
1069 }
1070 tprintf("[%08lx] ", pc);
Denys Vlasenko2d1e90f2012-02-25 02:46:14 +01001071#elif defined(SH)
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001072 long pc;
Wichert Akkermanccef6372002-05-01 16:39:22 +00001073
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001074 if (upeek(tcp, 4*REG_PC, &pc) < 0) {
Denys Vlasenko60fe8c12011-09-01 10:00:28 +02001075 tprints("[????????] ");
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001076 return;
1077 }
1078 tprintf("[%08lx] ", pc);
Denys Vlasenko2d1e90f2012-02-25 02:46:14 +01001079#elif defined(SH64)
Roland McGrathe1e584b2003-06-02 19:18:58 +00001080 long pc;
1081
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001082 if (upeek(tcp, REG_PC, &pc) < 0) {
Denys Vlasenko60fe8c12011-09-01 10:00:28 +02001083 tprints("[????????????????] ");
Roland McGrathe1e584b2003-06-02 19:18:58 +00001084 return;
1085 }
1086 tprintf("[%08lx] ", pc);
Denys Vlasenko2d1e90f2012-02-25 02:46:14 +01001087#elif defined(ARM)
Roland McGrathef388682003-06-03 23:28:59 +00001088 long pc;
Roland McGrathe1e584b2003-06-02 19:18:58 +00001089
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001090 if (upeek(tcp, 4*15, &pc) < 0) {
Roland McGrath7a918832005-02-02 20:55:23 +00001091 PRINTBADPC;
Roland McGrathef388682003-06-03 23:28:59 +00001092 return;
1093 }
1094 tprintf("[%08lx] ", pc);
Denys Vlasenko2d1e90f2012-02-25 02:46:14 +01001095#elif defined(AVR32)
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00001096 long pc;
1097
1098 if (upeek(tcp, REG_PC, &pc) < 0) {
Denys Vlasenko60fe8c12011-09-01 10:00:28 +02001099 tprints("[????????] ");
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00001100 return;
1101 }
1102 tprintf("[%08lx] ", pc);
Denys Vlasenko2d1e90f2012-02-25 02:46:14 +01001103#elif defined(BFIN)
Dmitry V. Levin87ea1f42008-11-10 22:21:41 +00001104 long pc;
1105
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001106 if (upeek(tcp, PT_PC, &pc) < 0) {
Dmitry V. Levin87ea1f42008-11-10 22:21:41 +00001107 PRINTBADPC;
1108 return;
1109 }
1110 tprintf("[%08lx] ", pc);
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001111#elif defined(CRISV10)
1112 long pc;
1113
Edgar E. Iglesiaseeb9ce32009-10-05 14:41:02 +00001114 if (upeek(tcp, 4*PT_IRP, &pc) < 0) {
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001115 PRINTBADPC;
1116 return;
1117 }
1118 tprintf("[%08lx] ", pc);
1119#elif defined(CRISV32)
1120 long pc;
1121
Edgar E. Iglesiaseeb9ce32009-10-05 14:41:02 +00001122 if (upeek(tcp, 4*PT_ERP, &pc) < 0) {
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001123 PRINTBADPC;
1124 return;
1125 }
1126 tprintf("[%08lx] ", pc);
Denys Vlasenko2d1e90f2012-02-25 02:46:14 +01001127#endif /* architecture */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001128}
1129
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001130/*
1131 * These #if's are huge, please indent them correctly.
1132 * It's easy to get confused otherwise.
1133 */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001134
Denys Vlasenko2d1e90f2012-02-25 02:46:14 +01001135#include "syscall.h"
Roland McGrath3291ef22008-05-20 00:34:34 +00001136
Denys Vlasenko2d1e90f2012-02-25 02:46:14 +01001137#ifndef CLONE_PTRACE
1138# define CLONE_PTRACE 0x00002000
1139#endif
1140#ifndef CLONE_VFORK
1141# define CLONE_VFORK 0x00004000
1142#endif
1143#ifndef CLONE_VM
1144# define CLONE_VM 0x00000100
1145#endif
Roland McGrathd81f1d92003-01-09 06:53:34 +00001146
Denys Vlasenko081533c2012-03-17 02:17:51 +01001147static int
1148change_syscall(struct tcb *tcp, int new)
1149{
1150#if defined(I386)
1151 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(ORIG_EAX * 4), new) < 0)
1152 return -1;
1153 return 0;
1154#elif defined(X86_64)
1155 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(ORIG_RAX * 8), new) < 0)
1156 return -1;
1157 return 0;
1158#elif defined(POWERPC)
1159 if (ptrace(PTRACE_POKEUSER, tcp->pid,
1160 (char*)(sizeof(unsigned long)*PT_R0), new) < 0)
1161 return -1;
1162 return 0;
1163#elif defined(S390) || defined(S390X)
1164 /* s390 linux after 2.4.7 has a hook in entry.S to allow this */
1165 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(PT_GPR2), new) < 0)
1166 return -1;
1167 return 0;
1168#elif defined(M68K)
1169 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(4*PT_ORIG_D0), new) < 0)
1170 return -1;
1171 return 0;
1172#elif defined(SPARC) || defined(SPARC64)
1173 struct pt_regs regs;
1174 if (ptrace(PTRACE_GETREGS, tcp->pid, (char*)&regs, 0) < 0)
1175 return -1;
1176 regs.u_regs[U_REG_G1] = new;
1177 if (ptrace(PTRACE_SETREGS, tcp->pid, (char*)&regs, 0) < 0)
1178 return -1;
1179 return 0;
1180#elif defined(MIPS)
1181 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(REG_V0), new) < 0)
1182 return -1;
1183 return 0;
1184#elif defined(ALPHA)
1185 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(REG_A3), new) < 0)
1186 return -1;
1187 return 0;
1188#elif defined(AVR32)
1189 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(REG_R8), new) < 0)
1190 return -1;
1191 return 0;
1192#elif defined(BFIN)
1193 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(REG_P0), new) < 0)
1194 return -1;
1195 return 0;
1196#elif defined(IA64)
1197 if (ia32) {
1198 switch (new) {
1199 case 2:
1200 break; /* x86 SYS_fork */
1201 case SYS_clone:
1202 new = 120;
1203 break;
1204 default:
1205 fprintf(stderr, "%s: unexpected syscall %d\n",
1206 __FUNCTION__, new);
1207 return -1;
1208 }
1209 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(PT_R1), new) < 0)
1210 return -1;
1211 } else if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(PT_R15), new) < 0)
1212 return -1;
1213 return 0;
1214#elif defined(HPPA)
1215 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(PT_GR20), new) < 0)
1216 return -1;
1217 return 0;
1218#elif defined(SH)
1219 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(4*(REG_REG0+3)), new) < 0)
1220 return -1;
1221 return 0;
1222#elif defined(SH64)
1223 /* Top half of reg encodes the no. of args n as 0x1n.
1224 Assume 0 args as kernel never actually checks... */
1225 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(REG_SYSCALL),
1226 0x100000 | new) < 0)
1227 return -1;
1228 return 0;
1229#elif defined(CRISV10) || defined(CRISV32)
1230 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(4*PT_R9), new) < 0)
1231 return -1;
1232 return 0;
1233#elif defined(ARM)
1234 /* Some kernels support this, some (pre-2.6.16 or so) don't. */
1235# ifndef PTRACE_SET_SYSCALL
1236# define PTRACE_SET_SYSCALL 23
1237# endif
1238 if (ptrace(PTRACE_SET_SYSCALL, tcp->pid, 0, new & 0xffff) != 0)
1239 return -1;
1240 return 0;
1241#elif defined(TILE)
1242 if (ptrace(PTRACE_POKEUSER, tcp->pid,
1243 (char*)PTREGS_OFFSET_REG(0),
1244 new) != 0)
1245 return -1;
1246 return 0;
1247#elif defined(MICROBLAZE)
1248 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(PT_GPR(0)), new) < 0)
1249 return -1;
1250 return 0;
1251#else
1252#warning Do not know how to handle change_syscall for this architecture
1253#endif /* architecture */
1254 return -1;
1255}
1256
Denys Vlasenko2d1e90f2012-02-25 02:46:14 +01001257#ifdef IA64
Roland McGrathd81f1d92003-01-09 06:53:34 +00001258
1259typedef unsigned long *arg_setup_state;
1260
1261static int
1262arg_setup(struct tcb *tcp, arg_setup_state *state)
1263{
Jan Kratochvil1f942712008-08-06 21:38:52 +00001264 unsigned long cfm, sof, sol;
1265 long bsp;
Roland McGrathd81f1d92003-01-09 06:53:34 +00001266
Jan Kratochvil1f942712008-08-06 21:38:52 +00001267 if (ia32) {
1268 /* Satisfy a false GCC warning. */
1269 *state = NULL;
Roland McGrath08267b82004-02-20 22:56:43 +00001270 return 0;
Jan Kratochvil1f942712008-08-06 21:38:52 +00001271 }
Roland McGrath08267b82004-02-20 22:56:43 +00001272
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001273 if (upeek(tcp, PT_AR_BSP, &bsp) < 0)
Roland McGrathd81f1d92003-01-09 06:53:34 +00001274 return -1;
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001275 if (upeek(tcp, PT_CFM, (long *) &cfm) < 0)
Roland McGrathd81f1d92003-01-09 06:53:34 +00001276 return -1;
1277
1278 sof = (cfm >> 0) & 0x7f;
1279 sol = (cfm >> 7) & 0x7f;
Jan Kratochvil1f942712008-08-06 21:38:52 +00001280 bsp = (long) ia64_rse_skip_regs((unsigned long *) bsp, -sof + sol);
Roland McGrathd81f1d92003-01-09 06:53:34 +00001281
Jan Kratochvil1f942712008-08-06 21:38:52 +00001282 *state = (unsigned long *) bsp;
Roland McGrathd81f1d92003-01-09 06:53:34 +00001283 return 0;
1284}
1285
Denys Vlasenko2d1e90f2012-02-25 02:46:14 +01001286# define arg_finish_change(tcp, state) 0
Roland McGrathd81f1d92003-01-09 06:53:34 +00001287
Roland McGrathd81f1d92003-01-09 06:53:34 +00001288static int
Denys Vlasenko12014262011-05-30 14:00:14 +02001289get_arg0(struct tcb *tcp, arg_setup_state *state, long *valp)
Roland McGrathd81f1d92003-01-09 06:53:34 +00001290{
Roland McGrath08267b82004-02-20 22:56:43 +00001291 int ret;
1292
1293 if (ia32)
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001294 ret = upeek(tcp, PT_R11, valp);
Roland McGrath08267b82004-02-20 22:56:43 +00001295 else
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001296 ret = umoven(tcp,
Roland McGrath08267b82004-02-20 22:56:43 +00001297 (unsigned long) ia64_rse_skip_regs(*state, 0),
1298 sizeof(long), (void *) valp);
1299 return ret;
Roland McGrathd81f1d92003-01-09 06:53:34 +00001300}
1301
1302static int
Denys Vlasenko12014262011-05-30 14:00:14 +02001303get_arg1(struct tcb *tcp, arg_setup_state *state, long *valp)
Roland McGrathd81f1d92003-01-09 06:53:34 +00001304{
Roland McGrath08267b82004-02-20 22:56:43 +00001305 int ret;
1306
1307 if (ia32)
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001308 ret = upeek(tcp, PT_R9, valp);
Roland McGrath08267b82004-02-20 22:56:43 +00001309 else
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001310 ret = umoven(tcp,
Roland McGrath08267b82004-02-20 22:56:43 +00001311 (unsigned long) ia64_rse_skip_regs(*state, 1),
1312 sizeof(long), (void *) valp);
1313 return ret;
Roland McGrathd81f1d92003-01-09 06:53:34 +00001314}
Roland McGrathd81f1d92003-01-09 06:53:34 +00001315
1316static int
Denys Vlasenko12014262011-05-30 14:00:14 +02001317set_arg0(struct tcb *tcp, arg_setup_state *state, long val)
Roland McGrathd81f1d92003-01-09 06:53:34 +00001318{
Roland McGrath08267b82004-02-20 22:56:43 +00001319 int req = PTRACE_POKEDATA;
1320 void *ap;
1321
1322 if (ia32) {
1323 ap = (void *) (intptr_t) PT_R11; /* r11 == EBX */
1324 req = PTRACE_POKEUSER;
1325 } else
1326 ap = ia64_rse_skip_regs(*state, 0);
Roland McGratheb9e2e82009-06-02 16:49:22 -07001327 errno = 0;
1328 ptrace(req, tcp->pid, ap, val);
1329 return errno ? -1 : 0;
Roland McGrathd81f1d92003-01-09 06:53:34 +00001330}
1331
1332static int
Denys Vlasenko12014262011-05-30 14:00:14 +02001333set_arg1(struct tcb *tcp, arg_setup_state *state, long val)
Roland McGrathd81f1d92003-01-09 06:53:34 +00001334{
Roland McGrath08267b82004-02-20 22:56:43 +00001335 int req = PTRACE_POKEDATA;
1336 void *ap;
1337
1338 if (ia32) {
1339 ap = (void *) (intptr_t) PT_R9; /* r9 == ECX */
1340 req = PTRACE_POKEUSER;
1341 } else
1342 ap = ia64_rse_skip_regs(*state, 1);
Roland McGratheb9e2e82009-06-02 16:49:22 -07001343 errno = 0;
1344 ptrace(req, tcp->pid, ap, val);
1345 return errno ? -1 : 0;
Roland McGrathd81f1d92003-01-09 06:53:34 +00001346}
1347
Roland McGrathb659f872008-07-18 01:19:36 +00001348/* ia64 does not return the input arguments from functions (and syscalls)
1349 according to ia64 RSE (Register Stack Engine) behavior. */
1350
Denys Vlasenko2d1e90f2012-02-25 02:46:14 +01001351# define restore_arg0(tcp, state, val) ((void) (state), 0)
1352# define restore_arg1(tcp, state, val) ((void) (state), 0)
Roland McGrathb659f872008-07-18 01:19:36 +00001353
Denys Vlasenko2d1e90f2012-02-25 02:46:14 +01001354#elif defined(SPARC) || defined(SPARC64)
Roland McGrathd81f1d92003-01-09 06:53:34 +00001355
Mike Frysinger8566c502009-10-12 11:05:14 -04001356typedef struct pt_regs arg_setup_state;
Roland McGrathd81f1d92003-01-09 06:53:34 +00001357
Denys Vlasenko2d1e90f2012-02-25 02:46:14 +01001358# define arg_setup(tcp, state) \
1359 (ptrace(PTRACE_GETREGS, (tcp)->pid, (char *) (state), 0))
1360# define arg_finish_change(tcp, state) \
1361 (ptrace(PTRACE_SETREGS, (tcp)->pid, (char *) (state), 0))
Roland McGrathd81f1d92003-01-09 06:53:34 +00001362
Denys Vlasenko2d1e90f2012-02-25 02:46:14 +01001363# define get_arg0(tcp, state, valp) (*(valp) = (state)->u_regs[U_REG_O0], 0)
1364# define get_arg1(tcp, state, valp) (*(valp) = (state)->u_regs[U_REG_O1], 0)
1365# define set_arg0(tcp, state, val) ((state)->u_regs[U_REG_O0] = (val), 0)
1366# define set_arg1(tcp, state, val) ((state)->u_regs[U_REG_O1] = (val), 0)
1367# define restore_arg0(tcp, state, val) 0
Roland McGrathd81f1d92003-01-09 06:53:34 +00001368
Denys Vlasenko2d1e90f2012-02-25 02:46:14 +01001369#else /* other architectures */
Roland McGrathd81f1d92003-01-09 06:53:34 +00001370
Denys Vlasenko2d1e90f2012-02-25 02:46:14 +01001371# if defined S390 || defined S390X
Roland McGrath7b308222003-01-20 09:04:36 +00001372/* Note: this is only true for the `clone' system call, which handles
1373 arguments specially. We could as well say that its first two arguments
1374 are swapped relative to other architectures, but that would just be
1375 another #ifdef in the calls. */
Denys Vlasenko2d1e90f2012-02-25 02:46:14 +01001376# define arg0_offset PT_GPR3
1377# define arg1_offset PT_ORIGGPR2
1378# define restore_arg0(tcp, state, val) ((void) (state), 0)
1379# define restore_arg1(tcp, state, val) ((void) (state), 0)
1380# define arg0_index 1
1381# define arg1_index 0
1382# elif defined(ALPHA) || defined(MIPS)
1383# define arg0_offset REG_A0
1384# define arg1_offset (REG_A0+1)
1385# elif defined(AVR32)
1386# define arg0_offset (REG_R12)
1387# define arg1_offset (REG_R11)
1388# elif defined(POWERPC)
1389# define arg0_offset (sizeof(unsigned long)*PT_R3)
1390# define arg1_offset (sizeof(unsigned long)*PT_R4)
1391# define restore_arg0(tcp, state, val) ((void) (state), 0)
1392# elif defined(HPPA)
1393# define arg0_offset PT_GR26
1394# define arg1_offset (PT_GR26-4)
1395# elif defined(X86_64)
1396# define arg0_offset ((long)(8*(current_personality ? RBX : RDI)))
1397# define arg1_offset ((long)(8*(current_personality ? RCX : RSI)))
1398# elif defined(SH)
1399# define arg0_offset (4*(REG_REG0+4))
1400# define arg1_offset (4*(REG_REG0+5))
1401# elif defined(SH64)
1402 /* ABI defines arg0 & 1 in r2 & r3 */
1403# define arg0_offset (REG_OFFSET+16)
1404# define arg1_offset (REG_OFFSET+24)
1405# define restore_arg0(tcp, state, val) 0
1406# elif defined CRISV10 || defined CRISV32
1407# define arg0_offset (4*PT_R11)
1408# define arg1_offset (4*PT_ORIG_R10)
1409# define restore_arg0(tcp, state, val) 0
1410# define restore_arg1(tcp, state, val) 0
1411# define arg0_index 1
1412# define arg1_index 0
1413# else
1414# define arg0_offset 0
1415# define arg1_offset 4
1416# if defined ARM
1417# define restore_arg0(tcp, state, val) 0
1418# endif
1419# endif
Roland McGrathd81f1d92003-01-09 06:53:34 +00001420
1421typedef int arg_setup_state;
1422
Denys Vlasenko2d1e90f2012-02-25 02:46:14 +01001423# define arg_setup(tcp, state) (0)
1424# define arg_finish_change(tcp, state) 0
1425# define get_arg0(tcp, cookie, valp) (upeek((tcp), arg0_offset, (valp)))
1426# define get_arg1(tcp, cookie, valp) (upeek((tcp), arg1_offset, (valp)))
Roland McGrathd81f1d92003-01-09 06:53:34 +00001427
1428static int
Denys Vlasenko12014262011-05-30 14:00:14 +02001429set_arg0(struct tcb *tcp, void *cookie, long val)
Roland McGrathd81f1d92003-01-09 06:53:34 +00001430{
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001431 return ptrace(PTRACE_POKEUSER, tcp->pid, (char*)arg0_offset, val);
Roland McGrathd81f1d92003-01-09 06:53:34 +00001432}
1433
1434static int
Denys Vlasenko12014262011-05-30 14:00:14 +02001435set_arg1(struct tcb *tcp, void *cookie, long val)
Roland McGrathd81f1d92003-01-09 06:53:34 +00001436{
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001437 return ptrace(PTRACE_POKEUSER, tcp->pid, (char*)arg1_offset, val);
Roland McGrathd81f1d92003-01-09 06:53:34 +00001438}
1439
Denys Vlasenko2d1e90f2012-02-25 02:46:14 +01001440#endif /* architectures */
Roland McGrathd81f1d92003-01-09 06:53:34 +00001441
Denys Vlasenko2d1e90f2012-02-25 02:46:14 +01001442#ifndef restore_arg0
1443# define restore_arg0(tcp, state, val) set_arg0((tcp), (state), (val))
1444#endif
1445#ifndef restore_arg1
1446# define restore_arg1(tcp, state, val) set_arg1((tcp), (state), (val))
1447#endif
Roland McGrathd81f1d92003-01-09 06:53:34 +00001448
Denys Vlasenko2d1e90f2012-02-25 02:46:14 +01001449#ifndef arg0_index
1450# define arg0_index 0
1451# define arg1_index 1
1452#endif
Roland McGrath90d0afd2004-03-01 21:05:16 +00001453
Roland McGrathd81f1d92003-01-09 06:53:34 +00001454int
Denys Vlasenko418d66a2009-01-17 01:52:54 +00001455setbpt(struct tcb *tcp)
Roland McGrathd81f1d92003-01-09 06:53:34 +00001456{
Roland McGrath3291ef22008-05-20 00:34:34 +00001457 static int clone_scno[SUPPORTED_PERSONALITIES] = { SYS_clone };
Roland McGrathd81f1d92003-01-09 06:53:34 +00001458 arg_setup_state state;
1459
1460 if (tcp->flags & TCB_BPTSET) {
1461 fprintf(stderr, "PANIC: TCB already set in pid %u\n", tcp->pid);
1462 return -1;
1463 }
1464
Roland McGrath3291ef22008-05-20 00:34:34 +00001465 /*
1466 * It's a silly kludge to initialize this with a search at runtime.
1467 * But it's better than maintaining another magic thing in the
1468 * godforsaken tables.
1469 */
1470 if (clone_scno[current_personality] == 0) {
1471 int i;
1472 for (i = 0; i < nsyscalls; ++i)
1473 if (sysent[i].sys_func == sys_clone) {
1474 clone_scno[current_personality] = i;
1475 break;
1476 }
1477 }
1478
Dmitry V. Levin0c661512012-02-20 21:17:58 +00001479 if (sysent[tcp->scno].sys_func == sys_fork ||
1480 sysent[tcp->scno].sys_func == sys_vfork) {
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001481 if (arg_setup(tcp, &state) < 0
1482 || get_arg0(tcp, &state, &tcp->inst[0]) < 0
1483 || get_arg1(tcp, &state, &tcp->inst[1]) < 0
Roland McGrath3291ef22008-05-20 00:34:34 +00001484 || change_syscall(tcp, clone_scno[current_personality]) < 0
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001485 || set_arg0(tcp, &state, CLONE_PTRACE|SIGCHLD) < 0
1486 || set_arg1(tcp, &state, 0) < 0
1487 || arg_finish_change(tcp, &state) < 0)
Roland McGrathd81f1d92003-01-09 06:53:34 +00001488 return -1;
Roland McGrathc9dc3c12004-03-01 20:57:09 +00001489 tcp->u_arg[arg0_index] = CLONE_PTRACE|SIGCHLD;
1490 tcp->u_arg[arg1_index] = 0;
Roland McGrathd81f1d92003-01-09 06:53:34 +00001491 tcp->flags |= TCB_BPTSET;
1492 return 0;
Dmitry V. Levin0c661512012-02-20 21:17:58 +00001493 }
Roland McGrathd81f1d92003-01-09 06:53:34 +00001494
Dmitry V. Levin0c661512012-02-20 21:17:58 +00001495 if (sysent[tcp->scno].sys_func == sys_clone) {
Jan Kratochvil8fc95752008-08-06 21:43:35 +00001496 /* ia64 calls directly `clone (CLONE_VFORK | CLONE_VM)'
Dmitry V. Levin0c661512012-02-20 21:17:58 +00001497 contrary to x86 vfork above. Even on x86 we turn the
Jan Kratochvil8fc95752008-08-06 21:43:35 +00001498 vfork semantics into plain fork - each application must not
1499 depend on the vfork specifics according to POSIX. We would
1500 hang waiting for the parent resume otherwise. We need to
1501 clear also CLONE_VM but only in the CLONE_VFORK case as
1502 otherwise we would break pthread_create. */
1503
Denys Vlasenkoc133bf02011-06-23 21:57:54 +02001504 long new_arg0 = (tcp->u_arg[arg0_index] | CLONE_PTRACE);
1505 if (new_arg0 & CLONE_VFORK)
1506 new_arg0 &= ~(unsigned long)(CLONE_VFORK | CLONE_VM);
1507 if (arg_setup(tcp, &state) < 0
1508 || set_arg0(tcp, &state, new_arg0) < 0
1509 || arg_finish_change(tcp, &state) < 0)
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00001510 return -1;
Roland McGrathd81f1d92003-01-09 06:53:34 +00001511 tcp->flags |= TCB_BPTSET;
Roland McGrathc9dc3c12004-03-01 20:57:09 +00001512 tcp->inst[0] = tcp->u_arg[arg0_index];
1513 tcp->inst[1] = tcp->u_arg[arg1_index];
Roland McGrathd81f1d92003-01-09 06:53:34 +00001514 return 0;
Roland McGrathd81f1d92003-01-09 06:53:34 +00001515 }
1516
Dmitry V. Levin0c661512012-02-20 21:17:58 +00001517 fprintf(stderr, "PANIC: setbpt for syscall %ld on %u???\n",
1518 tcp->scno, tcp->pid);
Roland McGrathd81f1d92003-01-09 06:53:34 +00001519 return -1;
1520}
1521
1522int
Denys Vlasenko12014262011-05-30 14:00:14 +02001523clearbpt(struct tcb *tcp)
Roland McGrathd81f1d92003-01-09 06:53:34 +00001524{
1525 arg_setup_state state;
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001526 if (arg_setup(tcp, &state) < 0
1527 || restore_arg0(tcp, &state, tcp->inst[0]) < 0
1528 || restore_arg1(tcp, &state, tcp->inst[1]) < 0
1529 || arg_finish_change(tcp, &state))
Denys Vlasenkoc133bf02011-06-23 21:57:54 +02001530 if (errno != ESRCH)
1531 return -1;
Roland McGrathd81f1d92003-01-09 06:53:34 +00001532 tcp->flags &= ~TCB_BPTSET;
1533 return 0;
1534}