blob: 88765ca274b349f00ceac10caa8e27ed0091f72f [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
Denys Vlasenko12014262011-05-30 14:00:14 +020083tv_nz(struct timeval *a)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +000084{
85 return a->tv_sec || a->tv_usec;
86}
87
88int
Denys Vlasenko12014262011-05-30 14:00:14 +020089tv_cmp(struct timeval *a, struct timeval *b)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +000090{
91 if (a->tv_sec < b->tv_sec
92 || (a->tv_sec == b->tv_sec && a->tv_usec < b->tv_usec))
93 return -1;
94 if (a->tv_sec > b->tv_sec
95 || (a->tv_sec == b->tv_sec && a->tv_usec > b->tv_usec))
96 return 1;
97 return 0;
98}
99
100double
Denys Vlasenko12014262011-05-30 14:00:14 +0200101tv_float(struct timeval *tv)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000102{
103 return tv->tv_sec + tv->tv_usec/1000000.0;
104}
105
106void
Denys Vlasenko12014262011-05-30 14:00:14 +0200107tv_add(struct timeval *tv, struct timeval *a, struct timeval *b)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000108{
109 tv->tv_sec = a->tv_sec + b->tv_sec;
110 tv->tv_usec = a->tv_usec + b->tv_usec;
Roland McGrath58372f52007-07-24 01:38:22 +0000111 if (tv->tv_usec >= 1000000) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000112 tv->tv_sec++;
113 tv->tv_usec -= 1000000;
114 }
115}
116
117void
Denys Vlasenko12014262011-05-30 14:00:14 +0200118tv_sub(struct timeval *tv, struct timeval *a, struct timeval *b)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000119{
120 tv->tv_sec = a->tv_sec - b->tv_sec;
121 tv->tv_usec = a->tv_usec - b->tv_usec;
122 if (((long) tv->tv_usec) < 0) {
123 tv->tv_sec--;
124 tv->tv_usec += 1000000;
125 }
126}
127
128void
Denys Vlasenko12014262011-05-30 14:00:14 +0200129tv_div(struct timeval *tv, struct timeval *a, int n)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000130{
131 tv->tv_usec = (a->tv_sec % n * 1000000 + a->tv_usec + n / 2) / n;
132 tv->tv_sec = a->tv_sec / n + tv->tv_usec / 1000000;
133 tv->tv_usec %= 1000000;
134}
135
136void
Denys Vlasenko12014262011-05-30 14:00:14 +0200137tv_mul(struct timeval *tv, struct timeval *a, int n)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000138{
139 tv->tv_usec = a->tv_usec * n;
Dmitry V. Levinfefdd972007-06-29 21:25:56 +0000140 tv->tv_sec = a->tv_sec * n + tv->tv_usec / 1000000;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000141 tv->tv_usec %= 1000000;
142}
143
Dmitry V. Levinab9008b2007-01-11 22:05:04 +0000144const char *
145xlookup(const struct xlat *xlat, int val)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000146{
147 for (; xlat->str != NULL; xlat++)
148 if (xlat->val == val)
149 return xlat->str;
150 return NULL;
151}
152
Denys Vlasenko0a295bc2011-09-01 16:31:48 +0200153#if !defined HAVE_STPCPY
Denys Vlasenko52845572011-08-31 12:07:38 +0200154char *
155stpcpy(char *dst, const char *src)
156{
157 while ((*dst = *src++) != '\0')
158 dst++;
159 return dst;
160}
Denys Vlasenko0a295bc2011-09-01 16:31:48 +0200161#endif
Denys Vlasenko52845572011-08-31 12:07:38 +0200162
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000163/*
Denys Vlasenko732d1bf2008-12-17 19:21:59 +0000164 * Used when we want to unblock stopped traced process.
165 * Should be only used with PTRACE_CONT, PTRACE_DETACH and PTRACE_SYSCALL.
166 * Returns 0 on success or if error was ESRCH
167 * (presumably process was killed while we talk to it).
168 * Otherwise prints error message and returns -1.
169 */
170int
Roland McGratheb9e2e82009-06-02 16:49:22 -0700171ptrace_restart(int op, struct tcb *tcp, int sig)
Denys Vlasenko732d1bf2008-12-17 19:21:59 +0000172{
173 int err;
Roland McGratheb9e2e82009-06-02 16:49:22 -0700174 const char *msg;
Denys Vlasenko732d1bf2008-12-17 19:21:59 +0000175
176 errno = 0;
Denys Vlasenko114aefd2012-03-08 12:13:44 +0100177 ptrace(op, tcp->pid, (void *) 0, (long) sig);
Denys Vlasenko732d1bf2008-12-17 19:21:59 +0000178 err = errno;
179 if (!err || err == ESRCH)
180 return 0;
181
182 tcp->ptrace_errno = err;
Roland McGratheb9e2e82009-06-02 16:49:22 -0700183 msg = "SYSCALL";
184 if (op == PTRACE_CONT)
185 msg = "CONT";
186 if (op == PTRACE_DETACH)
187 msg = "DETACH";
Denys Vlasenko31fa8a22012-01-29 02:01:44 +0100188#ifdef PTRACE_LISTEN
189 if (op == PTRACE_LISTEN)
190 msg = "LISTEN";
191#endif
Denys Vlasenko114aefd2012-03-08 12:13:44 +0100192 perror_msg("ptrace(PTRACE_%s,pid:%d,sig:%d)", msg, tcp->pid, sig);
Denys Vlasenko732d1bf2008-12-17 19:21:59 +0000193 return -1;
194}
195
196/*
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000197 * Print entry in struct xlat table, if there.
198 */
199void
Dmitry V. Levinab9008b2007-01-11 22:05:04 +0000200printxval(const struct xlat *xlat, int val, const char *dflt)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000201{
Dmitry V. Levinab9008b2007-01-11 22:05:04 +0000202 const char *str = xlookup(xlat, val);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000203
204 if (str)
Denys Vlasenko5940e652011-09-01 09:55:05 +0200205 tprints(str);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000206 else
207 tprintf("%#x /* %s */", val, dflt);
208}
209
Andreas Schwabb5600fc2009-11-04 17:08:34 +0100210#if HAVE_LONG_LONG
211/*
212 * Print 64bit argument at position llarg and return the index of the next
213 * argument.
214 */
215int
216printllval(struct tcb *tcp, const char *format, int llarg)
217{
Denys Vlasenkoaa925db2012-02-25 15:19:02 +0100218# if defined(X86_64) || defined(POWERPC64)
Andreas Schwabb5600fc2009-11-04 17:08:34 +0100219 if (current_personality == 0) {
220 tprintf(format, tcp->u_arg[llarg]);
221 llarg++;
222 } else {
Andreas Schwabd69fa492010-07-12 21:39:57 +0200223# ifdef POWERPC64
224 /* Align 64bit argument to 64bit boundary. */
Denys Vlasenko4b08df42011-08-19 15:58:24 +0200225 llarg = (llarg + 1) & 0x1e;
Andreas Schwabd69fa492010-07-12 21:39:57 +0200226# endif
Andreas Schwabb5600fc2009-11-04 17:08:34 +0100227 tprintf(format, LONG_LONG(tcp->u_arg[llarg], tcp->u_arg[llarg + 1]));
228 llarg += 2;
229 }
Andreas Schwabd69fa492010-07-12 21:39:57 +0200230# elif defined IA64 || defined ALPHA
Andreas Schwabb5600fc2009-11-04 17:08:34 +0100231 tprintf(format, tcp->u_arg[llarg]);
232 llarg++;
233# elif defined LINUX_MIPSN32
234 tprintf(format, tcp->ext_arg[llarg]);
235 llarg++;
236# else
237 tprintf(format, LONG_LONG(tcp->u_arg[llarg], tcp->u_arg[llarg + 1]));
238 llarg += 2;
239# endif
240 return llarg;
241}
242#endif
243
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000244/*
245 * Interpret `xlat' as an array of flags
246 * print the entries whose bits are on in `flags'
247 * return # of flags printed.
248 */
Denys Vlasenko4924dbd2011-08-19 18:06:46 +0200249void
Denys Vlasenko12014262011-05-30 14:00:14 +0200250addflags(const struct xlat *xlat, int flags)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000251{
Denys Vlasenko4924dbd2011-08-19 18:06:46 +0200252 for (; xlat->str; xlat++) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000253 if (xlat->val && (flags & xlat->val) == xlat->val) {
254 tprintf("|%s", xlat->str);
255 flags &= ~xlat->val;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000256 }
257 }
258 if (flags) {
259 tprintf("|%#x", flags);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000260 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000261}
262
Roland McGratha6c0d8c2007-11-01 21:46:22 +0000263/*
Denys Vlasenko4924dbd2011-08-19 18:06:46 +0200264 * Interpret `xlat' as an array of flags.
Roland McGratha6c0d8c2007-11-01 21:46:22 +0000265 * Print to static string the entries whose bits are on in `flags'
266 * Return static string.
267 */
268const char *
269sprintflags(const char *prefix, const struct xlat *xlat, int flags)
270{
271 static char outstr[1024];
Denys Vlasenko52845572011-08-31 12:07:38 +0200272 char *outptr;
Roland McGratha6c0d8c2007-11-01 21:46:22 +0000273 int found = 0;
274
Denys Vlasenko52845572011-08-31 12:07:38 +0200275 outptr = stpcpy(outstr, prefix);
Roland McGratha6c0d8c2007-11-01 21:46:22 +0000276
277 for (; xlat->str; xlat++) {
278 if ((flags & xlat->val) == xlat->val) {
279 if (found)
Denys Vlasenko52845572011-08-31 12:07:38 +0200280 *outptr++ = '|';
281 outptr = stpcpy(outptr, xlat->str);
Roland McGratha6c0d8c2007-11-01 21:46:22 +0000282 found = 1;
Denys Vlasenko4f3df072012-01-29 22:38:35 +0100283 flags &= ~xlat->val;
284 if (!flags)
285 break;
Roland McGratha6c0d8c2007-11-01 21:46:22 +0000286 }
287 }
288 if (flags) {
289 if (found)
Denys Vlasenko52845572011-08-31 12:07:38 +0200290 *outptr++ = '|';
291 outptr += sprintf(outptr, "%#x", flags);
Roland McGratha6c0d8c2007-11-01 21:46:22 +0000292 }
293
294 return outstr;
295}
296
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000297int
Dmitry V. Levin30145dd2010-09-06 22:08:24 +0000298printflags(const struct xlat *xlat, int flags, const char *dflt)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000299{
300 int n;
Dmitry V. Levin30145dd2010-09-06 22:08:24 +0000301 const char *sep;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000302
303 if (flags == 0 && xlat->val == 0) {
Denys Vlasenko5940e652011-09-01 09:55:05 +0200304 tprints(xlat->str);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000305 return 1;
306 }
307
308 sep = "";
309 for (n = 0; xlat->str; xlat++) {
310 if (xlat->val && (flags & xlat->val) == xlat->val) {
311 tprintf("%s%s", sep, xlat->str);
312 flags &= ~xlat->val;
313 sep = "|";
314 n++;
315 }
316 }
Roland McGrathb2dee132005-06-01 19:02:36 +0000317
318 if (n) {
319 if (flags) {
320 tprintf("%s%#x", sep, flags);
321 n++;
322 }
323 } else {
324 if (flags) {
325 tprintf("%#x", flags);
326 if (dflt)
327 tprintf(" /* %s */", dflt);
328 } else {
329 if (dflt)
Denys Vlasenko60fe8c12011-09-01 10:00:28 +0200330 tprints("0");
Roland McGrathb2dee132005-06-01 19:02:36 +0000331 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000332 }
Roland McGrathb2dee132005-06-01 19:02:36 +0000333
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000334 return n;
335}
336
337void
Dmitry V. Levin30145dd2010-09-06 22:08:24 +0000338printnum(struct tcb *tcp, long addr, const char *fmt)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000339{
Roland McGratheb285352003-01-14 09:59:00 +0000340 long num;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000341
342 if (!addr) {
Denys Vlasenko60fe8c12011-09-01 10:00:28 +0200343 tprints("NULL");
Wichert Akkerman76baf7c1999-02-19 00:21:36 +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("[");
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000351 tprintf(fmt, num);
Denys Vlasenko60fe8c12011-09-01 10:00:28 +0200352 tprints("]");
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000353}
354
Roland McGrath6bc12202003-11-13 22:32:27 +0000355void
Dmitry V. Levin30145dd2010-09-06 22:08:24 +0000356printnum_int(struct tcb *tcp, long addr, const char *fmt)
Roland McGrath9814a942005-07-04 23:28:10 +0000357{
358 int num;
359
360 if (!addr) {
Denys Vlasenko60fe8c12011-09-01 10:00:28 +0200361 tprints("NULL");
Roland McGrath9814a942005-07-04 23:28:10 +0000362 return;
363 }
364 if (umove(tcp, addr, &num) < 0) {
365 tprintf("%#lx", addr);
366 return;
367 }
Denys Vlasenko60fe8c12011-09-01 10:00:28 +0200368 tprints("[");
Roland McGrath9814a942005-07-04 23:28:10 +0000369 tprintf(fmt, num);
Denys Vlasenko60fe8c12011-09-01 10:00:28 +0200370 tprints("]");
Roland McGrath9814a942005-07-04 23:28:10 +0000371}
372
373void
Dmitry V. Levin31382132011-03-04 05:08:02 +0300374printfd(struct tcb *tcp, int fd)
375{
Grant Edwards8a082772011-04-07 20:25:40 +0000376 const char *p;
377
378 if (show_fd_path && (p = getfdpath(tcp, fd)))
379 tprintf("%d<%s>", fd, p);
380 else
381 tprintf("%d", fd);
Dmitry V. Levin31382132011-03-04 05:08:02 +0300382}
383
384void
Denys Vlasenko12014262011-05-30 14:00:14 +0200385printuid(const char *text, unsigned long uid)
Roland McGrath6bc12202003-11-13 22:32:27 +0000386{
Denys Vlasenko5940e652011-09-01 09:55:05 +0200387 tprintf((uid == -1) ? "%s%ld" : "%s%lu", text, uid);
Roland McGrath6bc12202003-11-13 22:32:27 +0000388}
389
Dmitry V. Levina501f142008-11-10 23:19:13 +0000390/*
391 * Quote string `instr' of length `size'
392 * Write up to (3 + `size' * 4) bytes to `outstr' buffer.
393 * If `len' < 0, treat `instr' as a NUL-terminated string
394 * and quote at most (`size' - 1) bytes.
Denys Vlasenko6cecba52012-01-20 11:56:00 +0100395 *
396 * Returns 0 if len < 0 and NUL was seen, 1 otherwise.
397 * Note that if len >= 0, always returns 1.
Dmitry V. Levina501f142008-11-10 23:19:13 +0000398 */
Roland McGrath6d970322007-11-01 23:53:59 +0000399static int
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000400string_quote(const char *instr, char *outstr, int len, int size)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000401{
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000402 const unsigned char *ustr = (const unsigned char *) instr;
403 char *s = outstr;
Denys Vlasenko8778bff2011-08-31 12:22:56 +0200404 int usehex, c, i, eol;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000405
Denys Vlasenko8778bff2011-08-31 12:22:56 +0200406 eol = 0x100; /* this can never match a char */
407 if (len < 0) {
408 size--;
409 eol = '\0';
410 }
411
412 usehex = 0;
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000413 if (xflag > 1)
414 usehex = 1;
415 else if (xflag) {
Dmitry V. Levina501f142008-11-10 23:19:13 +0000416 /* Check for presence of symbol which require
417 to hex-quote the whole string. */
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000418 for (i = 0; i < size; ++i) {
419 c = ustr[i];
Dmitry V. Levina501f142008-11-10 23:19:13 +0000420 /* Check for NUL-terminated string. */
Denys Vlasenko8778bff2011-08-31 12:22:56 +0200421 if (c == eol)
422 break;
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000423 if (!isprint(c) && !isspace(c)) {
424 usehex = 1;
425 break;
426 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000427 }
428 }
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000429
430 *s++ = '\"';
431
432 if (usehex) {
Dmitry V. Levina501f142008-11-10 23:19:13 +0000433 /* Hex-quote the whole string. */
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000434 for (i = 0; i < size; ++i) {
435 c = ustr[i];
Dmitry V. Levina501f142008-11-10 23:19:13 +0000436 /* Check for NUL-terminated string. */
Denys Vlasenko8778bff2011-08-31 12:22:56 +0200437 if (c == eol)
438 goto asciz_ended;
439 *s++ = '\\';
440 *s++ = 'x';
441 *s++ = "0123456789abcdef"[c >> 4];
442 *s++ = "0123456789abcdef"[c & 0xf];
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000443 }
444 } else {
445 for (i = 0; i < size; ++i) {
446 c = ustr[i];
Dmitry V. Levina501f142008-11-10 23:19:13 +0000447 /* Check for NUL-terminated string. */
Denys Vlasenko8778bff2011-08-31 12:22:56 +0200448 if (c == eol)
449 goto asciz_ended;
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000450 switch (c) {
451 case '\"': case '\\':
452 *s++ = '\\';
453 *s++ = c;
454 break;
455 case '\f':
456 *s++ = '\\';
457 *s++ = 'f';
458 break;
459 case '\n':
460 *s++ = '\\';
461 *s++ = 'n';
462 break;
463 case '\r':
464 *s++ = '\\';
465 *s++ = 'r';
466 break;
467 case '\t':
468 *s++ = '\\';
469 *s++ = 't';
470 break;
471 case '\v':
472 *s++ = '\\';
473 *s++ = 'v';
474 break;
475 default:
476 if (isprint(c))
477 *s++ = c;
Denys Vlasenko8778bff2011-08-31 12:22:56 +0200478 else {
479 /* Print \octal */
480 *s++ = '\\';
481 if (i + 1 < size
482 && ustr[i + 1] >= '0'
483 && ustr[i + 1] <= '9'
484 ) {
485 /* Print \ooo */
486 *s++ = '0' + (c >> 6);
487 *s++ = '0' + ((c >> 3) & 0x7);
488 } else {
489 /* Print \[[o]o]o */
490 if ((c >> 3) != 0) {
491 if ((c >> 6) != 0)
492 *s++ = '0' + (c >> 6);
493 *s++ = '0' + ((c >> 3) & 0x7);
494 }
495 }
496 *s++ = '0' + (c & 0x7);
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000497 }
498 break;
499 }
500 }
501 }
502
503 *s++ = '\"';
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000504 *s = '\0';
Roland McGrath6d970322007-11-01 23:53:59 +0000505
Denys Vlasenko8778bff2011-08-31 12:22:56 +0200506 /* Return zero if we printed entire ASCIZ string (didn't truncate it) */
507 if (len < 0 && ustr[i] == '\0') {
508 /* We didn't see NUL yet (otherwise we'd jump to 'asciz_ended')
509 * but next char is NUL.
510 */
511 return 0;
512 }
513
514 return 1;
515
516 asciz_ended:
517 *s++ = '\"';
518 *s = '\0';
519 /* Return zero: we printed entire ASCIZ string (didn't truncate it) */
520 return 0;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000521}
522
Dmitry V. Levina501f142008-11-10 23:19:13 +0000523/*
524 * Print path string specified by address `addr' and length `n'.
525 * If path length exceeds `n', append `...' to the output.
526 */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000527void
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000528printpathn(struct tcb *tcp, long addr, int n)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000529{
Denys Vlasenkob3c52cf2012-01-19 17:20:23 +0100530 char path[MAXPATHLEN + 1];
Denys Vlasenko6cecba52012-01-20 11:56:00 +0100531 int nul_seen;
Denys Vlasenkob3c52cf2012-01-19 17:20:23 +0100532
Dmitry V. Levina501f142008-11-10 23:19:13 +0000533 if (!addr) {
Denys Vlasenko60fe8c12011-09-01 10:00:28 +0200534 tprints("NULL");
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000535 return;
536 }
537
Denys Vlasenko6cecba52012-01-20 11:56:00 +0100538 /* Cap path length to the path buffer size */
Dmitry V. Levina501f142008-11-10 23:19:13 +0000539 if (n > sizeof path - 1)
540 n = sizeof path - 1;
Dmitry V. Levina501f142008-11-10 23:19:13 +0000541
542 /* Fetch one byte more to find out whether path length > n. */
Denys Vlasenko6cecba52012-01-20 11:56:00 +0100543 nul_seen = umovestr(tcp, addr, n + 1, path);
544 if (nul_seen < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000545 tprintf("%#lx", addr);
546 else {
Denys Vlasenkob3c52cf2012-01-19 17:20:23 +0100547 char *outstr;
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000548
Denys Vlasenko6cecba52012-01-20 11:56:00 +0100549 path[n] = '\0';
Denys Vlasenkob3c52cf2012-01-19 17:20:23 +0100550 n++;
Denys Vlasenko6cecba52012-01-20 11:56:00 +0100551 outstr = alloca(4 * n); /* 4*(n-1) + 3 for quotes and NUL */
Denys Vlasenkob3c52cf2012-01-19 17:20:23 +0100552 string_quote(path, outstr, -1, n);
553 tprints(outstr);
Denys Vlasenko6cecba52012-01-20 11:56:00 +0100554 if (!nul_seen)
Denys Vlasenkob3c52cf2012-01-19 17:20:23 +0100555 tprints("...");
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000556 }
557}
558
559void
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000560printpath(struct tcb *tcp, long addr)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000561{
Denys Vlasenkob3c52cf2012-01-19 17:20:23 +0100562 /* Size must correspond to char path[] size in printpathn */
563 printpathn(tcp, addr, MAXPATHLEN);
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000564}
565
Dmitry V. Levina501f142008-11-10 23:19:13 +0000566/*
567 * Print string specified by address `addr' and length `len'.
568 * If `len' < 0, treat the string as a NUL-terminated string.
569 * If string length exceeds `max_strlen', append `...' to the output.
570 */
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000571void
572printstr(struct tcb *tcp, long addr, int len)
573{
574 static char *str = NULL;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000575 static char *outstr;
Roland McGrath6d970322007-11-01 23:53:59 +0000576 int size;
Denys Vlasenkob3c52cf2012-01-19 17:20:23 +0100577 int ellipsis;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000578
579 if (!addr) {
Denys Vlasenko60fe8c12011-09-01 10:00:28 +0200580 tprints("NULL");
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000581 return;
582 }
Dmitry V. Levina501f142008-11-10 23:19:13 +0000583 /* Allocate static buffers if they are not allocated yet. */
Denys Vlasenko1d46ba52011-08-31 14:00:02 +0200584 if (!str) {
Dmitry V. Levina501f142008-11-10 23:19:13 +0000585 str = malloc(max_strlen + 1);
Denys Vlasenko1d46ba52011-08-31 14:00:02 +0200586 if (!str)
587 die_out_of_memory();
Denys Vlasenko6cecba52012-01-20 11:56:00 +0100588 outstr = malloc(4 * max_strlen + /*for quotes and NUL:*/ 3);
Denys Vlasenko1d46ba52011-08-31 14:00:02 +0200589 if (!outstr)
590 die_out_of_memory();
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000591 }
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000592
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000593 if (len < 0) {
Dmitry V. Levina501f142008-11-10 23:19:13 +0000594 /*
595 * Treat as a NUL-terminated string: fetch one byte more
596 * because string_quote() quotes one byte less.
597 */
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000598 size = max_strlen + 1;
599 if (umovestr(tcp, addr, size, str) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000600 tprintf("%#lx", addr);
601 return;
602 }
603 }
604 else {
Dmitry V. Levina501f142008-11-10 23:19:13 +0000605 size = MIN(len, max_strlen);
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000606 if (umoven(tcp, addr, size, str) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000607 tprintf("%#lx", addr);
608 return;
609 }
610 }
611
Denys Vlasenko6cecba52012-01-20 11:56:00 +0100612 /* If string_quote didn't see NUL and (it was supposed to be ASCIZ str
613 * or we were requested to print more than -s NUM chars)...
614 */
Denys Vlasenkob3c52cf2012-01-19 17:20:23 +0100615 ellipsis = (string_quote(str, outstr, len, size) &&
616 (len < 0 || len > max_strlen));
Roland McGratha503dcf2007-08-02 02:06:26 +0000617
Denys Vlasenkob3c52cf2012-01-19 17:20:23 +0100618 tprints(outstr);
619 if (ellipsis)
620 tprints("...");
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000621}
622
John Hughes1d08dcf2001-07-10 13:48:44 +0000623#if HAVE_SYS_UIO_H
624void
Denys Vlasenko12014262011-05-30 14:00:14 +0200625dumpiov(struct tcb *tcp, int len, long addr)
John Hughes1d08dcf2001-07-10 13:48:44 +0000626{
Denys Vlasenko84703742012-02-25 02:38:52 +0100627#if SUPPORTED_PERSONALITIES > 1
Dmitry V. Levin4ebb4e32006-12-13 17:08:08 +0000628 union {
629 struct { u_int32_t base; u_int32_t len; } *iov32;
630 struct { u_int64_t base; u_int64_t len; } *iov64;
631 } iovu;
632#define iov iovu.iov64
633#define sizeof_iov \
634 (personality_wordsize[current_personality] == 4 \
635 ? sizeof(*iovu.iov32) : sizeof(*iovu.iov64))
636#define iov_iov_base(i) \
637 (personality_wordsize[current_personality] == 4 \
638 ? (u_int64_t) iovu.iov32[i].base : iovu.iov64[i].base)
639#define iov_iov_len(i) \
640 (personality_wordsize[current_personality] == 4 \
641 ? (u_int64_t) iovu.iov32[i].len : iovu.iov64[i].len)
642#else
John Hughes1d08dcf2001-07-10 13:48:44 +0000643 struct iovec *iov;
Dmitry V. Levin4ebb4e32006-12-13 17:08:08 +0000644#define sizeof_iov sizeof(*iov)
645#define iov_iov_base(i) iov[i].iov_base
646#define iov_iov_len(i) iov[i].iov_len
647#endif
John Hughes1d08dcf2001-07-10 13:48:44 +0000648 int i;
Denys Vlasenko79a79ea2011-09-01 16:35:44 +0200649 unsigned size;
John Hughes1d08dcf2001-07-10 13:48:44 +0000650
Denys Vlasenko79a79ea2011-09-01 16:35:44 +0200651 size = sizeof_iov * len;
652 /* Assuming no sane program has millions of iovs */
653 if ((unsigned)len > 1024*1024 /* insane or negative size? */
Dmitry V. Levin4ebb4e32006-12-13 17:08:08 +0000654 || (iov = malloc(size)) == NULL) {
Denys Vlasenko79a79ea2011-09-01 16:35:44 +0200655 fprintf(stderr, "Out of memory\n");
656 return;
John Hughes1d08dcf2001-07-10 13:48:44 +0000657 }
Roland McGrathaa524c82005-06-01 19:22:06 +0000658 if (umoven(tcp, addr, size, (char *) iov) >= 0) {
John Hughes1d08dcf2001-07-10 13:48:44 +0000659 for (i = 0; i < len; i++) {
Denys Vlasenkoadedb512008-12-30 18:47:55 +0000660 /* include the buffer number to make it easy to
661 * match up the trace with the source */
662 tprintf(" * %lu bytes in buffer %d\n",
663 (unsigned long)iov_iov_len(i), i);
664 dumpstr(tcp, (long) iov_iov_base(i),
665 iov_iov_len(i));
666 }
John Hughes1d08dcf2001-07-10 13:48:44 +0000667 }
Denys Vlasenko79a79ea2011-09-01 16:35:44 +0200668 free(iov);
Dmitry V. Levin4ebb4e32006-12-13 17:08:08 +0000669#undef sizeof_iov
670#undef iov_iov_base
671#undef iov_iov_len
672#undef iov
John Hughes1d08dcf2001-07-10 13:48:44 +0000673}
674#endif
675
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000676void
Denys Vlasenko12014262011-05-30 14:00:14 +0200677dumpstr(struct tcb *tcp, long addr, int len)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000678{
679 static int strsize = -1;
680 static unsigned char *str;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000681 char *s;
682 int i, j;
683
684 if (strsize < len) {
Denys Vlasenko5d645812011-08-20 12:48:18 +0200685 free(str);
686 str = malloc(len);
Denys Vlasenko79a79ea2011-09-01 16:35:44 +0200687 if (!str) {
688 strsize = -1;
689 fprintf(stderr, "Out of memory\n");
690 return;
691 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000692 strsize = len;
693 }
694
695 if (umoven(tcp, addr, len, (char *) str) < 0)
696 return;
697
698 for (i = 0; i < len; i += 16) {
Denys Vlasenko1d46ba52011-08-31 14:00:02 +0200699 char outstr[80];
700
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000701 s = outstr;
702 sprintf(s, " | %05x ", i);
703 s += 9;
704 for (j = 0; j < 16; j++) {
705 if (j == 8)
706 *s++ = ' ';
707 if (i + j < len) {
708 sprintf(s, " %02x", str[i + j]);
709 s += 3;
710 }
711 else {
712 *s++ = ' '; *s++ = ' '; *s++ = ' ';
713 }
714 }
715 *s++ = ' '; *s++ = ' ';
716 for (j = 0; j < 16; j++) {
717 if (j == 8)
718 *s++ = ' ';
719 if (i + j < len) {
720 if (isprint(str[i + j]))
721 *s++ = str[i + j];
722 else
723 *s++ = '.';
724 }
725 else
726 *s++ = ' ';
727 }
728 tprintf("%s |\n", outstr);
729 }
730}
731
Mike Frysinger612659e2012-02-14 14:38:28 +0100732#ifdef HAVE_PROCESS_VM_READV
733/* C library supports this, but the kernel might not. */
734static bool process_vm_readv_not_supported = 0;
735#else
736
Denys Vlasenko3af224c2012-01-28 01:46:33 +0100737/* Need to do this since process_vm_readv() is not yet available in libc.
738 * When libc is be updated, only "static bool process_vm_readv_not_supported"
739 * line should remain.
740 */
741#if !defined(__NR_process_vm_readv)
742# if defined(I386)
743# define __NR_process_vm_readv 347
744# elif defined(X86_64)
745# define __NR_process_vm_readv 310
746# elif defined(POWERPC)
747# define __NR_process_vm_readv 351
748# endif
749#endif
750
751#if defined(__NR_process_vm_readv)
752static bool process_vm_readv_not_supported = 0;
753static ssize_t process_vm_readv(pid_t pid,
754 const struct iovec *lvec,
755 unsigned long liovcnt,
756 const struct iovec *rvec,
757 unsigned long riovcnt,
758 unsigned long flags)
759{
760 return syscall(__NR_process_vm_readv, (long)pid, lvec, liovcnt, rvec, riovcnt, flags);
761}
762#else
763static bool process_vm_readv_not_supported = 1;
764# define process_vm_readv(...) (errno = ENOSYS, -1)
765#endif
Mike Frysinger612659e2012-02-14 14:38:28 +0100766
767#endif /* end of hack */
Denys Vlasenko3af224c2012-01-28 01:46:33 +0100768
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000769#define PAGMASK (~(PAGSIZ - 1))
770/*
771 * move `len' bytes of data from process `pid'
772 * at address `addr' to our space at `laddr'
773 */
774int
Denys Vlasenkoef2fbf82009-01-06 21:45:06 +0000775umoven(struct tcb *tcp, long addr, int len, char *laddr)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000776{
Roland McGratheb9e2e82009-06-02 16:49:22 -0700777 int pid = tcp->pid;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000778 int n, m;
Denys Vlasenkoa47e6b92012-01-21 04:01:56 +0100779 int started;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000780 union {
781 long val;
782 char x[sizeof(long)];
783 } u;
784
Denys Vlasenkod2a660f2012-02-25 00:43:22 +0100785#if SUPPORTED_PERSONALITIES > 1
786 if (personality_wordsize[current_personality] < sizeof(addr))
787 addr &= (1ul << 8 * personality_wordsize[current_personality]) - 1;
788#endif
789
Denys Vlasenko3af224c2012-01-28 01:46:33 +0100790 if (!process_vm_readv_not_supported) {
791 struct iovec local[1], remote[1];
792 int r;
793
794 local[0].iov_base = laddr;
795 remote[0].iov_base = (void*)addr;
796 local[0].iov_len = remote[0].iov_len = len;
797 r = process_vm_readv(pid,
798 local, 1,
799 remote, 1,
800 /*flags:*/ 0
801 );
802 if (r < 0) {
803 if (errno == ENOSYS)
804 process_vm_readv_not_supported = 1;
Denys Vlasenko29456392012-01-28 02:49:48 +0100805 else if (errno != EINVAL) /* EINVAL is seen if process is gone */
806 /* strange... */
Denys Vlasenko3af224c2012-01-28 01:46:33 +0100807 perror("process_vm_readv");
808 goto vm_readv_didnt_work;
809 }
810 return r;
811 }
812 vm_readv_didnt_work:
813
Denys Vlasenkoa47e6b92012-01-21 04:01:56 +0100814 started = 0;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000815 if (addr & (sizeof(long) - 1)) {
816 /* addr not a multiple of sizeof(long) */
817 n = addr - (addr & -sizeof(long)); /* residue */
818 addr &= -sizeof(long); /* residue */
Roland McGratheb9e2e82009-06-02 16:49:22 -0700819 errno = 0;
820 u.val = ptrace(PTRACE_PEEKDATA, pid, (char *) addr, 0);
821 if (errno) {
Roland McGratheb9e2e82009-06-02 16:49:22 -0700822 /* But if not started, we had a bogus address. */
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) - n, len);
829 memcpy(laddr, &u.x[n], m);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000830 addr += sizeof(long), laddr += m, len -= m;
831 }
832 while (len) {
Roland McGratheb9e2e82009-06-02 16:49:22 -0700833 errno = 0;
834 u.val = ptrace(PTRACE_PEEKDATA, pid, (char *) addr, 0);
835 if (errno) {
836 if (started && (errno==EPERM || errno==EIO)) {
837 /* Ran into 'end of memory' - stupid "printpath" */
838 return 0;
839 }
840 if (addr != 0 && errno != EIO && errno != ESRCH)
Denys Vlasenko4c65c442012-03-08 11:54:10 +0100841 perror_msg("umoven: PTRACE_PEEKDATA pid:%d @0x%lx", pid, addr);
Roland McGratheb9e2e82009-06-02 16:49:22 -0700842 return -1;
843 }
Wichert Akkerman5daa0281999-03-15 19:49:42 +0000844 started = 1;
Denys Vlasenkoa47e6b92012-01-21 04:01:56 +0100845 m = MIN(sizeof(long), len);
846 memcpy(laddr, u.x, m);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000847 addr += sizeof(long), laddr += m, len -= m;
848 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000849
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000850 return 0;
851}
852
853/*
Denys Vlasenko6cecba52012-01-20 11:56:00 +0100854 * Like `umove' but make the additional effort of looking
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000855 * for a terminating zero byte.
Denys Vlasenko6cecba52012-01-20 11:56:00 +0100856 *
857 * Returns < 0 on error, > 0 if NUL was seen,
858 * (TODO if useful: return count of bytes including NUL),
859 * else 0 if len bytes were read but no NUL byte seen.
860 *
861 * Note: there is no guarantee we won't overwrite some bytes
862 * in laddr[] _after_ terminating NUL (but, of course,
863 * we never write past laddr[len-1]).
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000864 */
865int
Denys Vlasenkoef2fbf82009-01-06 21:45:06 +0000866umovestr(struct tcb *tcp, long addr, int len, char *laddr)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000867{
Denys Vlasenkoa47e6b92012-01-21 04:01:56 +0100868 int started;
Roland McGratheb9e2e82009-06-02 16:49:22 -0700869 int pid = tcp->pid;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000870 int i, n, m;
871 union {
872 long val;
873 char x[sizeof(long)];
874 } u;
875
Dmitry V. Levin856c7ed2011-12-26 20:12:02 +0000876#if SUPPORTED_PERSONALITIES > 1
877 if (personality_wordsize[current_personality] < sizeof(addr))
878 addr &= (1ul << 8 * personality_wordsize[current_personality]) - 1;
879#endif
880
Denys Vlasenko3af224c2012-01-28 01:46:33 +0100881 if (!process_vm_readv_not_supported) {
882 struct iovec local[1], remote[1];
883
884 local[0].iov_base = laddr;
885 remote[0].iov_base = (void*)addr;
886
887 while (len > 0) {
888 int end_in_page;
889 int r;
890 int chunk_len;
891
892 /* Don't read kilobytes: most strings are short */
893 chunk_len = len;
894 if (chunk_len > 256)
895 chunk_len = 256;
896 /* Don't cross pages. I guess otherwise we can get EFAULT
897 * and fail to notice that terminating NUL lies
898 * in the existing (first) page.
899 * (I hope there aren't arches with pages < 4K)
900 */
901 end_in_page = ((addr + chunk_len) & 4095);
902 r = chunk_len - end_in_page;
903 if (r > 0) /* if chunk_len > end_in_page */
904 chunk_len = r; /* chunk_len -= end_in_page */
905
906 local[0].iov_len = remote[0].iov_len = chunk_len;
907 r = process_vm_readv(pid,
908 local, 1,
909 remote, 1,
910 /*flags:*/ 0
911 );
912 if (r < 0) {
913 if (errno == ENOSYS)
914 process_vm_readv_not_supported = 1;
Denys Vlasenko29456392012-01-28 02:49:48 +0100915 else if (errno != EINVAL) /* EINVAL is seen if process is gone */
916 /* strange... */
Denys Vlasenko3af224c2012-01-28 01:46:33 +0100917 perror("process_vm_readv");
918 goto vm_readv_didnt_work;
919 }
920 if (memchr(local[0].iov_base, '\0', r))
921 return 1;
922 local[0].iov_base += r;
923 remote[0].iov_base += r;
924 len -= r;
925 }
926 return 0;
927 }
928 vm_readv_didnt_work:
929
Denys Vlasenkoa47e6b92012-01-21 04:01:56 +0100930 started = 0;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000931 if (addr & (sizeof(long) - 1)) {
932 /* addr not a multiple of sizeof(long) */
933 n = addr - (addr & -sizeof(long)); /* residue */
934 addr &= -sizeof(long); /* residue */
Roland McGratheb9e2e82009-06-02 16:49:22 -0700935 errno = 0;
936 u.val = ptrace(PTRACE_PEEKDATA, pid, (char *)addr, 0);
937 if (errno) {
Roland McGratheb9e2e82009-06-02 16:49:22 -0700938 if (addr != 0 && errno != EIO && errno != ESRCH)
Denys Vlasenko4c65c442012-03-08 11:54:10 +0100939 perror_msg("umovestr: PTRACE_PEEKDATA pid:%d @0x%lx", pid, addr);
Roland McGratheb9e2e82009-06-02 16:49:22 -0700940 return -1;
941 }
Wichert Akkerman5daa0281999-03-15 19:49:42 +0000942 started = 1;
Denys Vlasenkoa47e6b92012-01-21 04:01:56 +0100943 m = MIN(sizeof(long) - n, len);
944 memcpy(laddr, &u.x[n], m);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000945 while (n & (sizeof(long) - 1))
946 if (u.x[n++] == '\0')
Denys Vlasenko6cecba52012-01-20 11:56:00 +0100947 return 1;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000948 addr += sizeof(long), laddr += m, len -= m;
949 }
950 while (len) {
Roland McGratheb9e2e82009-06-02 16:49:22 -0700951 errno = 0;
952 u.val = ptrace(PTRACE_PEEKDATA, pid, (char *)addr, 0);
953 if (errno) {
954 if (started && (errno==EPERM || errno==EIO)) {
955 /* Ran into 'end of memory' - stupid "printpath" */
956 return 0;
957 }
958 if (addr != 0 && errno != EIO && errno != ESRCH)
Denys Vlasenko4c65c442012-03-08 11:54:10 +0100959 perror_msg("umovestr: PTRACE_PEEKDATA pid:%d @0x%lx", pid, addr);
Roland McGratheb9e2e82009-06-02 16:49:22 -0700960 return -1;
961 }
Wichert Akkerman5daa0281999-03-15 19:49:42 +0000962 started = 1;
Denys Vlasenkoa47e6b92012-01-21 04:01:56 +0100963 m = MIN(sizeof(long), len);
964 memcpy(laddr, u.x, m);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000965 for (i = 0; i < sizeof(long); i++)
966 if (u.x[i] == '\0')
Denys Vlasenko6cecba52012-01-20 11:56:00 +0100967 return 1;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000968 addr += sizeof(long), laddr += m, len -= m;
969 }
John Hughesaa09c6b2001-05-15 14:53:43 +0000970 return 0;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000971}
972
Denys Vlasenko2d1e90f2012-02-25 02:46:14 +0100973#if !defined(SPARC) && !defined(SPARC64)
974# define PTRACE_WRITETEXT 101
975# define PTRACE_WRITEDATA 102
976#endif /* !SPARC && !SPARC64 */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000977
978int
Denys Vlasenko12014262011-05-30 14:00:14 +0200979upeek(struct tcb *tcp, long off, long *res)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000980{
981 long val;
982
Roland McGratheb9e2e82009-06-02 16:49:22 -0700983 errno = 0;
Denys Vlasenko114aefd2012-03-08 12:13:44 +0100984 val = ptrace(PTRACE_PEEKUSER, tcp->pid, (char *) off, 0);
Roland McGratheb9e2e82009-06-02 16:49:22 -0700985 if (val == -1 && errno) {
986 if (errno != ESRCH) {
Denys Vlasenko4c65c442012-03-08 11:54:10 +0100987 perror_msg("upeek: PTRACE_PEEKUSER pid:%d @0x%lx)", tcp->pid, off);
Roland McGratheb9e2e82009-06-02 16:49:22 -0700988 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000989 return -1;
Roland McGratheb9e2e82009-06-02 16:49:22 -0700990 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000991 *res = val;
992 return 0;
993}
994
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000995void
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +0000996printcall(struct tcb *tcp)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000997{
Roland McGrath7a918832005-02-02 20:55:23 +0000998#define PRINTBADPC tprintf(sizeof(long) == 4 ? "[????????] " : \
999 sizeof(long) == 8 ? "[????????????????] " : \
1000 NULL /* crash */)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001001
Denys Vlasenko2d1e90f2012-02-25 02:46:14 +01001002#if defined(I386)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001003 long eip;
1004
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001005 if (upeek(tcp, 4*EIP, &eip) < 0) {
Roland McGrath7a918832005-02-02 20:55:23 +00001006 PRINTBADPC;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001007 return;
1008 }
1009 tprintf("[%08lx] ", eip);
Denys Vlasenko2d1e90f2012-02-25 02:46:14 +01001010#elif defined(S390) || defined(S390X)
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001011 long psw;
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001012 if (upeek(tcp, PT_PSWADDR, &psw) < 0) {
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001013 PRINTBADPC;
1014 return;
1015 }
Denys Vlasenko2d1e90f2012-02-25 02:46:14 +01001016# ifdef S390
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001017 tprintf("[%08lx] ", psw);
Denys Vlasenko2d1e90f2012-02-25 02:46:14 +01001018# elif S390X
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001019 tprintf("[%16lx] ", psw);
Denys Vlasenko2d1e90f2012-02-25 02:46:14 +01001020# endif
Roland McGratheac26fc2005-02-02 02:48:53 +00001021
Denys Vlasenko2d1e90f2012-02-25 02:46:14 +01001022#elif defined(X86_64)
Michal Ludvig0e035502002-09-23 15:41:01 +00001023 long rip;
1024
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001025 if (upeek(tcp, 8*RIP, &rip) < 0) {
Roland McGrath7a918832005-02-02 20:55:23 +00001026 PRINTBADPC;
Michal Ludvig0e035502002-09-23 15:41:01 +00001027 return;
1028 }
1029 tprintf("[%16lx] ", rip);
Denys Vlasenko2d1e90f2012-02-25 02:46:14 +01001030#elif defined(IA64)
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00001031 long ip;
1032
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001033 if (upeek(tcp, PT_B0, &ip) < 0) {
Roland McGrath7a918832005-02-02 20:55:23 +00001034 PRINTBADPC;
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00001035 return;
1036 }
1037 tprintf("[%08lx] ", ip);
Denys Vlasenko2d1e90f2012-02-25 02:46:14 +01001038#elif defined(POWERPC)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001039 long pc;
1040
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001041 if (upeek(tcp, sizeof(unsigned long)*PT_NIP, &pc) < 0) {
Andreas Schwabd69fa492010-07-12 21:39:57 +02001042 PRINTBADPC;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001043 return;
1044 }
Denys Vlasenko2d1e90f2012-02-25 02:46:14 +01001045# ifdef POWERPC64
Andreas Schwabd69fa492010-07-12 21:39:57 +02001046 tprintf("[%016lx] ", pc);
Denys Vlasenko2d1e90f2012-02-25 02:46:14 +01001047# else
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001048 tprintf("[%08lx] ", pc);
Denys Vlasenko2d1e90f2012-02-25 02:46:14 +01001049# endif
1050#elif defined(M68K)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001051 long pc;
1052
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001053 if (upeek(tcp, 4*PT_PC, &pc) < 0) {
Denys Vlasenko60fe8c12011-09-01 10:00:28 +02001054 tprints("[????????] ");
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001055 return;
1056 }
1057 tprintf("[%08lx] ", pc);
Denys Vlasenko2d1e90f2012-02-25 02:46:14 +01001058#elif defined(ALPHA)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001059 long pc;
1060
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001061 if (upeek(tcp, REG_PC, &pc) < 0) {
Denys Vlasenko60fe8c12011-09-01 10:00:28 +02001062 tprints("[????????????????] ");
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001063 return;
1064 }
1065 tprintf("[%08lx] ", pc);
Denys Vlasenko2d1e90f2012-02-25 02:46:14 +01001066#elif defined(SPARC) || defined(SPARC64)
Mike Frysinger8566c502009-10-12 11:05:14 -04001067 struct pt_regs regs;
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001068 if (ptrace(PTRACE_GETREGS, tcp->pid, (char *)&regs, 0) < 0) {
Roland McGrath7a918832005-02-02 20:55:23 +00001069 PRINTBADPC;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001070 return;
1071 }
Denys Vlasenko2d1e90f2012-02-25 02:46:14 +01001072# if defined(SPARC64)
Mike Frysinger8566c502009-10-12 11:05:14 -04001073 tprintf("[%08lx] ", regs.tpc);
Denys Vlasenko2d1e90f2012-02-25 02:46:14 +01001074# else
Mike Frysinger8566c502009-10-12 11:05:14 -04001075 tprintf("[%08lx] ", regs.pc);
Denys Vlasenko2d1e90f2012-02-25 02:46:14 +01001076# endif
1077#elif defined(HPPA)
Wichert Akkermanc1652e22001-03-27 12:17:16 +00001078 long pc;
1079
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001080 if (upeek(tcp, PT_IAOQ0, &pc) < 0) {
Denys Vlasenko60fe8c12011-09-01 10:00:28 +02001081 tprints("[????????] ");
Wichert Akkermanc1652e22001-03-27 12:17:16 +00001082 return;
1083 }
1084 tprintf("[%08lx] ", pc);
Denys Vlasenko2d1e90f2012-02-25 02:46:14 +01001085#elif defined(MIPS)
Wichert Akkerman75c422b2001-04-10 10:22:50 +00001086 long pc;
1087
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001088 if (upeek(tcp, REG_EPC, &pc) < 0) {
Denys Vlasenko60fe8c12011-09-01 10:00:28 +02001089 tprints("[????????] ");
Wichert Akkerman75c422b2001-04-10 10:22:50 +00001090 return;
1091 }
1092 tprintf("[%08lx] ", pc);
Denys Vlasenko2d1e90f2012-02-25 02:46:14 +01001093#elif defined(SH)
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001094 long pc;
Wichert Akkermanccef6372002-05-01 16:39:22 +00001095
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001096 if (upeek(tcp, 4*REG_PC, &pc) < 0) {
Denys Vlasenko60fe8c12011-09-01 10:00:28 +02001097 tprints("[????????] ");
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001098 return;
1099 }
1100 tprintf("[%08lx] ", pc);
Denys Vlasenko2d1e90f2012-02-25 02:46:14 +01001101#elif defined(SH64)
Roland McGrathe1e584b2003-06-02 19:18:58 +00001102 long pc;
1103
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001104 if (upeek(tcp, REG_PC, &pc) < 0) {
Denys Vlasenko60fe8c12011-09-01 10:00:28 +02001105 tprints("[????????????????] ");
Roland McGrathe1e584b2003-06-02 19:18:58 +00001106 return;
1107 }
1108 tprintf("[%08lx] ", pc);
Denys Vlasenko2d1e90f2012-02-25 02:46:14 +01001109#elif defined(ARM)
Roland McGrathef388682003-06-03 23:28:59 +00001110 long pc;
Roland McGrathe1e584b2003-06-02 19:18:58 +00001111
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001112 if (upeek(tcp, 4*15, &pc) < 0) {
Roland McGrath7a918832005-02-02 20:55:23 +00001113 PRINTBADPC;
Roland McGrathef388682003-06-03 23:28:59 +00001114 return;
1115 }
1116 tprintf("[%08lx] ", pc);
Denys Vlasenko2d1e90f2012-02-25 02:46:14 +01001117#elif defined(AVR32)
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00001118 long pc;
1119
1120 if (upeek(tcp, REG_PC, &pc) < 0) {
Denys Vlasenko60fe8c12011-09-01 10:00:28 +02001121 tprints("[????????] ");
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00001122 return;
1123 }
1124 tprintf("[%08lx] ", pc);
Denys Vlasenko2d1e90f2012-02-25 02:46:14 +01001125#elif defined(BFIN)
Dmitry V. Levin87ea1f42008-11-10 22:21:41 +00001126 long pc;
1127
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001128 if (upeek(tcp, PT_PC, &pc) < 0) {
Dmitry V. Levin87ea1f42008-11-10 22:21:41 +00001129 PRINTBADPC;
1130 return;
1131 }
1132 tprintf("[%08lx] ", pc);
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001133#elif defined(CRISV10)
1134 long pc;
1135
Edgar E. Iglesiaseeb9ce32009-10-05 14:41:02 +00001136 if (upeek(tcp, 4*PT_IRP, &pc) < 0) {
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001137 PRINTBADPC;
1138 return;
1139 }
1140 tprintf("[%08lx] ", pc);
1141#elif defined(CRISV32)
1142 long pc;
1143
Edgar E. Iglesiaseeb9ce32009-10-05 14:41:02 +00001144 if (upeek(tcp, 4*PT_ERP, &pc) < 0) {
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001145 PRINTBADPC;
1146 return;
1147 }
1148 tprintf("[%08lx] ", pc);
Denys Vlasenko2d1e90f2012-02-25 02:46:14 +01001149#endif /* architecture */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001150}
1151
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001152/*
1153 * These #if's are huge, please indent them correctly.
1154 * It's easy to get confused otherwise.
1155 */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001156
Denys Vlasenko2d1e90f2012-02-25 02:46:14 +01001157#include "syscall.h"
Roland McGrath3291ef22008-05-20 00:34:34 +00001158
Denys Vlasenko2d1e90f2012-02-25 02:46:14 +01001159#ifndef CLONE_PTRACE
1160# define CLONE_PTRACE 0x00002000
1161#endif
1162#ifndef CLONE_VFORK
1163# define CLONE_VFORK 0x00004000
1164#endif
1165#ifndef CLONE_VM
1166# define CLONE_VM 0x00000100
1167#endif
1168#ifndef CLONE_STOPPED
1169# define CLONE_STOPPED 0x02000000
1170#endif
Roland McGrathd81f1d92003-01-09 06:53:34 +00001171
Denys Vlasenko2d1e90f2012-02-25 02:46:14 +01001172#ifdef IA64
Roland McGrathd81f1d92003-01-09 06:53:34 +00001173
1174typedef unsigned long *arg_setup_state;
1175
1176static int
1177arg_setup(struct tcb *tcp, arg_setup_state *state)
1178{
Jan Kratochvil1f942712008-08-06 21:38:52 +00001179 unsigned long cfm, sof, sol;
1180 long bsp;
Roland McGrathd81f1d92003-01-09 06:53:34 +00001181
Jan Kratochvil1f942712008-08-06 21:38:52 +00001182 if (ia32) {
1183 /* Satisfy a false GCC warning. */
1184 *state = NULL;
Roland McGrath08267b82004-02-20 22:56:43 +00001185 return 0;
Jan Kratochvil1f942712008-08-06 21:38:52 +00001186 }
Roland McGrath08267b82004-02-20 22:56:43 +00001187
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001188 if (upeek(tcp, PT_AR_BSP, &bsp) < 0)
Roland McGrathd81f1d92003-01-09 06:53:34 +00001189 return -1;
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001190 if (upeek(tcp, PT_CFM, (long *) &cfm) < 0)
Roland McGrathd81f1d92003-01-09 06:53:34 +00001191 return -1;
1192
1193 sof = (cfm >> 0) & 0x7f;
1194 sol = (cfm >> 7) & 0x7f;
Jan Kratochvil1f942712008-08-06 21:38:52 +00001195 bsp = (long) ia64_rse_skip_regs((unsigned long *) bsp, -sof + sol);
Roland McGrathd81f1d92003-01-09 06:53:34 +00001196
Jan Kratochvil1f942712008-08-06 21:38:52 +00001197 *state = (unsigned long *) bsp;
Roland McGrathd81f1d92003-01-09 06:53:34 +00001198 return 0;
1199}
1200
Denys Vlasenko2d1e90f2012-02-25 02:46:14 +01001201# define arg_finish_change(tcp, state) 0
Roland McGrathd81f1d92003-01-09 06:53:34 +00001202
Roland McGrathd81f1d92003-01-09 06:53:34 +00001203static int
Denys Vlasenko12014262011-05-30 14:00:14 +02001204get_arg0(struct tcb *tcp, arg_setup_state *state, long *valp)
Roland McGrathd81f1d92003-01-09 06:53:34 +00001205{
Roland McGrath08267b82004-02-20 22:56:43 +00001206 int ret;
1207
1208 if (ia32)
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001209 ret = upeek(tcp, PT_R11, valp);
Roland McGrath08267b82004-02-20 22:56:43 +00001210 else
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001211 ret = umoven(tcp,
Roland McGrath08267b82004-02-20 22:56:43 +00001212 (unsigned long) ia64_rse_skip_regs(*state, 0),
1213 sizeof(long), (void *) valp);
1214 return ret;
Roland McGrathd81f1d92003-01-09 06:53:34 +00001215}
1216
1217static int
Denys Vlasenko12014262011-05-30 14:00:14 +02001218get_arg1(struct tcb *tcp, arg_setup_state *state, long *valp)
Roland McGrathd81f1d92003-01-09 06:53:34 +00001219{
Roland McGrath08267b82004-02-20 22:56:43 +00001220 int ret;
1221
1222 if (ia32)
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001223 ret = upeek(tcp, PT_R9, valp);
Roland McGrath08267b82004-02-20 22:56:43 +00001224 else
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001225 ret = umoven(tcp,
Roland McGrath08267b82004-02-20 22:56:43 +00001226 (unsigned long) ia64_rse_skip_regs(*state, 1),
1227 sizeof(long), (void *) valp);
1228 return ret;
Roland McGrathd81f1d92003-01-09 06:53:34 +00001229}
Roland McGrathd81f1d92003-01-09 06:53:34 +00001230
1231static int
Denys Vlasenko12014262011-05-30 14:00:14 +02001232set_arg0(struct tcb *tcp, arg_setup_state *state, long val)
Roland McGrathd81f1d92003-01-09 06:53:34 +00001233{
Roland McGrath08267b82004-02-20 22:56:43 +00001234 int req = PTRACE_POKEDATA;
1235 void *ap;
1236
1237 if (ia32) {
1238 ap = (void *) (intptr_t) PT_R11; /* r11 == EBX */
1239 req = PTRACE_POKEUSER;
1240 } else
1241 ap = ia64_rse_skip_regs(*state, 0);
Roland McGratheb9e2e82009-06-02 16:49:22 -07001242 errno = 0;
1243 ptrace(req, tcp->pid, ap, val);
1244 return errno ? -1 : 0;
Roland McGrathd81f1d92003-01-09 06:53:34 +00001245}
1246
1247static int
Denys Vlasenko12014262011-05-30 14:00:14 +02001248set_arg1(struct tcb *tcp, arg_setup_state *state, long val)
Roland McGrathd81f1d92003-01-09 06:53:34 +00001249{
Roland McGrath08267b82004-02-20 22:56:43 +00001250 int req = PTRACE_POKEDATA;
1251 void *ap;
1252
1253 if (ia32) {
1254 ap = (void *) (intptr_t) PT_R9; /* r9 == ECX */
1255 req = PTRACE_POKEUSER;
1256 } else
1257 ap = ia64_rse_skip_regs(*state, 1);
Roland McGratheb9e2e82009-06-02 16:49:22 -07001258 errno = 0;
1259 ptrace(req, tcp->pid, ap, val);
1260 return errno ? -1 : 0;
Roland McGrathd81f1d92003-01-09 06:53:34 +00001261}
1262
Roland McGrathb659f872008-07-18 01:19:36 +00001263/* ia64 does not return the input arguments from functions (and syscalls)
1264 according to ia64 RSE (Register Stack Engine) behavior. */
1265
Denys Vlasenko2d1e90f2012-02-25 02:46:14 +01001266# define restore_arg0(tcp, state, val) ((void) (state), 0)
1267# define restore_arg1(tcp, state, val) ((void) (state), 0)
Roland McGrathb659f872008-07-18 01:19:36 +00001268
Denys Vlasenko2d1e90f2012-02-25 02:46:14 +01001269#elif defined(SPARC) || defined(SPARC64)
Roland McGrathd81f1d92003-01-09 06:53:34 +00001270
Mike Frysinger8566c502009-10-12 11:05:14 -04001271typedef struct pt_regs arg_setup_state;
Roland McGrathd81f1d92003-01-09 06:53:34 +00001272
Denys Vlasenko2d1e90f2012-02-25 02:46:14 +01001273# define arg_setup(tcp, state) \
1274 (ptrace(PTRACE_GETREGS, (tcp)->pid, (char *) (state), 0))
1275# define arg_finish_change(tcp, state) \
1276 (ptrace(PTRACE_SETREGS, (tcp)->pid, (char *) (state), 0))
Roland McGrathd81f1d92003-01-09 06:53:34 +00001277
Denys Vlasenko2d1e90f2012-02-25 02:46:14 +01001278# define get_arg0(tcp, state, valp) (*(valp) = (state)->u_regs[U_REG_O0], 0)
1279# define get_arg1(tcp, state, valp) (*(valp) = (state)->u_regs[U_REG_O1], 0)
1280# define set_arg0(tcp, state, val) ((state)->u_regs[U_REG_O0] = (val), 0)
1281# define set_arg1(tcp, state, val) ((state)->u_regs[U_REG_O1] = (val), 0)
1282# define restore_arg0(tcp, state, val) 0
Roland McGrathd81f1d92003-01-09 06:53:34 +00001283
Denys Vlasenko2d1e90f2012-02-25 02:46:14 +01001284#else /* other architectures */
Roland McGrathd81f1d92003-01-09 06:53:34 +00001285
Denys Vlasenko2d1e90f2012-02-25 02:46:14 +01001286# if defined S390 || defined S390X
Roland McGrath7b308222003-01-20 09:04:36 +00001287/* Note: this is only true for the `clone' system call, which handles
1288 arguments specially. We could as well say that its first two arguments
1289 are swapped relative to other architectures, but that would just be
1290 another #ifdef in the calls. */
Denys Vlasenko2d1e90f2012-02-25 02:46:14 +01001291# define arg0_offset PT_GPR3
1292# define arg1_offset PT_ORIGGPR2
1293# define restore_arg0(tcp, state, val) ((void) (state), 0)
1294# define restore_arg1(tcp, state, val) ((void) (state), 0)
1295# define arg0_index 1
1296# define arg1_index 0
1297# elif defined(ALPHA) || defined(MIPS)
1298# define arg0_offset REG_A0
1299# define arg1_offset (REG_A0+1)
1300# elif defined(AVR32)
1301# define arg0_offset (REG_R12)
1302# define arg1_offset (REG_R11)
1303# elif defined(POWERPC)
1304# define arg0_offset (sizeof(unsigned long)*PT_R3)
1305# define arg1_offset (sizeof(unsigned long)*PT_R4)
1306# define restore_arg0(tcp, state, val) ((void) (state), 0)
1307# elif defined(HPPA)
1308# define arg0_offset PT_GR26
1309# define arg1_offset (PT_GR26-4)
1310# elif defined(X86_64)
1311# define arg0_offset ((long)(8*(current_personality ? RBX : RDI)))
1312# define arg1_offset ((long)(8*(current_personality ? RCX : RSI)))
1313# elif defined(SH)
1314# define arg0_offset (4*(REG_REG0+4))
1315# define arg1_offset (4*(REG_REG0+5))
1316# elif defined(SH64)
1317 /* ABI defines arg0 & 1 in r2 & r3 */
1318# define arg0_offset (REG_OFFSET+16)
1319# define arg1_offset (REG_OFFSET+24)
1320# define restore_arg0(tcp, state, val) 0
1321# elif defined CRISV10 || defined CRISV32
1322# define arg0_offset (4*PT_R11)
1323# define arg1_offset (4*PT_ORIG_R10)
1324# define restore_arg0(tcp, state, val) 0
1325# define restore_arg1(tcp, state, val) 0
1326# define arg0_index 1
1327# define arg1_index 0
1328# else
1329# define arg0_offset 0
1330# define arg1_offset 4
1331# if defined ARM
1332# define restore_arg0(tcp, state, val) 0
1333# endif
1334# endif
Roland McGrathd81f1d92003-01-09 06:53:34 +00001335
1336typedef int arg_setup_state;
1337
Denys Vlasenko2d1e90f2012-02-25 02:46:14 +01001338# define arg_setup(tcp, state) (0)
1339# define arg_finish_change(tcp, state) 0
1340# define get_arg0(tcp, cookie, valp) (upeek((tcp), arg0_offset, (valp)))
1341# define get_arg1(tcp, cookie, valp) (upeek((tcp), arg1_offset, (valp)))
Roland McGrathd81f1d92003-01-09 06:53:34 +00001342
1343static int
Denys Vlasenko12014262011-05-30 14:00:14 +02001344set_arg0(struct tcb *tcp, void *cookie, long val)
Roland McGrathd81f1d92003-01-09 06:53:34 +00001345{
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001346 return ptrace(PTRACE_POKEUSER, tcp->pid, (char*)arg0_offset, val);
Roland McGrathd81f1d92003-01-09 06:53:34 +00001347}
1348
1349static int
Denys Vlasenko12014262011-05-30 14:00:14 +02001350set_arg1(struct tcb *tcp, void *cookie, long val)
Roland McGrathd81f1d92003-01-09 06:53:34 +00001351{
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001352 return ptrace(PTRACE_POKEUSER, tcp->pid, (char*)arg1_offset, val);
Roland McGrathd81f1d92003-01-09 06:53:34 +00001353}
1354
Denys Vlasenko2d1e90f2012-02-25 02:46:14 +01001355#endif /* architectures */
Roland McGrathd81f1d92003-01-09 06:53:34 +00001356
Denys Vlasenko2d1e90f2012-02-25 02:46:14 +01001357#ifndef restore_arg0
1358# define restore_arg0(tcp, state, val) set_arg0((tcp), (state), (val))
1359#endif
1360#ifndef restore_arg1
1361# define restore_arg1(tcp, state, val) set_arg1((tcp), (state), (val))
1362#endif
Roland McGrathd81f1d92003-01-09 06:53:34 +00001363
Denys Vlasenko2d1e90f2012-02-25 02:46:14 +01001364#ifndef arg0_index
1365# define arg0_index 0
1366# define arg1_index 1
1367#endif
Roland McGrath90d0afd2004-03-01 21:05:16 +00001368
Roland McGrathd81f1d92003-01-09 06:53:34 +00001369int
Denys Vlasenko418d66a2009-01-17 01:52:54 +00001370setbpt(struct tcb *tcp)
Roland McGrathd81f1d92003-01-09 06:53:34 +00001371{
Roland McGrath3291ef22008-05-20 00:34:34 +00001372 static int clone_scno[SUPPORTED_PERSONALITIES] = { SYS_clone };
Roland McGrathd81f1d92003-01-09 06:53:34 +00001373 arg_setup_state state;
1374
1375 if (tcp->flags & TCB_BPTSET) {
1376 fprintf(stderr, "PANIC: TCB already set in pid %u\n", tcp->pid);
1377 return -1;
1378 }
1379
Roland McGrath3291ef22008-05-20 00:34:34 +00001380 /*
1381 * It's a silly kludge to initialize this with a search at runtime.
1382 * But it's better than maintaining another magic thing in the
1383 * godforsaken tables.
1384 */
1385 if (clone_scno[current_personality] == 0) {
1386 int i;
1387 for (i = 0; i < nsyscalls; ++i)
1388 if (sysent[i].sys_func == sys_clone) {
1389 clone_scno[current_personality] = i;
1390 break;
1391 }
1392 }
1393
Dmitry V. Levin0c661512012-02-20 21:17:58 +00001394 if (sysent[tcp->scno].sys_func == sys_fork ||
1395 sysent[tcp->scno].sys_func == sys_vfork) {
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001396 if (arg_setup(tcp, &state) < 0
1397 || get_arg0(tcp, &state, &tcp->inst[0]) < 0
1398 || get_arg1(tcp, &state, &tcp->inst[1]) < 0
Roland McGrath3291ef22008-05-20 00:34:34 +00001399 || change_syscall(tcp, clone_scno[current_personality]) < 0
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001400 || set_arg0(tcp, &state, CLONE_PTRACE|SIGCHLD) < 0
1401 || set_arg1(tcp, &state, 0) < 0
1402 || arg_finish_change(tcp, &state) < 0)
Roland McGrathd81f1d92003-01-09 06:53:34 +00001403 return -1;
Roland McGrathc9dc3c12004-03-01 20:57:09 +00001404 tcp->u_arg[arg0_index] = CLONE_PTRACE|SIGCHLD;
1405 tcp->u_arg[arg1_index] = 0;
Roland McGrathd81f1d92003-01-09 06:53:34 +00001406 tcp->flags |= TCB_BPTSET;
1407 return 0;
Dmitry V. Levin0c661512012-02-20 21:17:58 +00001408 }
Roland McGrathd81f1d92003-01-09 06:53:34 +00001409
Dmitry V. Levin0c661512012-02-20 21:17:58 +00001410 if (sysent[tcp->scno].sys_func == sys_clone) {
Jan Kratochvil8fc95752008-08-06 21:43:35 +00001411 /* ia64 calls directly `clone (CLONE_VFORK | CLONE_VM)'
Dmitry V. Levin0c661512012-02-20 21:17:58 +00001412 contrary to x86 vfork above. Even on x86 we turn the
Jan Kratochvil8fc95752008-08-06 21:43:35 +00001413 vfork semantics into plain fork - each application must not
1414 depend on the vfork specifics according to POSIX. We would
1415 hang waiting for the parent resume otherwise. We need to
1416 clear also CLONE_VM but only in the CLONE_VFORK case as
1417 otherwise we would break pthread_create. */
1418
Denys Vlasenkoc133bf02011-06-23 21:57:54 +02001419 long new_arg0 = (tcp->u_arg[arg0_index] | CLONE_PTRACE);
1420 if (new_arg0 & CLONE_VFORK)
1421 new_arg0 &= ~(unsigned long)(CLONE_VFORK | CLONE_VM);
1422 if (arg_setup(tcp, &state) < 0
1423 || set_arg0(tcp, &state, new_arg0) < 0
1424 || arg_finish_change(tcp, &state) < 0)
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00001425 return -1;
Roland McGrathd81f1d92003-01-09 06:53:34 +00001426 tcp->flags |= TCB_BPTSET;
Roland McGrathc9dc3c12004-03-01 20:57:09 +00001427 tcp->inst[0] = tcp->u_arg[arg0_index];
1428 tcp->inst[1] = tcp->u_arg[arg1_index];
Roland McGrathd81f1d92003-01-09 06:53:34 +00001429 return 0;
Roland McGrathd81f1d92003-01-09 06:53:34 +00001430 }
1431
Dmitry V. Levin0c661512012-02-20 21:17:58 +00001432 fprintf(stderr, "PANIC: setbpt for syscall %ld on %u???\n",
1433 tcp->scno, tcp->pid);
Roland McGrathd81f1d92003-01-09 06:53:34 +00001434 return -1;
1435}
1436
1437int
Denys Vlasenko12014262011-05-30 14:00:14 +02001438clearbpt(struct tcb *tcp)
Roland McGrathd81f1d92003-01-09 06:53:34 +00001439{
1440 arg_setup_state state;
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001441 if (arg_setup(tcp, &state) < 0
1442 || restore_arg0(tcp, &state, tcp->inst[0]) < 0
1443 || restore_arg1(tcp, &state, tcp->inst[1]) < 0
1444 || arg_finish_change(tcp, &state))
Denys Vlasenkoc133bf02011-06-23 21:57:54 +02001445 if (errno != ESRCH)
1446 return -1;
Roland McGrathd81f1d92003-01-09 06:53:34 +00001447 tcp->flags &= ~TCB_BPTSET;
1448 return 0;
1449}