blob: f27acdf6c35387c04ae19b702cde4089caf401ec [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;
Denys Vlasenko29456392012-01-28 02:49:48 +0100792 else if (errno != EINVAL) /* EINVAL is seen if process is gone */
793 /* strange... */
Denys Vlasenko3af224c2012-01-28 01:46:33 +0100794 perror("process_vm_readv");
795 goto vm_readv_didnt_work;
796 }
797 return r;
798 }
799 vm_readv_didnt_work:
800
Denys Vlasenkoa47e6b92012-01-21 04:01:56 +0100801 started = 0;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000802 if (addr & (sizeof(long) - 1)) {
803 /* addr not a multiple of sizeof(long) */
804 n = addr - (addr & -sizeof(long)); /* residue */
805 addr &= -sizeof(long); /* residue */
Roland McGratheb9e2e82009-06-02 16:49:22 -0700806 errno = 0;
807 u.val = ptrace(PTRACE_PEEKDATA, pid, (char *) addr, 0);
808 if (errno) {
Roland McGratheb9e2e82009-06-02 16:49:22 -0700809 /* But if not started, we had a bogus address. */
810 if (addr != 0 && errno != EIO && errno != ESRCH)
Denys Vlasenko4c65c442012-03-08 11:54:10 +0100811 perror_msg("umoven: PTRACE_PEEKDATA pid:%d @0x%lx", pid, addr);
Roland McGratheb9e2e82009-06-02 16:49:22 -0700812 return -1;
813 }
Wichert Akkerman5daa0281999-03-15 19:49:42 +0000814 started = 1;
Denys Vlasenkoa47e6b92012-01-21 04:01:56 +0100815 m = MIN(sizeof(long) - n, len);
816 memcpy(laddr, &u.x[n], m);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000817 addr += sizeof(long), laddr += m, len -= m;
818 }
819 while (len) {
Roland McGratheb9e2e82009-06-02 16:49:22 -0700820 errno = 0;
821 u.val = ptrace(PTRACE_PEEKDATA, pid, (char *) addr, 0);
822 if (errno) {
823 if (started && (errno==EPERM || errno==EIO)) {
824 /* Ran into 'end of memory' - stupid "printpath" */
825 return 0;
826 }
827 if (addr != 0 && errno != EIO && errno != ESRCH)
Denys Vlasenko4c65c442012-03-08 11:54:10 +0100828 perror_msg("umoven: PTRACE_PEEKDATA pid:%d @0x%lx", pid, addr);
Roland McGratheb9e2e82009-06-02 16:49:22 -0700829 return -1;
830 }
Wichert Akkerman5daa0281999-03-15 19:49:42 +0000831 started = 1;
Denys Vlasenkoa47e6b92012-01-21 04:01:56 +0100832 m = MIN(sizeof(long), len);
833 memcpy(laddr, u.x, m);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000834 addr += sizeof(long), laddr += m, len -= m;
835 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000836
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000837 return 0;
838}
839
840/*
Denys Vlasenko6cecba52012-01-20 11:56:00 +0100841 * Like `umove' but make the additional effort of looking
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000842 * for a terminating zero byte.
Denys Vlasenko6cecba52012-01-20 11:56:00 +0100843 *
844 * Returns < 0 on error, > 0 if NUL was seen,
845 * (TODO if useful: return count of bytes including NUL),
846 * else 0 if len bytes were read but no NUL byte seen.
847 *
848 * Note: there is no guarantee we won't overwrite some bytes
849 * in laddr[] _after_ terminating NUL (but, of course,
850 * we never write past laddr[len-1]).
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000851 */
852int
Denys Vlasenkoef2fbf82009-01-06 21:45:06 +0000853umovestr(struct tcb *tcp, long addr, int len, char *laddr)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000854{
Denys Vlasenkoa47e6b92012-01-21 04:01:56 +0100855 int started;
Roland McGratheb9e2e82009-06-02 16:49:22 -0700856 int pid = tcp->pid;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000857 int i, n, m;
858 union {
859 long val;
860 char x[sizeof(long)];
861 } u;
862
Dmitry V. Levin856c7ed2011-12-26 20:12:02 +0000863#if SUPPORTED_PERSONALITIES > 1
Denys Vlasenko9fd4f962012-03-19 09:36:42 +0100864 if (current_wordsize < sizeof(addr))
865 addr &= (1ul << 8 * current_wordsize) - 1;
Dmitry V. Levin856c7ed2011-12-26 20:12:02 +0000866#endif
867
Denys Vlasenko3af224c2012-01-28 01:46:33 +0100868 if (!process_vm_readv_not_supported) {
869 struct iovec local[1], remote[1];
870
871 local[0].iov_base = laddr;
872 remote[0].iov_base = (void*)addr;
873
874 while (len > 0) {
875 int end_in_page;
876 int r;
877 int chunk_len;
878
879 /* Don't read kilobytes: most strings are short */
880 chunk_len = len;
881 if (chunk_len > 256)
882 chunk_len = 256;
883 /* Don't cross pages. I guess otherwise we can get EFAULT
884 * and fail to notice that terminating NUL lies
885 * in the existing (first) page.
886 * (I hope there aren't arches with pages < 4K)
887 */
888 end_in_page = ((addr + chunk_len) & 4095);
889 r = chunk_len - end_in_page;
890 if (r > 0) /* if chunk_len > end_in_page */
891 chunk_len = r; /* chunk_len -= end_in_page */
892
893 local[0].iov_len = remote[0].iov_len = chunk_len;
894 r = process_vm_readv(pid,
895 local, 1,
896 remote, 1,
897 /*flags:*/ 0
898 );
899 if (r < 0) {
900 if (errno == ENOSYS)
901 process_vm_readv_not_supported = 1;
Denys Vlasenko29456392012-01-28 02:49:48 +0100902 else if (errno != EINVAL) /* EINVAL is seen if process is gone */
903 /* strange... */
Denys Vlasenko3af224c2012-01-28 01:46:33 +0100904 perror("process_vm_readv");
905 goto vm_readv_didnt_work;
906 }
907 if (memchr(local[0].iov_base, '\0', r))
908 return 1;
909 local[0].iov_base += r;
910 remote[0].iov_base += r;
911 len -= r;
912 }
913 return 0;
914 }
915 vm_readv_didnt_work:
916
Denys Vlasenkoa47e6b92012-01-21 04:01:56 +0100917 started = 0;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000918 if (addr & (sizeof(long) - 1)) {
919 /* addr not a multiple of sizeof(long) */
920 n = addr - (addr & -sizeof(long)); /* residue */
921 addr &= -sizeof(long); /* residue */
Roland McGratheb9e2e82009-06-02 16:49:22 -0700922 errno = 0;
923 u.val = ptrace(PTRACE_PEEKDATA, pid, (char *)addr, 0);
924 if (errno) {
Roland McGratheb9e2e82009-06-02 16:49:22 -0700925 if (addr != 0 && errno != EIO && errno != ESRCH)
Denys Vlasenko4c65c442012-03-08 11:54:10 +0100926 perror_msg("umovestr: PTRACE_PEEKDATA pid:%d @0x%lx", pid, addr);
Roland McGratheb9e2e82009-06-02 16:49:22 -0700927 return -1;
928 }
Wichert Akkerman5daa0281999-03-15 19:49:42 +0000929 started = 1;
Denys Vlasenkoa47e6b92012-01-21 04:01:56 +0100930 m = MIN(sizeof(long) - n, len);
931 memcpy(laddr, &u.x[n], m);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000932 while (n & (sizeof(long) - 1))
933 if (u.x[n++] == '\0')
Denys Vlasenko6cecba52012-01-20 11:56:00 +0100934 return 1;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000935 addr += sizeof(long), laddr += m, len -= m;
936 }
937 while (len) {
Roland McGratheb9e2e82009-06-02 16:49:22 -0700938 errno = 0;
939 u.val = ptrace(PTRACE_PEEKDATA, pid, (char *)addr, 0);
940 if (errno) {
941 if (started && (errno==EPERM || errno==EIO)) {
942 /* Ran into 'end of memory' - stupid "printpath" */
943 return 0;
944 }
945 if (addr != 0 && errno != EIO && errno != ESRCH)
Denys Vlasenko4c65c442012-03-08 11:54:10 +0100946 perror_msg("umovestr: PTRACE_PEEKDATA pid:%d @0x%lx", pid, addr);
Roland McGratheb9e2e82009-06-02 16:49:22 -0700947 return -1;
948 }
Wichert Akkerman5daa0281999-03-15 19:49:42 +0000949 started = 1;
Denys Vlasenkoa47e6b92012-01-21 04:01:56 +0100950 m = MIN(sizeof(long), len);
951 memcpy(laddr, u.x, m);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000952 for (i = 0; i < sizeof(long); i++)
953 if (u.x[i] == '\0')
Denys Vlasenko6cecba52012-01-20 11:56:00 +0100954 return 1;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000955 addr += sizeof(long), laddr += m, len -= m;
956 }
John Hughesaa09c6b2001-05-15 14:53:43 +0000957 return 0;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000958}
959
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000960int
Denys Vlasenko12014262011-05-30 14:00:14 +0200961upeek(struct tcb *tcp, long off, long *res)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000962{
963 long val;
964
Roland McGratheb9e2e82009-06-02 16:49:22 -0700965 errno = 0;
Denys Vlasenko114aefd2012-03-08 12:13:44 +0100966 val = ptrace(PTRACE_PEEKUSER, tcp->pid, (char *) off, 0);
Roland McGratheb9e2e82009-06-02 16:49:22 -0700967 if (val == -1 && errno) {
968 if (errno != ESRCH) {
Denys Vlasenko4c65c442012-03-08 11:54:10 +0100969 perror_msg("upeek: PTRACE_PEEKUSER pid:%d @0x%lx)", tcp->pid, off);
Roland McGratheb9e2e82009-06-02 16:49:22 -0700970 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000971 return -1;
Roland McGratheb9e2e82009-06-02 16:49:22 -0700972 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000973 *res = val;
974 return 0;
975}
976
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000977void
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +0000978printcall(struct tcb *tcp)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000979{
Roland McGrath7a918832005-02-02 20:55:23 +0000980#define PRINTBADPC tprintf(sizeof(long) == 4 ? "[????????] " : \
981 sizeof(long) == 8 ? "[????????????????] " : \
982 NULL /* crash */)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000983
Denys Vlasenko2d1e90f2012-02-25 02:46:14 +0100984#if defined(I386)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000985 long eip;
986
Denys Vlasenko932fc7d2008-12-16 18:18:40 +0000987 if (upeek(tcp, 4*EIP, &eip) < 0) {
Roland McGrath7a918832005-02-02 20:55:23 +0000988 PRINTBADPC;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000989 return;
990 }
991 tprintf("[%08lx] ", eip);
Denys Vlasenko2d1e90f2012-02-25 02:46:14 +0100992#elif defined(S390) || defined(S390X)
Denys Vlasenkoadedb512008-12-30 18:47:55 +0000993 long psw;
Denys Vlasenkob63256e2011-06-07 12:13:24 +0200994 if (upeek(tcp, PT_PSWADDR, &psw) < 0) {
Denys Vlasenkoadedb512008-12-30 18:47:55 +0000995 PRINTBADPC;
996 return;
997 }
Denys Vlasenko2d1e90f2012-02-25 02:46:14 +0100998# ifdef S390
Denys Vlasenkoadedb512008-12-30 18:47:55 +0000999 tprintf("[%08lx] ", psw);
Denys Vlasenko2d1e90f2012-02-25 02:46:14 +01001000# elif S390X
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001001 tprintf("[%16lx] ", psw);
Denys Vlasenko2d1e90f2012-02-25 02:46:14 +01001002# endif
Roland McGratheac26fc2005-02-02 02:48:53 +00001003
H.J. Lu35be5812012-04-16 13:00:01 +02001004#elif defined(X86_64) || defined(X32)
Michal Ludvig0e035502002-09-23 15:41:01 +00001005 long rip;
1006
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001007 if (upeek(tcp, 8*RIP, &rip) < 0) {
Roland McGrath7a918832005-02-02 20:55:23 +00001008 PRINTBADPC;
Michal Ludvig0e035502002-09-23 15:41:01 +00001009 return;
1010 }
1011 tprintf("[%16lx] ", rip);
Denys Vlasenko2d1e90f2012-02-25 02:46:14 +01001012#elif defined(IA64)
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00001013 long ip;
1014
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001015 if (upeek(tcp, PT_B0, &ip) < 0) {
Roland McGrath7a918832005-02-02 20:55:23 +00001016 PRINTBADPC;
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00001017 return;
1018 }
1019 tprintf("[%08lx] ", ip);
Denys Vlasenko2d1e90f2012-02-25 02:46:14 +01001020#elif defined(POWERPC)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001021 long pc;
1022
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001023 if (upeek(tcp, sizeof(unsigned long)*PT_NIP, &pc) < 0) {
Andreas Schwabd69fa492010-07-12 21:39:57 +02001024 PRINTBADPC;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001025 return;
1026 }
Denys Vlasenko2d1e90f2012-02-25 02:46:14 +01001027# ifdef POWERPC64
Andreas Schwabd69fa492010-07-12 21:39:57 +02001028 tprintf("[%016lx] ", pc);
Denys Vlasenko2d1e90f2012-02-25 02:46:14 +01001029# else
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001030 tprintf("[%08lx] ", pc);
Denys Vlasenko2d1e90f2012-02-25 02:46:14 +01001031# endif
1032#elif defined(M68K)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001033 long pc;
1034
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001035 if (upeek(tcp, 4*PT_PC, &pc) < 0) {
Denys Vlasenko60fe8c12011-09-01 10:00:28 +02001036 tprints("[????????] ");
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001037 return;
1038 }
1039 tprintf("[%08lx] ", pc);
Denys Vlasenko2d1e90f2012-02-25 02:46:14 +01001040#elif defined(ALPHA)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001041 long pc;
1042
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001043 if (upeek(tcp, REG_PC, &pc) < 0) {
Denys Vlasenko60fe8c12011-09-01 10:00:28 +02001044 tprints("[????????????????] ");
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001045 return;
1046 }
1047 tprintf("[%08lx] ", pc);
Denys Vlasenko2d1e90f2012-02-25 02:46:14 +01001048#elif defined(SPARC) || defined(SPARC64)
Mike Frysinger8566c502009-10-12 11:05:14 -04001049 struct pt_regs regs;
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001050 if (ptrace(PTRACE_GETREGS, tcp->pid, (char *)&regs, 0) < 0) {
Roland McGrath7a918832005-02-02 20:55:23 +00001051 PRINTBADPC;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001052 return;
1053 }
Denys Vlasenko2d1e90f2012-02-25 02:46:14 +01001054# if defined(SPARC64)
Mike Frysinger8566c502009-10-12 11:05:14 -04001055 tprintf("[%08lx] ", regs.tpc);
Denys Vlasenko2d1e90f2012-02-25 02:46:14 +01001056# else
Mike Frysinger8566c502009-10-12 11:05:14 -04001057 tprintf("[%08lx] ", regs.pc);
Denys Vlasenko2d1e90f2012-02-25 02:46:14 +01001058# endif
1059#elif defined(HPPA)
Wichert Akkermanc1652e22001-03-27 12:17:16 +00001060 long pc;
1061
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001062 if (upeek(tcp, PT_IAOQ0, &pc) < 0) {
Denys Vlasenko60fe8c12011-09-01 10:00:28 +02001063 tprints("[????????] ");
Wichert Akkermanc1652e22001-03-27 12:17:16 +00001064 return;
1065 }
1066 tprintf("[%08lx] ", pc);
Denys Vlasenko2d1e90f2012-02-25 02:46:14 +01001067#elif defined(MIPS)
Wichert Akkerman75c422b2001-04-10 10:22:50 +00001068 long pc;
1069
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001070 if (upeek(tcp, REG_EPC, &pc) < 0) {
Denys Vlasenko60fe8c12011-09-01 10:00:28 +02001071 tprints("[????????] ");
Wichert Akkerman75c422b2001-04-10 10:22:50 +00001072 return;
1073 }
1074 tprintf("[%08lx] ", pc);
Denys Vlasenko2d1e90f2012-02-25 02:46:14 +01001075#elif defined(SH)
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001076 long pc;
Wichert Akkermanccef6372002-05-01 16:39:22 +00001077
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001078 if (upeek(tcp, 4*REG_PC, &pc) < 0) {
Denys Vlasenko60fe8c12011-09-01 10:00:28 +02001079 tprints("[????????] ");
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001080 return;
1081 }
1082 tprintf("[%08lx] ", pc);
Denys Vlasenko2d1e90f2012-02-25 02:46:14 +01001083#elif defined(SH64)
Roland McGrathe1e584b2003-06-02 19:18:58 +00001084 long pc;
1085
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001086 if (upeek(tcp, REG_PC, &pc) < 0) {
Denys Vlasenko60fe8c12011-09-01 10:00:28 +02001087 tprints("[????????????????] ");
Roland McGrathe1e584b2003-06-02 19:18:58 +00001088 return;
1089 }
1090 tprintf("[%08lx] ", pc);
Denys Vlasenko2d1e90f2012-02-25 02:46:14 +01001091#elif defined(ARM)
Roland McGrathef388682003-06-03 23:28:59 +00001092 long pc;
Roland McGrathe1e584b2003-06-02 19:18:58 +00001093
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001094 if (upeek(tcp, 4*15, &pc) < 0) {
Roland McGrath7a918832005-02-02 20:55:23 +00001095 PRINTBADPC;
Roland McGrathef388682003-06-03 23:28:59 +00001096 return;
1097 }
1098 tprintf("[%08lx] ", pc);
Denys Vlasenko2d1e90f2012-02-25 02:46:14 +01001099#elif defined(AVR32)
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00001100 long pc;
1101
1102 if (upeek(tcp, REG_PC, &pc) < 0) {
Denys Vlasenko60fe8c12011-09-01 10:00:28 +02001103 tprints("[????????] ");
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00001104 return;
1105 }
1106 tprintf("[%08lx] ", pc);
Denys Vlasenko2d1e90f2012-02-25 02:46:14 +01001107#elif defined(BFIN)
Dmitry V. Levin87ea1f42008-11-10 22:21:41 +00001108 long pc;
1109
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001110 if (upeek(tcp, PT_PC, &pc) < 0) {
Dmitry V. Levin87ea1f42008-11-10 22:21:41 +00001111 PRINTBADPC;
1112 return;
1113 }
1114 tprintf("[%08lx] ", pc);
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001115#elif defined(CRISV10)
1116 long pc;
1117
Edgar E. Iglesiaseeb9ce32009-10-05 14:41:02 +00001118 if (upeek(tcp, 4*PT_IRP, &pc) < 0) {
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001119 PRINTBADPC;
1120 return;
1121 }
1122 tprintf("[%08lx] ", pc);
1123#elif defined(CRISV32)
1124 long pc;
1125
Edgar E. Iglesiaseeb9ce32009-10-05 14:41:02 +00001126 if (upeek(tcp, 4*PT_ERP, &pc) < 0) {
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001127 PRINTBADPC;
1128 return;
1129 }
1130 tprintf("[%08lx] ", pc);
Denys Vlasenko2d1e90f2012-02-25 02:46:14 +01001131#endif /* architecture */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001132}
1133
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001134/*
1135 * These #if's are huge, please indent them correctly.
1136 * It's easy to get confused otherwise.
1137 */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001138
Denys Vlasenko2d1e90f2012-02-25 02:46:14 +01001139#include "syscall.h"
Roland McGrath3291ef22008-05-20 00:34:34 +00001140
Denys Vlasenko2d1e90f2012-02-25 02:46:14 +01001141#ifndef CLONE_PTRACE
1142# define CLONE_PTRACE 0x00002000
1143#endif
1144#ifndef CLONE_VFORK
1145# define CLONE_VFORK 0x00004000
1146#endif
1147#ifndef CLONE_VM
1148# define CLONE_VM 0x00000100
1149#endif
Roland McGrathd81f1d92003-01-09 06:53:34 +00001150
Denys Vlasenko081533c2012-03-17 02:17:51 +01001151static int
1152change_syscall(struct tcb *tcp, int new)
1153{
1154#if defined(I386)
1155 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(ORIG_EAX * 4), new) < 0)
1156 return -1;
1157 return 0;
H.J. Lu35be5812012-04-16 13:00:01 +02001158#elif defined(X86_64) || defined(X32)
Denys Vlasenko081533c2012-03-17 02:17:51 +01001159 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(ORIG_RAX * 8), new) < 0)
1160 return -1;
1161 return 0;
1162#elif defined(POWERPC)
1163 if (ptrace(PTRACE_POKEUSER, tcp->pid,
1164 (char*)(sizeof(unsigned long)*PT_R0), new) < 0)
1165 return -1;
1166 return 0;
1167#elif defined(S390) || defined(S390X)
1168 /* s390 linux after 2.4.7 has a hook in entry.S to allow this */
1169 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(PT_GPR2), new) < 0)
1170 return -1;
1171 return 0;
1172#elif defined(M68K)
1173 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(4*PT_ORIG_D0), new) < 0)
1174 return -1;
1175 return 0;
1176#elif defined(SPARC) || defined(SPARC64)
1177 struct pt_regs regs;
1178 if (ptrace(PTRACE_GETREGS, tcp->pid, (char*)&regs, 0) < 0)
1179 return -1;
1180 regs.u_regs[U_REG_G1] = new;
1181 if (ptrace(PTRACE_SETREGS, tcp->pid, (char*)&regs, 0) < 0)
1182 return -1;
1183 return 0;
1184#elif defined(MIPS)
1185 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(REG_V0), new) < 0)
1186 return -1;
1187 return 0;
1188#elif defined(ALPHA)
1189 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(REG_A3), new) < 0)
1190 return -1;
1191 return 0;
1192#elif defined(AVR32)
1193 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(REG_R8), new) < 0)
1194 return -1;
1195 return 0;
1196#elif defined(BFIN)
1197 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(REG_P0), new) < 0)
1198 return -1;
1199 return 0;
1200#elif defined(IA64)
1201 if (ia32) {
1202 switch (new) {
1203 case 2:
1204 break; /* x86 SYS_fork */
1205 case SYS_clone:
1206 new = 120;
1207 break;
1208 default:
1209 fprintf(stderr, "%s: unexpected syscall %d\n",
1210 __FUNCTION__, new);
1211 return -1;
1212 }
1213 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(PT_R1), new) < 0)
1214 return -1;
1215 } else if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(PT_R15), new) < 0)
1216 return -1;
1217 return 0;
1218#elif defined(HPPA)
1219 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(PT_GR20), new) < 0)
1220 return -1;
1221 return 0;
1222#elif defined(SH)
1223 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(4*(REG_REG0+3)), new) < 0)
1224 return -1;
1225 return 0;
1226#elif defined(SH64)
1227 /* Top half of reg encodes the no. of args n as 0x1n.
1228 Assume 0 args as kernel never actually checks... */
1229 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(REG_SYSCALL),
1230 0x100000 | new) < 0)
1231 return -1;
1232 return 0;
1233#elif defined(CRISV10) || defined(CRISV32)
1234 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(4*PT_R9), new) < 0)
1235 return -1;
1236 return 0;
1237#elif defined(ARM)
1238 /* Some kernels support this, some (pre-2.6.16 or so) don't. */
1239# ifndef PTRACE_SET_SYSCALL
1240# define PTRACE_SET_SYSCALL 23
1241# endif
1242 if (ptrace(PTRACE_SET_SYSCALL, tcp->pid, 0, new & 0xffff) != 0)
1243 return -1;
1244 return 0;
1245#elif defined(TILE)
1246 if (ptrace(PTRACE_POKEUSER, tcp->pid,
1247 (char*)PTREGS_OFFSET_REG(0),
1248 new) != 0)
1249 return -1;
1250 return 0;
1251#elif defined(MICROBLAZE)
1252 if (ptrace(PTRACE_POKEUSER, tcp->pid, (char*)(PT_GPR(0)), new) < 0)
1253 return -1;
1254 return 0;
1255#else
1256#warning Do not know how to handle change_syscall for this architecture
1257#endif /* architecture */
1258 return -1;
1259}
1260
Denys Vlasenko2d1e90f2012-02-25 02:46:14 +01001261#ifdef IA64
Roland McGrathd81f1d92003-01-09 06:53:34 +00001262
1263typedef unsigned long *arg_setup_state;
1264
1265static int
1266arg_setup(struct tcb *tcp, arg_setup_state *state)
1267{
Jan Kratochvil1f942712008-08-06 21:38:52 +00001268 unsigned long cfm, sof, sol;
1269 long bsp;
Roland McGrathd81f1d92003-01-09 06:53:34 +00001270
Jan Kratochvil1f942712008-08-06 21:38:52 +00001271 if (ia32) {
1272 /* Satisfy a false GCC warning. */
1273 *state = NULL;
Roland McGrath08267b82004-02-20 22:56:43 +00001274 return 0;
Jan Kratochvil1f942712008-08-06 21:38:52 +00001275 }
Roland McGrath08267b82004-02-20 22:56:43 +00001276
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001277 if (upeek(tcp, PT_AR_BSP, &bsp) < 0)
Roland McGrathd81f1d92003-01-09 06:53:34 +00001278 return -1;
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001279 if (upeek(tcp, PT_CFM, (long *) &cfm) < 0)
Roland McGrathd81f1d92003-01-09 06:53:34 +00001280 return -1;
1281
1282 sof = (cfm >> 0) & 0x7f;
1283 sol = (cfm >> 7) & 0x7f;
Jan Kratochvil1f942712008-08-06 21:38:52 +00001284 bsp = (long) ia64_rse_skip_regs((unsigned long *) bsp, -sof + sol);
Roland McGrathd81f1d92003-01-09 06:53:34 +00001285
Jan Kratochvil1f942712008-08-06 21:38:52 +00001286 *state = (unsigned long *) bsp;
Roland McGrathd81f1d92003-01-09 06:53:34 +00001287 return 0;
1288}
1289
Denys Vlasenko2d1e90f2012-02-25 02:46:14 +01001290# define arg_finish_change(tcp, state) 0
Roland McGrathd81f1d92003-01-09 06:53:34 +00001291
Roland McGrathd81f1d92003-01-09 06:53:34 +00001292static int
Denys Vlasenko12014262011-05-30 14:00:14 +02001293get_arg0(struct tcb *tcp, arg_setup_state *state, long *valp)
Roland McGrathd81f1d92003-01-09 06:53:34 +00001294{
Roland McGrath08267b82004-02-20 22:56:43 +00001295 int ret;
1296
1297 if (ia32)
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001298 ret = upeek(tcp, PT_R11, valp);
Roland McGrath08267b82004-02-20 22:56:43 +00001299 else
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001300 ret = umoven(tcp,
Roland McGrath08267b82004-02-20 22:56:43 +00001301 (unsigned long) ia64_rse_skip_regs(*state, 0),
1302 sizeof(long), (void *) valp);
1303 return ret;
Roland McGrathd81f1d92003-01-09 06:53:34 +00001304}
1305
1306static int
Denys Vlasenko12014262011-05-30 14:00:14 +02001307get_arg1(struct tcb *tcp, arg_setup_state *state, long *valp)
Roland McGrathd81f1d92003-01-09 06:53:34 +00001308{
Roland McGrath08267b82004-02-20 22:56:43 +00001309 int ret;
1310
1311 if (ia32)
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001312 ret = upeek(tcp, PT_R9, valp);
Roland McGrath08267b82004-02-20 22:56:43 +00001313 else
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001314 ret = umoven(tcp,
Roland McGrath08267b82004-02-20 22:56:43 +00001315 (unsigned long) ia64_rse_skip_regs(*state, 1),
1316 sizeof(long), (void *) valp);
1317 return ret;
Roland McGrathd81f1d92003-01-09 06:53:34 +00001318}
Roland McGrathd81f1d92003-01-09 06:53:34 +00001319
1320static int
Denys Vlasenko12014262011-05-30 14:00:14 +02001321set_arg0(struct tcb *tcp, arg_setup_state *state, long val)
Roland McGrathd81f1d92003-01-09 06:53:34 +00001322{
Roland McGrath08267b82004-02-20 22:56:43 +00001323 int req = PTRACE_POKEDATA;
1324 void *ap;
1325
1326 if (ia32) {
1327 ap = (void *) (intptr_t) PT_R11; /* r11 == EBX */
1328 req = PTRACE_POKEUSER;
1329 } else
1330 ap = ia64_rse_skip_regs(*state, 0);
Roland McGratheb9e2e82009-06-02 16:49:22 -07001331 errno = 0;
1332 ptrace(req, tcp->pid, ap, val);
1333 return errno ? -1 : 0;
Roland McGrathd81f1d92003-01-09 06:53:34 +00001334}
1335
1336static int
Denys Vlasenko12014262011-05-30 14:00:14 +02001337set_arg1(struct tcb *tcp, arg_setup_state *state, long val)
Roland McGrathd81f1d92003-01-09 06:53:34 +00001338{
Roland McGrath08267b82004-02-20 22:56:43 +00001339 int req = PTRACE_POKEDATA;
1340 void *ap;
1341
1342 if (ia32) {
1343 ap = (void *) (intptr_t) PT_R9; /* r9 == ECX */
1344 req = PTRACE_POKEUSER;
1345 } else
1346 ap = ia64_rse_skip_regs(*state, 1);
Roland McGratheb9e2e82009-06-02 16:49:22 -07001347 errno = 0;
1348 ptrace(req, tcp->pid, ap, val);
1349 return errno ? -1 : 0;
Roland McGrathd81f1d92003-01-09 06:53:34 +00001350}
1351
Roland McGrathb659f872008-07-18 01:19:36 +00001352/* ia64 does not return the input arguments from functions (and syscalls)
1353 according to ia64 RSE (Register Stack Engine) behavior. */
1354
Denys Vlasenko2d1e90f2012-02-25 02:46:14 +01001355# define restore_arg0(tcp, state, val) ((void) (state), 0)
1356# define restore_arg1(tcp, state, val) ((void) (state), 0)
Roland McGrathb659f872008-07-18 01:19:36 +00001357
Denys Vlasenko2d1e90f2012-02-25 02:46:14 +01001358#elif defined(SPARC) || defined(SPARC64)
Roland McGrathd81f1d92003-01-09 06:53:34 +00001359
Mike Frysinger8566c502009-10-12 11:05:14 -04001360typedef struct pt_regs arg_setup_state;
Roland McGrathd81f1d92003-01-09 06:53:34 +00001361
Denys Vlasenko2d1e90f2012-02-25 02:46:14 +01001362# define arg_setup(tcp, state) \
1363 (ptrace(PTRACE_GETREGS, (tcp)->pid, (char *) (state), 0))
1364# define arg_finish_change(tcp, state) \
1365 (ptrace(PTRACE_SETREGS, (tcp)->pid, (char *) (state), 0))
Roland McGrathd81f1d92003-01-09 06:53:34 +00001366
Denys Vlasenko2d1e90f2012-02-25 02:46:14 +01001367# define get_arg0(tcp, state, valp) (*(valp) = (state)->u_regs[U_REG_O0], 0)
1368# define get_arg1(tcp, state, valp) (*(valp) = (state)->u_regs[U_REG_O1], 0)
1369# define set_arg0(tcp, state, val) ((state)->u_regs[U_REG_O0] = (val), 0)
1370# define set_arg1(tcp, state, val) ((state)->u_regs[U_REG_O1] = (val), 0)
1371# define restore_arg0(tcp, state, val) 0
Roland McGrathd81f1d92003-01-09 06:53:34 +00001372
Denys Vlasenko2d1e90f2012-02-25 02:46:14 +01001373#else /* other architectures */
Roland McGrathd81f1d92003-01-09 06:53:34 +00001374
Denys Vlasenko2d1e90f2012-02-25 02:46:14 +01001375# if defined S390 || defined S390X
Roland McGrath7b308222003-01-20 09:04:36 +00001376/* Note: this is only true for the `clone' system call, which handles
1377 arguments specially. We could as well say that its first two arguments
1378 are swapped relative to other architectures, but that would just be
1379 another #ifdef in the calls. */
Denys Vlasenko2d1e90f2012-02-25 02:46:14 +01001380# define arg0_offset PT_GPR3
1381# define arg1_offset PT_ORIGGPR2
1382# define restore_arg0(tcp, state, val) ((void) (state), 0)
1383# define restore_arg1(tcp, state, val) ((void) (state), 0)
1384# define arg0_index 1
1385# define arg1_index 0
1386# elif defined(ALPHA) || defined(MIPS)
1387# define arg0_offset REG_A0
1388# define arg1_offset (REG_A0+1)
1389# elif defined(AVR32)
1390# define arg0_offset (REG_R12)
1391# define arg1_offset (REG_R11)
1392# elif defined(POWERPC)
1393# define arg0_offset (sizeof(unsigned long)*PT_R3)
1394# define arg1_offset (sizeof(unsigned long)*PT_R4)
1395# define restore_arg0(tcp, state, val) ((void) (state), 0)
1396# elif defined(HPPA)
1397# define arg0_offset PT_GR26
1398# define arg1_offset (PT_GR26-4)
H.J. Lu35be5812012-04-16 13:00:01 +02001399# elif defined(X86_64) || defined(X32)
Denys Vlasenko2d1e90f2012-02-25 02:46:14 +01001400# define arg0_offset ((long)(8*(current_personality ? RBX : RDI)))
1401# define arg1_offset ((long)(8*(current_personality ? RCX : RSI)))
1402# elif defined(SH)
1403# define arg0_offset (4*(REG_REG0+4))
1404# define arg1_offset (4*(REG_REG0+5))
1405# elif defined(SH64)
1406 /* ABI defines arg0 & 1 in r2 & r3 */
1407# define arg0_offset (REG_OFFSET+16)
1408# define arg1_offset (REG_OFFSET+24)
1409# define restore_arg0(tcp, state, val) 0
1410# elif defined CRISV10 || defined CRISV32
1411# define arg0_offset (4*PT_R11)
1412# define arg1_offset (4*PT_ORIG_R10)
1413# define restore_arg0(tcp, state, val) 0
1414# define restore_arg1(tcp, state, val) 0
1415# define arg0_index 1
1416# define arg1_index 0
1417# else
1418# define arg0_offset 0
1419# define arg1_offset 4
1420# if defined ARM
1421# define restore_arg0(tcp, state, val) 0
1422# endif
1423# endif
Roland McGrathd81f1d92003-01-09 06:53:34 +00001424
1425typedef int arg_setup_state;
1426
Denys Vlasenko2d1e90f2012-02-25 02:46:14 +01001427# define arg_setup(tcp, state) (0)
1428# define arg_finish_change(tcp, state) 0
1429# define get_arg0(tcp, cookie, valp) (upeek((tcp), arg0_offset, (valp)))
1430# define get_arg1(tcp, cookie, valp) (upeek((tcp), arg1_offset, (valp)))
Roland McGrathd81f1d92003-01-09 06:53:34 +00001431
1432static int
Denys Vlasenko12014262011-05-30 14:00:14 +02001433set_arg0(struct tcb *tcp, void *cookie, long val)
Roland McGrathd81f1d92003-01-09 06:53:34 +00001434{
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001435 return ptrace(PTRACE_POKEUSER, tcp->pid, (char*)arg0_offset, val);
Roland McGrathd81f1d92003-01-09 06:53:34 +00001436}
1437
1438static int
Denys Vlasenko12014262011-05-30 14:00:14 +02001439set_arg1(struct tcb *tcp, void *cookie, long val)
Roland McGrathd81f1d92003-01-09 06:53:34 +00001440{
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001441 return ptrace(PTRACE_POKEUSER, tcp->pid, (char*)arg1_offset, val);
Roland McGrathd81f1d92003-01-09 06:53:34 +00001442}
1443
Denys Vlasenko2d1e90f2012-02-25 02:46:14 +01001444#endif /* architectures */
Roland McGrathd81f1d92003-01-09 06:53:34 +00001445
Denys Vlasenko2d1e90f2012-02-25 02:46:14 +01001446#ifndef restore_arg0
1447# define restore_arg0(tcp, state, val) set_arg0((tcp), (state), (val))
1448#endif
1449#ifndef restore_arg1
1450# define restore_arg1(tcp, state, val) set_arg1((tcp), (state), (val))
1451#endif
Roland McGrathd81f1d92003-01-09 06:53:34 +00001452
Denys Vlasenko2d1e90f2012-02-25 02:46:14 +01001453#ifndef arg0_index
1454# define arg0_index 0
1455# define arg1_index 1
1456#endif
Roland McGrath90d0afd2004-03-01 21:05:16 +00001457
Roland McGrathd81f1d92003-01-09 06:53:34 +00001458int
Denys Vlasenko418d66a2009-01-17 01:52:54 +00001459setbpt(struct tcb *tcp)
Roland McGrathd81f1d92003-01-09 06:53:34 +00001460{
Roland McGrath3291ef22008-05-20 00:34:34 +00001461 static int clone_scno[SUPPORTED_PERSONALITIES] = { SYS_clone };
Roland McGrathd81f1d92003-01-09 06:53:34 +00001462 arg_setup_state state;
1463
1464 if (tcp->flags & TCB_BPTSET) {
1465 fprintf(stderr, "PANIC: TCB already set in pid %u\n", tcp->pid);
1466 return -1;
1467 }
1468
Roland McGrath3291ef22008-05-20 00:34:34 +00001469 /*
1470 * It's a silly kludge to initialize this with a search at runtime.
1471 * But it's better than maintaining another magic thing in the
1472 * godforsaken tables.
1473 */
1474 if (clone_scno[current_personality] == 0) {
1475 int i;
1476 for (i = 0; i < nsyscalls; ++i)
1477 if (sysent[i].sys_func == sys_clone) {
1478 clone_scno[current_personality] = i;
1479 break;
1480 }
1481 }
1482
Dmitry V. Levin0c661512012-02-20 21:17:58 +00001483 if (sysent[tcp->scno].sys_func == sys_fork ||
1484 sysent[tcp->scno].sys_func == sys_vfork) {
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001485 if (arg_setup(tcp, &state) < 0
1486 || get_arg0(tcp, &state, &tcp->inst[0]) < 0
1487 || get_arg1(tcp, &state, &tcp->inst[1]) < 0
Roland McGrath3291ef22008-05-20 00:34:34 +00001488 || change_syscall(tcp, clone_scno[current_personality]) < 0
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001489 || set_arg0(tcp, &state, CLONE_PTRACE|SIGCHLD) < 0
1490 || set_arg1(tcp, &state, 0) < 0
1491 || arg_finish_change(tcp, &state) < 0)
Roland McGrathd81f1d92003-01-09 06:53:34 +00001492 return -1;
Roland McGrathc9dc3c12004-03-01 20:57:09 +00001493 tcp->u_arg[arg0_index] = CLONE_PTRACE|SIGCHLD;
1494 tcp->u_arg[arg1_index] = 0;
Roland McGrathd81f1d92003-01-09 06:53:34 +00001495 tcp->flags |= TCB_BPTSET;
1496 return 0;
Dmitry V. Levin0c661512012-02-20 21:17:58 +00001497 }
Roland McGrathd81f1d92003-01-09 06:53:34 +00001498
Dmitry V. Levin0c661512012-02-20 21:17:58 +00001499 if (sysent[tcp->scno].sys_func == sys_clone) {
Jan Kratochvil8fc95752008-08-06 21:43:35 +00001500 /* ia64 calls directly `clone (CLONE_VFORK | CLONE_VM)'
Dmitry V. Levin0c661512012-02-20 21:17:58 +00001501 contrary to x86 vfork above. Even on x86 we turn the
Jan Kratochvil8fc95752008-08-06 21:43:35 +00001502 vfork semantics into plain fork - each application must not
1503 depend on the vfork specifics according to POSIX. We would
1504 hang waiting for the parent resume otherwise. We need to
1505 clear also CLONE_VM but only in the CLONE_VFORK case as
1506 otherwise we would break pthread_create. */
1507
Denys Vlasenkoc133bf02011-06-23 21:57:54 +02001508 long new_arg0 = (tcp->u_arg[arg0_index] | CLONE_PTRACE);
1509 if (new_arg0 & CLONE_VFORK)
1510 new_arg0 &= ~(unsigned long)(CLONE_VFORK | CLONE_VM);
1511 if (arg_setup(tcp, &state) < 0
1512 || set_arg0(tcp, &state, new_arg0) < 0
1513 || arg_finish_change(tcp, &state) < 0)
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00001514 return -1;
Roland McGrathd81f1d92003-01-09 06:53:34 +00001515 tcp->flags |= TCB_BPTSET;
Roland McGrathc9dc3c12004-03-01 20:57:09 +00001516 tcp->inst[0] = tcp->u_arg[arg0_index];
1517 tcp->inst[1] = tcp->u_arg[arg1_index];
Roland McGrathd81f1d92003-01-09 06:53:34 +00001518 return 0;
Roland McGrathd81f1d92003-01-09 06:53:34 +00001519 }
1520
Dmitry V. Levin0c661512012-02-20 21:17:58 +00001521 fprintf(stderr, "PANIC: setbpt for syscall %ld on %u???\n",
1522 tcp->scno, tcp->pid);
Roland McGrathd81f1d92003-01-09 06:53:34 +00001523 return -1;
1524}
1525
1526int
Denys Vlasenko12014262011-05-30 14:00:14 +02001527clearbpt(struct tcb *tcp)
Roland McGrathd81f1d92003-01-09 06:53:34 +00001528{
1529 arg_setup_state state;
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001530 if (arg_setup(tcp, &state) < 0
1531 || restore_arg0(tcp, &state, tcp->inst[0]) < 0
1532 || restore_arg1(tcp, &state, tcp->inst[1]) < 0
1533 || arg_finish_change(tcp, &state))
Denys Vlasenkoc133bf02011-06-23 21:57:54 +02001534 if (errno != ESRCH)
1535 return -1;
Roland McGrathd81f1d92003-01-09 06:53:34 +00001536 tcp->flags &= ~TCB_BPTSET;
1537 return 0;
1538}