blob: a7cb19c0ceb1c31576d75ebc569741bc06351123 [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.
32 *
33 * $Id$
34 */
35
36#include "defs.h"
37
Roland McGrathd81f1d92003-01-09 06:53:34 +000038#include <signal.h>
39#include <sys/syscall.h>
Wichert Akkerman76baf7c1999-02-19 00:21:36 +000040#include <sys/user.h>
41#include <sys/param.h>
42#include <fcntl.h>
John Hughes1d08dcf2001-07-10 13:48:44 +000043#if HAVE_SYS_UIO_H
Denys Vlasenko2d1e90f2012-02-25 02:46:14 +010044# include <sys/uio.h>
John Hughes1d08dcf2001-07-10 13:48:44 +000045#endif
Wichert Akkerman36915a11999-07-13 15:45:02 +000046
Denys Vlasenko84703742012-02-25 02:38:52 +010047#if __GLIBC__ < 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ < 1)
Wichert Akkerman36915a11999-07-13 15:45:02 +000048#include <linux/ptrace.h>
Roland McGrath1e85cf92002-12-16 20:40:54 +000049#endif
Wichert Akkerman36915a11999-07-13 15:45:02 +000050
Denys Vlasenko84703742012-02-25 02:38:52 +010051#if defined(IA64)
Roland McGrathd81f1d92003-01-09 06:53:34 +000052# include <asm/ptrace_offsets.h>
53# include <asm/rse.h>
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +000054#endif
55
Wichert Akkerman36915a11999-07-13 15:45:02 +000056#ifdef HAVE_SYS_REG_H
Denys Vlasenko84703742012-02-25 02:38:52 +010057# include <sys/reg.h>
Wichert Akkerman76baf7c1999-02-19 00:21:36 +000058# define PTRACE_PEEKUSR PTRACE_PEEKUSER
Wichert Akkermanfaf72222000-02-19 23:59:03 +000059#elif defined(HAVE_LINUX_PTRACE_H)
Denys Vlasenko84703742012-02-25 02:38:52 +010060# undef PTRACE_SYSCALL
Roland McGrathce9f0742004-03-01 21:29:22 +000061# ifdef HAVE_STRUCT_IA64_FPREG
62# define ia64_fpreg XXX_ia64_fpreg
63# endif
64# ifdef HAVE_STRUCT_PT_ALL_USER_REGS
65# define pt_all_user_regs XXX_pt_all_user_regs
66# endif
Denys Vlasenko84703742012-02-25 02:38:52 +010067# include <linux/ptrace.h>
Roland McGrathce9f0742004-03-01 21:29:22 +000068# undef ia64_fpreg
69# undef pt_all_user_regs
Wichert Akkerman2e2553a1999-05-09 00:29:58 +000070#endif
71
Denys Vlasenko2d1e90f2012-02-25 02:46:14 +010072#if defined(SPARC64)
Roland McGrath6d1a65c2004-07-12 07:44:08 +000073# undef PTRACE_GETREGS
74# define PTRACE_GETREGS PTRACE_GETREGS64
75# undef PTRACE_SETREGS
76# define PTRACE_SETREGS PTRACE_SETREGS64
Wichert Akkerman9ce1a631999-08-29 23:15:07 +000077#endif
78
Wichert Akkerman76baf7c1999-02-19 00:21:36 +000079/* macros */
80#ifndef MAX
Denys Vlasenko2d1e90f2012-02-25 02:46:14 +010081# define MAX(a,b) (((a) > (b)) ? (a) : (b))
Wichert Akkerman76baf7c1999-02-19 00:21:36 +000082#endif
83#ifndef MIN
Denys Vlasenko2d1e90f2012-02-25 02:46:14 +010084# define MIN(a,b) (((a) < (b)) ? (a) : (b))
Wichert Akkerman76baf7c1999-02-19 00:21:36 +000085#endif
86
Wichert Akkerman76baf7c1999-02-19 00:21:36 +000087int
Denys Vlasenko12014262011-05-30 14:00:14 +020088tv_nz(struct timeval *a)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +000089{
90 return a->tv_sec || a->tv_usec;
91}
92
93int
Denys Vlasenko12014262011-05-30 14:00:14 +020094tv_cmp(struct timeval *a, struct timeval *b)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +000095{
96 if (a->tv_sec < b->tv_sec
97 || (a->tv_sec == b->tv_sec && a->tv_usec < b->tv_usec))
98 return -1;
99 if (a->tv_sec > b->tv_sec
100 || (a->tv_sec == b->tv_sec && a->tv_usec > b->tv_usec))
101 return 1;
102 return 0;
103}
104
105double
Denys Vlasenko12014262011-05-30 14:00:14 +0200106tv_float(struct timeval *tv)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000107{
108 return tv->tv_sec + tv->tv_usec/1000000.0;
109}
110
111void
Denys Vlasenko12014262011-05-30 14:00:14 +0200112tv_add(struct timeval *tv, struct timeval *a, struct timeval *b)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000113{
114 tv->tv_sec = a->tv_sec + b->tv_sec;
115 tv->tv_usec = a->tv_usec + b->tv_usec;
Roland McGrath58372f52007-07-24 01:38:22 +0000116 if (tv->tv_usec >= 1000000) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000117 tv->tv_sec++;
118 tv->tv_usec -= 1000000;
119 }
120}
121
122void
Denys Vlasenko12014262011-05-30 14:00:14 +0200123tv_sub(struct timeval *tv, struct timeval *a, struct timeval *b)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000124{
125 tv->tv_sec = a->tv_sec - b->tv_sec;
126 tv->tv_usec = a->tv_usec - b->tv_usec;
127 if (((long) tv->tv_usec) < 0) {
128 tv->tv_sec--;
129 tv->tv_usec += 1000000;
130 }
131}
132
133void
Denys Vlasenko12014262011-05-30 14:00:14 +0200134tv_div(struct timeval *tv, struct timeval *a, int n)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000135{
136 tv->tv_usec = (a->tv_sec % n * 1000000 + a->tv_usec + n / 2) / n;
137 tv->tv_sec = a->tv_sec / n + tv->tv_usec / 1000000;
138 tv->tv_usec %= 1000000;
139}
140
141void
Denys Vlasenko12014262011-05-30 14:00:14 +0200142tv_mul(struct timeval *tv, struct timeval *a, int n)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000143{
144 tv->tv_usec = a->tv_usec * n;
Dmitry V. Levinfefdd972007-06-29 21:25:56 +0000145 tv->tv_sec = a->tv_sec * n + tv->tv_usec / 1000000;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000146 tv->tv_usec %= 1000000;
147}
148
Dmitry V. Levinab9008b2007-01-11 22:05:04 +0000149const char *
150xlookup(const struct xlat *xlat, int val)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000151{
152 for (; xlat->str != NULL; xlat++)
153 if (xlat->val == val)
154 return xlat->str;
155 return NULL;
156}
157
Denys Vlasenko0a295bc2011-09-01 16:31:48 +0200158#if !defined HAVE_STPCPY
Denys Vlasenko52845572011-08-31 12:07:38 +0200159char *
160stpcpy(char *dst, const char *src)
161{
162 while ((*dst = *src++) != '\0')
163 dst++;
164 return dst;
165}
Denys Vlasenko0a295bc2011-09-01 16:31:48 +0200166#endif
Denys Vlasenko52845572011-08-31 12:07:38 +0200167
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000168/*
Roland McGratheb9e2e82009-06-02 16:49:22 -0700169 * Generic ptrace wrapper which tracks ESRCH errors
170 * by setting tcp->ptrace_errno to ESRCH.
Denys Vlasenko732d1bf2008-12-17 19:21:59 +0000171 *
172 * We assume that ESRCH indicates likely process death (SIGKILL?),
173 * modulo bugs where process somehow ended up not stopped.
174 * Unfortunately kernel uses ESRCH for that case too. Oh well.
Roland McGratheb9e2e82009-06-02 16:49:22 -0700175 *
176 * Currently used by upeek() only.
177 * TODO: use this in all other ptrace() calls while decoding.
Denys Vlasenko732d1bf2008-12-17 19:21:59 +0000178 */
Denys Vlasenko4dedd562009-02-24 15:17:53 +0000179long
Roland McGratheb9e2e82009-06-02 16:49:22 -0700180do_ptrace(int request, struct tcb *tcp, void *addr, void *data)
Denys Vlasenko4dedd562009-02-24 15:17:53 +0000181{
Denys Vlasenko732d1bf2008-12-17 19:21:59 +0000182 long l;
183
184 errno = 0;
Mike Frysinger09a13c22009-10-07 01:13:39 -0400185 l = ptrace(request, tcp->pid, addr, (long) data);
Roland McGratheb9e2e82009-06-02 16:49:22 -0700186 /* Non-ESRCH errors might be our invalid reg/mem accesses,
187 * we do not record them. */
188 if (errno == ESRCH)
189 tcp->ptrace_errno = ESRCH;
Denys Vlasenko732d1bf2008-12-17 19:21:59 +0000190 return l;
191}
192
193/*
194 * Used when we want to unblock stopped traced process.
195 * Should be only used with PTRACE_CONT, PTRACE_DETACH and PTRACE_SYSCALL.
196 * Returns 0 on success or if error was ESRCH
197 * (presumably process was killed while we talk to it).
198 * Otherwise prints error message and returns -1.
199 */
200int
Roland McGratheb9e2e82009-06-02 16:49:22 -0700201ptrace_restart(int op, struct tcb *tcp, int sig)
Denys Vlasenko732d1bf2008-12-17 19:21:59 +0000202{
203 int err;
Roland McGratheb9e2e82009-06-02 16:49:22 -0700204 const char *msg;
Denys Vlasenko732d1bf2008-12-17 19:21:59 +0000205
206 errno = 0;
Mike Frysinger09a13c22009-10-07 01:13:39 -0400207 ptrace(op, tcp->pid, (void *) 1, (long) sig);
Denys Vlasenko732d1bf2008-12-17 19:21:59 +0000208 err = errno;
209 if (!err || err == ESRCH)
210 return 0;
211
212 tcp->ptrace_errno = err;
Roland McGratheb9e2e82009-06-02 16:49:22 -0700213 msg = "SYSCALL";
214 if (op == PTRACE_CONT)
215 msg = "CONT";
216 if (op == PTRACE_DETACH)
217 msg = "DETACH";
Denys Vlasenko31fa8a22012-01-29 02:01:44 +0100218#ifdef PTRACE_LISTEN
219 if (op == PTRACE_LISTEN)
220 msg = "LISTEN";
221#endif
Denys Vlasenko4c65c442012-03-08 11:54:10 +0100222 perror_msg("ptrace(PTRACE_%s,pid:%d,1,sig:%d)", msg, tcp->pid, sig);
Denys Vlasenko732d1bf2008-12-17 19:21:59 +0000223 return -1;
224}
225
226/*
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000227 * Print entry in struct xlat table, if there.
228 */
229void
Dmitry V. Levinab9008b2007-01-11 22:05:04 +0000230printxval(const struct xlat *xlat, int val, const char *dflt)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000231{
Dmitry V. Levinab9008b2007-01-11 22:05:04 +0000232 const char *str = xlookup(xlat, val);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000233
234 if (str)
Denys Vlasenko5940e652011-09-01 09:55:05 +0200235 tprints(str);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000236 else
237 tprintf("%#x /* %s */", val, dflt);
238}
239
Andreas Schwabb5600fc2009-11-04 17:08:34 +0100240#if HAVE_LONG_LONG
241/*
242 * Print 64bit argument at position llarg and return the index of the next
243 * argument.
244 */
245int
246printllval(struct tcb *tcp, const char *format, int llarg)
247{
Denys Vlasenkoaa925db2012-02-25 15:19:02 +0100248# if defined(X86_64) || defined(POWERPC64)
Andreas Schwabb5600fc2009-11-04 17:08:34 +0100249 if (current_personality == 0) {
250 tprintf(format, tcp->u_arg[llarg]);
251 llarg++;
252 } else {
Andreas Schwabd69fa492010-07-12 21:39:57 +0200253# ifdef POWERPC64
254 /* Align 64bit argument to 64bit boundary. */
Denys Vlasenko4b08df42011-08-19 15:58:24 +0200255 llarg = (llarg + 1) & 0x1e;
Andreas Schwabd69fa492010-07-12 21:39:57 +0200256# endif
Andreas Schwabb5600fc2009-11-04 17:08:34 +0100257 tprintf(format, LONG_LONG(tcp->u_arg[llarg], tcp->u_arg[llarg + 1]));
258 llarg += 2;
259 }
Andreas Schwabd69fa492010-07-12 21:39:57 +0200260# elif defined IA64 || defined ALPHA
Andreas Schwabb5600fc2009-11-04 17:08:34 +0100261 tprintf(format, tcp->u_arg[llarg]);
262 llarg++;
263# elif defined LINUX_MIPSN32
264 tprintf(format, tcp->ext_arg[llarg]);
265 llarg++;
266# else
267 tprintf(format, LONG_LONG(tcp->u_arg[llarg], tcp->u_arg[llarg + 1]));
268 llarg += 2;
269# endif
270 return llarg;
271}
272#endif
273
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000274/*
275 * Interpret `xlat' as an array of flags
276 * print the entries whose bits are on in `flags'
277 * return # of flags printed.
278 */
Denys Vlasenko4924dbd2011-08-19 18:06:46 +0200279void
Denys Vlasenko12014262011-05-30 14:00:14 +0200280addflags(const struct xlat *xlat, int flags)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000281{
Denys Vlasenko4924dbd2011-08-19 18:06:46 +0200282 for (; xlat->str; xlat++) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000283 if (xlat->val && (flags & xlat->val) == xlat->val) {
284 tprintf("|%s", xlat->str);
285 flags &= ~xlat->val;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000286 }
287 }
288 if (flags) {
289 tprintf("|%#x", flags);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000290 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000291}
292
Roland McGratha6c0d8c2007-11-01 21:46:22 +0000293/*
Denys Vlasenko4924dbd2011-08-19 18:06:46 +0200294 * Interpret `xlat' as an array of flags.
Roland McGratha6c0d8c2007-11-01 21:46:22 +0000295 * Print to static string the entries whose bits are on in `flags'
296 * Return static string.
297 */
298const char *
299sprintflags(const char *prefix, const struct xlat *xlat, int flags)
300{
301 static char outstr[1024];
Denys Vlasenko52845572011-08-31 12:07:38 +0200302 char *outptr;
Roland McGratha6c0d8c2007-11-01 21:46:22 +0000303 int found = 0;
304
Denys Vlasenko52845572011-08-31 12:07:38 +0200305 outptr = stpcpy(outstr, prefix);
Roland McGratha6c0d8c2007-11-01 21:46:22 +0000306
307 for (; xlat->str; xlat++) {
308 if ((flags & xlat->val) == xlat->val) {
309 if (found)
Denys Vlasenko52845572011-08-31 12:07:38 +0200310 *outptr++ = '|';
311 outptr = stpcpy(outptr, xlat->str);
Roland McGratha6c0d8c2007-11-01 21:46:22 +0000312 found = 1;
Denys Vlasenko4f3df072012-01-29 22:38:35 +0100313 flags &= ~xlat->val;
314 if (!flags)
315 break;
Roland McGratha6c0d8c2007-11-01 21:46:22 +0000316 }
317 }
318 if (flags) {
319 if (found)
Denys Vlasenko52845572011-08-31 12:07:38 +0200320 *outptr++ = '|';
321 outptr += sprintf(outptr, "%#x", flags);
Roland McGratha6c0d8c2007-11-01 21:46:22 +0000322 }
323
324 return outstr;
325}
326
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000327int
Dmitry V. Levin30145dd2010-09-06 22:08:24 +0000328printflags(const struct xlat *xlat, int flags, const char *dflt)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000329{
330 int n;
Dmitry V. Levin30145dd2010-09-06 22:08:24 +0000331 const char *sep;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000332
333 if (flags == 0 && xlat->val == 0) {
Denys Vlasenko5940e652011-09-01 09:55:05 +0200334 tprints(xlat->str);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000335 return 1;
336 }
337
338 sep = "";
339 for (n = 0; xlat->str; xlat++) {
340 if (xlat->val && (flags & xlat->val) == xlat->val) {
341 tprintf("%s%s", sep, xlat->str);
342 flags &= ~xlat->val;
343 sep = "|";
344 n++;
345 }
346 }
Roland McGrathb2dee132005-06-01 19:02:36 +0000347
348 if (n) {
349 if (flags) {
350 tprintf("%s%#x", sep, flags);
351 n++;
352 }
353 } else {
354 if (flags) {
355 tprintf("%#x", flags);
356 if (dflt)
357 tprintf(" /* %s */", dflt);
358 } else {
359 if (dflt)
Denys Vlasenko60fe8c12011-09-01 10:00:28 +0200360 tprints("0");
Roland McGrathb2dee132005-06-01 19:02:36 +0000361 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000362 }
Roland McGrathb2dee132005-06-01 19:02:36 +0000363
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000364 return n;
365}
366
367void
Dmitry V. Levin30145dd2010-09-06 22:08:24 +0000368printnum(struct tcb *tcp, long addr, const char *fmt)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000369{
Roland McGratheb285352003-01-14 09:59:00 +0000370 long num;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000371
372 if (!addr) {
Denys Vlasenko60fe8c12011-09-01 10:00:28 +0200373 tprints("NULL");
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000374 return;
375 }
376 if (umove(tcp, addr, &num) < 0) {
377 tprintf("%#lx", addr);
378 return;
379 }
Denys Vlasenko60fe8c12011-09-01 10:00:28 +0200380 tprints("[");
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000381 tprintf(fmt, num);
Denys Vlasenko60fe8c12011-09-01 10:00:28 +0200382 tprints("]");
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000383}
384
Roland McGrath6bc12202003-11-13 22:32:27 +0000385void
Dmitry V. Levin30145dd2010-09-06 22:08:24 +0000386printnum_int(struct tcb *tcp, long addr, const char *fmt)
Roland McGrath9814a942005-07-04 23:28:10 +0000387{
388 int num;
389
390 if (!addr) {
Denys Vlasenko60fe8c12011-09-01 10:00:28 +0200391 tprints("NULL");
Roland McGrath9814a942005-07-04 23:28:10 +0000392 return;
393 }
394 if (umove(tcp, addr, &num) < 0) {
395 tprintf("%#lx", addr);
396 return;
397 }
Denys Vlasenko60fe8c12011-09-01 10:00:28 +0200398 tprints("[");
Roland McGrath9814a942005-07-04 23:28:10 +0000399 tprintf(fmt, num);
Denys Vlasenko60fe8c12011-09-01 10:00:28 +0200400 tprints("]");
Roland McGrath9814a942005-07-04 23:28:10 +0000401}
402
403void
Dmitry V. Levin31382132011-03-04 05:08:02 +0300404printfd(struct tcb *tcp, int fd)
405{
Grant Edwards8a082772011-04-07 20:25:40 +0000406 const char *p;
407
408 if (show_fd_path && (p = getfdpath(tcp, fd)))
409 tprintf("%d<%s>", fd, p);
410 else
411 tprintf("%d", fd);
Dmitry V. Levin31382132011-03-04 05:08:02 +0300412}
413
414void
Denys Vlasenko12014262011-05-30 14:00:14 +0200415printuid(const char *text, unsigned long uid)
Roland McGrath6bc12202003-11-13 22:32:27 +0000416{
Denys Vlasenko5940e652011-09-01 09:55:05 +0200417 tprintf((uid == -1) ? "%s%ld" : "%s%lu", text, uid);
Roland McGrath6bc12202003-11-13 22:32:27 +0000418}
419
Dmitry V. Levina501f142008-11-10 23:19:13 +0000420/*
421 * Quote string `instr' of length `size'
422 * Write up to (3 + `size' * 4) bytes to `outstr' buffer.
423 * If `len' < 0, treat `instr' as a NUL-terminated string
424 * and quote at most (`size' - 1) bytes.
Denys Vlasenko6cecba52012-01-20 11:56:00 +0100425 *
426 * Returns 0 if len < 0 and NUL was seen, 1 otherwise.
427 * Note that if len >= 0, always returns 1.
Dmitry V. Levina501f142008-11-10 23:19:13 +0000428 */
Roland McGrath6d970322007-11-01 23:53:59 +0000429static int
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000430string_quote(const char *instr, char *outstr, int len, int size)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000431{
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000432 const unsigned char *ustr = (const unsigned char *) instr;
433 char *s = outstr;
Denys Vlasenko8778bff2011-08-31 12:22:56 +0200434 int usehex, c, i, eol;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000435
Denys Vlasenko8778bff2011-08-31 12:22:56 +0200436 eol = 0x100; /* this can never match a char */
437 if (len < 0) {
438 size--;
439 eol = '\0';
440 }
441
442 usehex = 0;
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000443 if (xflag > 1)
444 usehex = 1;
445 else if (xflag) {
Dmitry V. Levina501f142008-11-10 23:19:13 +0000446 /* Check for presence of symbol which require
447 to hex-quote the whole string. */
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000448 for (i = 0; i < size; ++i) {
449 c = ustr[i];
Dmitry V. Levina501f142008-11-10 23:19:13 +0000450 /* Check for NUL-terminated string. */
Denys Vlasenko8778bff2011-08-31 12:22:56 +0200451 if (c == eol)
452 break;
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000453 if (!isprint(c) && !isspace(c)) {
454 usehex = 1;
455 break;
456 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000457 }
458 }
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000459
460 *s++ = '\"';
461
462 if (usehex) {
Dmitry V. Levina501f142008-11-10 23:19:13 +0000463 /* Hex-quote the whole string. */
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000464 for (i = 0; i < size; ++i) {
465 c = ustr[i];
Dmitry V. Levina501f142008-11-10 23:19:13 +0000466 /* Check for NUL-terminated string. */
Denys Vlasenko8778bff2011-08-31 12:22:56 +0200467 if (c == eol)
468 goto asciz_ended;
469 *s++ = '\\';
470 *s++ = 'x';
471 *s++ = "0123456789abcdef"[c >> 4];
472 *s++ = "0123456789abcdef"[c & 0xf];
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000473 }
474 } else {
475 for (i = 0; i < size; ++i) {
476 c = ustr[i];
Dmitry V. Levina501f142008-11-10 23:19:13 +0000477 /* Check for NUL-terminated string. */
Denys Vlasenko8778bff2011-08-31 12:22:56 +0200478 if (c == eol)
479 goto asciz_ended;
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000480 switch (c) {
481 case '\"': case '\\':
482 *s++ = '\\';
483 *s++ = c;
484 break;
485 case '\f':
486 *s++ = '\\';
487 *s++ = 'f';
488 break;
489 case '\n':
490 *s++ = '\\';
491 *s++ = 'n';
492 break;
493 case '\r':
494 *s++ = '\\';
495 *s++ = 'r';
496 break;
497 case '\t':
498 *s++ = '\\';
499 *s++ = 't';
500 break;
501 case '\v':
502 *s++ = '\\';
503 *s++ = 'v';
504 break;
505 default:
506 if (isprint(c))
507 *s++ = c;
Denys Vlasenko8778bff2011-08-31 12:22:56 +0200508 else {
509 /* Print \octal */
510 *s++ = '\\';
511 if (i + 1 < size
512 && ustr[i + 1] >= '0'
513 && ustr[i + 1] <= '9'
514 ) {
515 /* Print \ooo */
516 *s++ = '0' + (c >> 6);
517 *s++ = '0' + ((c >> 3) & 0x7);
518 } else {
519 /* Print \[[o]o]o */
520 if ((c >> 3) != 0) {
521 if ((c >> 6) != 0)
522 *s++ = '0' + (c >> 6);
523 *s++ = '0' + ((c >> 3) & 0x7);
524 }
525 }
526 *s++ = '0' + (c & 0x7);
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000527 }
528 break;
529 }
530 }
531 }
532
533 *s++ = '\"';
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000534 *s = '\0';
Roland McGrath6d970322007-11-01 23:53:59 +0000535
Denys Vlasenko8778bff2011-08-31 12:22:56 +0200536 /* Return zero if we printed entire ASCIZ string (didn't truncate it) */
537 if (len < 0 && ustr[i] == '\0') {
538 /* We didn't see NUL yet (otherwise we'd jump to 'asciz_ended')
539 * but next char is NUL.
540 */
541 return 0;
542 }
543
544 return 1;
545
546 asciz_ended:
547 *s++ = '\"';
548 *s = '\0';
549 /* Return zero: we printed entire ASCIZ string (didn't truncate it) */
550 return 0;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000551}
552
Dmitry V. Levina501f142008-11-10 23:19:13 +0000553/*
554 * Print path string specified by address `addr' and length `n'.
555 * If path length exceeds `n', append `...' to the output.
556 */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000557void
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000558printpathn(struct tcb *tcp, long addr, int n)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000559{
Denys Vlasenkob3c52cf2012-01-19 17:20:23 +0100560 char path[MAXPATHLEN + 1];
Denys Vlasenko6cecba52012-01-20 11:56:00 +0100561 int nul_seen;
Denys Vlasenkob3c52cf2012-01-19 17:20:23 +0100562
Dmitry V. Levina501f142008-11-10 23:19:13 +0000563 if (!addr) {
Denys Vlasenko60fe8c12011-09-01 10:00:28 +0200564 tprints("NULL");
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000565 return;
566 }
567
Denys Vlasenko6cecba52012-01-20 11:56:00 +0100568 /* Cap path length to the path buffer size */
Dmitry V. Levina501f142008-11-10 23:19:13 +0000569 if (n > sizeof path - 1)
570 n = sizeof path - 1;
Dmitry V. Levina501f142008-11-10 23:19:13 +0000571
572 /* Fetch one byte more to find out whether path length > n. */
Denys Vlasenko6cecba52012-01-20 11:56:00 +0100573 nul_seen = umovestr(tcp, addr, n + 1, path);
574 if (nul_seen < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000575 tprintf("%#lx", addr);
576 else {
Denys Vlasenkob3c52cf2012-01-19 17:20:23 +0100577 char *outstr;
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000578
Denys Vlasenko6cecba52012-01-20 11:56:00 +0100579 path[n] = '\0';
Denys Vlasenkob3c52cf2012-01-19 17:20:23 +0100580 n++;
Denys Vlasenko6cecba52012-01-20 11:56:00 +0100581 outstr = alloca(4 * n); /* 4*(n-1) + 3 for quotes and NUL */
Denys Vlasenkob3c52cf2012-01-19 17:20:23 +0100582 string_quote(path, outstr, -1, n);
583 tprints(outstr);
Denys Vlasenko6cecba52012-01-20 11:56:00 +0100584 if (!nul_seen)
Denys Vlasenkob3c52cf2012-01-19 17:20:23 +0100585 tprints("...");
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000586 }
587}
588
589void
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000590printpath(struct tcb *tcp, long addr)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000591{
Denys Vlasenkob3c52cf2012-01-19 17:20:23 +0100592 /* Size must correspond to char path[] size in printpathn */
593 printpathn(tcp, addr, MAXPATHLEN);
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000594}
595
Dmitry V. Levina501f142008-11-10 23:19:13 +0000596/*
597 * Print string specified by address `addr' and length `len'.
598 * If `len' < 0, treat the string as a NUL-terminated string.
599 * If string length exceeds `max_strlen', append `...' to the output.
600 */
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000601void
602printstr(struct tcb *tcp, long addr, int len)
603{
604 static char *str = NULL;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000605 static char *outstr;
Roland McGrath6d970322007-11-01 23:53:59 +0000606 int size;
Denys Vlasenkob3c52cf2012-01-19 17:20:23 +0100607 int ellipsis;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000608
609 if (!addr) {
Denys Vlasenko60fe8c12011-09-01 10:00:28 +0200610 tprints("NULL");
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000611 return;
612 }
Dmitry V. Levina501f142008-11-10 23:19:13 +0000613 /* Allocate static buffers if they are not allocated yet. */
Denys Vlasenko1d46ba52011-08-31 14:00:02 +0200614 if (!str) {
Dmitry V. Levina501f142008-11-10 23:19:13 +0000615 str = malloc(max_strlen + 1);
Denys Vlasenko1d46ba52011-08-31 14:00:02 +0200616 if (!str)
617 die_out_of_memory();
Denys Vlasenko6cecba52012-01-20 11:56:00 +0100618 outstr = malloc(4 * max_strlen + /*for quotes and NUL:*/ 3);
Denys Vlasenko1d46ba52011-08-31 14:00:02 +0200619 if (!outstr)
620 die_out_of_memory();
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000621 }
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000622
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000623 if (len < 0) {
Dmitry V. Levina501f142008-11-10 23:19:13 +0000624 /*
625 * Treat as a NUL-terminated string: fetch one byte more
626 * because string_quote() quotes one byte less.
627 */
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000628 size = max_strlen + 1;
629 if (umovestr(tcp, addr, size, str) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000630 tprintf("%#lx", addr);
631 return;
632 }
633 }
634 else {
Dmitry V. Levina501f142008-11-10 23:19:13 +0000635 size = MIN(len, max_strlen);
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000636 if (umoven(tcp, addr, size, str) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000637 tprintf("%#lx", addr);
638 return;
639 }
640 }
641
Denys Vlasenko6cecba52012-01-20 11:56:00 +0100642 /* If string_quote didn't see NUL and (it was supposed to be ASCIZ str
643 * or we were requested to print more than -s NUM chars)...
644 */
Denys Vlasenkob3c52cf2012-01-19 17:20:23 +0100645 ellipsis = (string_quote(str, outstr, len, size) &&
646 (len < 0 || len > max_strlen));
Roland McGratha503dcf2007-08-02 02:06:26 +0000647
Denys Vlasenkob3c52cf2012-01-19 17:20:23 +0100648 tprints(outstr);
649 if (ellipsis)
650 tprints("...");
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000651}
652
John Hughes1d08dcf2001-07-10 13:48:44 +0000653#if HAVE_SYS_UIO_H
654void
Denys Vlasenko12014262011-05-30 14:00:14 +0200655dumpiov(struct tcb *tcp, int len, long addr)
John Hughes1d08dcf2001-07-10 13:48:44 +0000656{
Denys Vlasenko84703742012-02-25 02:38:52 +0100657#if SUPPORTED_PERSONALITIES > 1
Dmitry V. Levin4ebb4e32006-12-13 17:08:08 +0000658 union {
659 struct { u_int32_t base; u_int32_t len; } *iov32;
660 struct { u_int64_t base; u_int64_t len; } *iov64;
661 } iovu;
662#define iov iovu.iov64
663#define sizeof_iov \
664 (personality_wordsize[current_personality] == 4 \
665 ? sizeof(*iovu.iov32) : sizeof(*iovu.iov64))
666#define iov_iov_base(i) \
667 (personality_wordsize[current_personality] == 4 \
668 ? (u_int64_t) iovu.iov32[i].base : iovu.iov64[i].base)
669#define iov_iov_len(i) \
670 (personality_wordsize[current_personality] == 4 \
671 ? (u_int64_t) iovu.iov32[i].len : iovu.iov64[i].len)
672#else
John Hughes1d08dcf2001-07-10 13:48:44 +0000673 struct iovec *iov;
Dmitry V. Levin4ebb4e32006-12-13 17:08:08 +0000674#define sizeof_iov sizeof(*iov)
675#define iov_iov_base(i) iov[i].iov_base
676#define iov_iov_len(i) iov[i].iov_len
677#endif
John Hughes1d08dcf2001-07-10 13:48:44 +0000678 int i;
Denys Vlasenko79a79ea2011-09-01 16:35:44 +0200679 unsigned size;
John Hughes1d08dcf2001-07-10 13:48:44 +0000680
Denys Vlasenko79a79ea2011-09-01 16:35:44 +0200681 size = sizeof_iov * len;
682 /* Assuming no sane program has millions of iovs */
683 if ((unsigned)len > 1024*1024 /* insane or negative size? */
Dmitry V. Levin4ebb4e32006-12-13 17:08:08 +0000684 || (iov = malloc(size)) == NULL) {
Denys Vlasenko79a79ea2011-09-01 16:35:44 +0200685 fprintf(stderr, "Out of memory\n");
686 return;
John Hughes1d08dcf2001-07-10 13:48:44 +0000687 }
Roland McGrathaa524c82005-06-01 19:22:06 +0000688 if (umoven(tcp, addr, size, (char *) iov) >= 0) {
John Hughes1d08dcf2001-07-10 13:48:44 +0000689 for (i = 0; i < len; i++) {
Denys Vlasenkoadedb512008-12-30 18:47:55 +0000690 /* include the buffer number to make it easy to
691 * match up the trace with the source */
692 tprintf(" * %lu bytes in buffer %d\n",
693 (unsigned long)iov_iov_len(i), i);
694 dumpstr(tcp, (long) iov_iov_base(i),
695 iov_iov_len(i));
696 }
John Hughes1d08dcf2001-07-10 13:48:44 +0000697 }
Denys Vlasenko79a79ea2011-09-01 16:35:44 +0200698 free(iov);
Dmitry V. Levin4ebb4e32006-12-13 17:08:08 +0000699#undef sizeof_iov
700#undef iov_iov_base
701#undef iov_iov_len
702#undef iov
John Hughes1d08dcf2001-07-10 13:48:44 +0000703}
704#endif
705
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000706void
Denys Vlasenko12014262011-05-30 14:00:14 +0200707dumpstr(struct tcb *tcp, long addr, int len)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000708{
709 static int strsize = -1;
710 static unsigned char *str;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000711 char *s;
712 int i, j;
713
714 if (strsize < len) {
Denys Vlasenko5d645812011-08-20 12:48:18 +0200715 free(str);
716 str = malloc(len);
Denys Vlasenko79a79ea2011-09-01 16:35:44 +0200717 if (!str) {
718 strsize = -1;
719 fprintf(stderr, "Out of memory\n");
720 return;
721 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000722 strsize = len;
723 }
724
725 if (umoven(tcp, addr, len, (char *) str) < 0)
726 return;
727
728 for (i = 0; i < len; i += 16) {
Denys Vlasenko1d46ba52011-08-31 14:00:02 +0200729 char outstr[80];
730
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000731 s = outstr;
732 sprintf(s, " | %05x ", i);
733 s += 9;
734 for (j = 0; j < 16; j++) {
735 if (j == 8)
736 *s++ = ' ';
737 if (i + j < len) {
738 sprintf(s, " %02x", str[i + j]);
739 s += 3;
740 }
741 else {
742 *s++ = ' '; *s++ = ' '; *s++ = ' ';
743 }
744 }
745 *s++ = ' '; *s++ = ' ';
746 for (j = 0; j < 16; j++) {
747 if (j == 8)
748 *s++ = ' ';
749 if (i + j < len) {
750 if (isprint(str[i + j]))
751 *s++ = str[i + j];
752 else
753 *s++ = '.';
754 }
755 else
756 *s++ = ' ';
757 }
758 tprintf("%s |\n", outstr);
759 }
760}
761
Mike Frysinger612659e2012-02-14 14:38:28 +0100762#ifdef HAVE_PROCESS_VM_READV
763/* C library supports this, but the kernel might not. */
764static bool process_vm_readv_not_supported = 0;
765#else
766
Denys Vlasenko3af224c2012-01-28 01:46:33 +0100767/* Need to do this since process_vm_readv() is not yet available in libc.
768 * When libc is be updated, only "static bool process_vm_readv_not_supported"
769 * line should remain.
770 */
771#if !defined(__NR_process_vm_readv)
772# if defined(I386)
773# define __NR_process_vm_readv 347
774# elif defined(X86_64)
775# define __NR_process_vm_readv 310
776# elif defined(POWERPC)
777# define __NR_process_vm_readv 351
778# endif
779#endif
780
781#if defined(__NR_process_vm_readv)
782static bool process_vm_readv_not_supported = 0;
783static ssize_t process_vm_readv(pid_t pid,
784 const struct iovec *lvec,
785 unsigned long liovcnt,
786 const struct iovec *rvec,
787 unsigned long riovcnt,
788 unsigned long flags)
789{
790 return syscall(__NR_process_vm_readv, (long)pid, lvec, liovcnt, rvec, riovcnt, flags);
791}
792#else
793static bool process_vm_readv_not_supported = 1;
794# define process_vm_readv(...) (errno = ENOSYS, -1)
795#endif
Mike Frysinger612659e2012-02-14 14:38:28 +0100796
797#endif /* end of hack */
Denys Vlasenko3af224c2012-01-28 01:46:33 +0100798
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000799#define PAGMASK (~(PAGSIZ - 1))
800/*
801 * move `len' bytes of data from process `pid'
802 * at address `addr' to our space at `laddr'
803 */
804int
Denys Vlasenkoef2fbf82009-01-06 21:45:06 +0000805umoven(struct tcb *tcp, long addr, int len, char *laddr)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000806{
Roland McGratheb9e2e82009-06-02 16:49:22 -0700807 int pid = tcp->pid;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000808 int n, m;
Denys Vlasenkoa47e6b92012-01-21 04:01:56 +0100809 int started;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000810 union {
811 long val;
812 char x[sizeof(long)];
813 } u;
814
Denys Vlasenkod2a660f2012-02-25 00:43:22 +0100815#if SUPPORTED_PERSONALITIES > 1
816 if (personality_wordsize[current_personality] < sizeof(addr))
817 addr &= (1ul << 8 * personality_wordsize[current_personality]) - 1;
818#endif
819
Denys Vlasenko3af224c2012-01-28 01:46:33 +0100820 if (!process_vm_readv_not_supported) {
821 struct iovec local[1], remote[1];
822 int r;
823
824 local[0].iov_base = laddr;
825 remote[0].iov_base = (void*)addr;
826 local[0].iov_len = remote[0].iov_len = len;
827 r = process_vm_readv(pid,
828 local, 1,
829 remote, 1,
830 /*flags:*/ 0
831 );
832 if (r < 0) {
833 if (errno == ENOSYS)
834 process_vm_readv_not_supported = 1;
Denys Vlasenko29456392012-01-28 02:49:48 +0100835 else if (errno != EINVAL) /* EINVAL is seen if process is gone */
836 /* strange... */
Denys Vlasenko3af224c2012-01-28 01:46:33 +0100837 perror("process_vm_readv");
838 goto vm_readv_didnt_work;
839 }
840 return r;
841 }
842 vm_readv_didnt_work:
843
Denys Vlasenkoa47e6b92012-01-21 04:01:56 +0100844 started = 0;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000845 if (addr & (sizeof(long) - 1)) {
846 /* addr not a multiple of sizeof(long) */
847 n = addr - (addr & -sizeof(long)); /* residue */
848 addr &= -sizeof(long); /* residue */
Roland McGratheb9e2e82009-06-02 16:49:22 -0700849 errno = 0;
850 u.val = ptrace(PTRACE_PEEKDATA, pid, (char *) addr, 0);
851 if (errno) {
Roland McGratheb9e2e82009-06-02 16:49:22 -0700852 /* But if not started, we had a bogus address. */
853 if (addr != 0 && errno != EIO && errno != ESRCH)
Denys Vlasenko4c65c442012-03-08 11:54:10 +0100854 perror_msg("umoven: PTRACE_PEEKDATA pid:%d @0x%lx", pid, addr);
Roland McGratheb9e2e82009-06-02 16:49:22 -0700855 return -1;
856 }
Wichert Akkerman5daa0281999-03-15 19:49:42 +0000857 started = 1;
Denys Vlasenkoa47e6b92012-01-21 04:01:56 +0100858 m = MIN(sizeof(long) - n, len);
859 memcpy(laddr, &u.x[n], m);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000860 addr += sizeof(long), laddr += m, len -= m;
861 }
862 while (len) {
Roland McGratheb9e2e82009-06-02 16:49:22 -0700863 errno = 0;
864 u.val = ptrace(PTRACE_PEEKDATA, pid, (char *) addr, 0);
865 if (errno) {
866 if (started && (errno==EPERM || errno==EIO)) {
867 /* Ran into 'end of memory' - stupid "printpath" */
868 return 0;
869 }
870 if (addr != 0 && errno != EIO && errno != ESRCH)
Denys Vlasenko4c65c442012-03-08 11:54:10 +0100871 perror_msg("umoven: PTRACE_PEEKDATA pid:%d @0x%lx", pid, addr);
Roland McGratheb9e2e82009-06-02 16:49:22 -0700872 return -1;
873 }
Wichert Akkerman5daa0281999-03-15 19:49:42 +0000874 started = 1;
Denys Vlasenkoa47e6b92012-01-21 04:01:56 +0100875 m = MIN(sizeof(long), len);
876 memcpy(laddr, u.x, m);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000877 addr += sizeof(long), laddr += m, len -= m;
878 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000879
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000880 return 0;
881}
882
883/*
Denys Vlasenko6cecba52012-01-20 11:56:00 +0100884 * Like `umove' but make the additional effort of looking
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000885 * for a terminating zero byte.
Denys Vlasenko6cecba52012-01-20 11:56:00 +0100886 *
887 * Returns < 0 on error, > 0 if NUL was seen,
888 * (TODO if useful: return count of bytes including NUL),
889 * else 0 if len bytes were read but no NUL byte seen.
890 *
891 * Note: there is no guarantee we won't overwrite some bytes
892 * in laddr[] _after_ terminating NUL (but, of course,
893 * we never write past laddr[len-1]).
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000894 */
895int
Denys Vlasenkoef2fbf82009-01-06 21:45:06 +0000896umovestr(struct tcb *tcp, long addr, int len, char *laddr)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000897{
Denys Vlasenkoa47e6b92012-01-21 04:01:56 +0100898 int started;
Roland McGratheb9e2e82009-06-02 16:49:22 -0700899 int pid = tcp->pid;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000900 int i, n, m;
901 union {
902 long val;
903 char x[sizeof(long)];
904 } u;
905
Dmitry V. Levin856c7ed2011-12-26 20:12:02 +0000906#if SUPPORTED_PERSONALITIES > 1
907 if (personality_wordsize[current_personality] < sizeof(addr))
908 addr &= (1ul << 8 * personality_wordsize[current_personality]) - 1;
909#endif
910
Denys Vlasenko3af224c2012-01-28 01:46:33 +0100911 if (!process_vm_readv_not_supported) {
912 struct iovec local[1], remote[1];
913
914 local[0].iov_base = laddr;
915 remote[0].iov_base = (void*)addr;
916
917 while (len > 0) {
918 int end_in_page;
919 int r;
920 int chunk_len;
921
922 /* Don't read kilobytes: most strings are short */
923 chunk_len = len;
924 if (chunk_len > 256)
925 chunk_len = 256;
926 /* Don't cross pages. I guess otherwise we can get EFAULT
927 * and fail to notice that terminating NUL lies
928 * in the existing (first) page.
929 * (I hope there aren't arches with pages < 4K)
930 */
931 end_in_page = ((addr + chunk_len) & 4095);
932 r = chunk_len - end_in_page;
933 if (r > 0) /* if chunk_len > end_in_page */
934 chunk_len = r; /* chunk_len -= end_in_page */
935
936 local[0].iov_len = remote[0].iov_len = chunk_len;
937 r = process_vm_readv(pid,
938 local, 1,
939 remote, 1,
940 /*flags:*/ 0
941 );
942 if (r < 0) {
943 if (errno == ENOSYS)
944 process_vm_readv_not_supported = 1;
Denys Vlasenko29456392012-01-28 02:49:48 +0100945 else if (errno != EINVAL) /* EINVAL is seen if process is gone */
946 /* strange... */
Denys Vlasenko3af224c2012-01-28 01:46:33 +0100947 perror("process_vm_readv");
948 goto vm_readv_didnt_work;
949 }
950 if (memchr(local[0].iov_base, '\0', r))
951 return 1;
952 local[0].iov_base += r;
953 remote[0].iov_base += r;
954 len -= r;
955 }
956 return 0;
957 }
958 vm_readv_didnt_work:
959
Denys Vlasenkoa47e6b92012-01-21 04:01:56 +0100960 started = 0;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000961 if (addr & (sizeof(long) - 1)) {
962 /* addr not a multiple of sizeof(long) */
963 n = addr - (addr & -sizeof(long)); /* residue */
964 addr &= -sizeof(long); /* residue */
Roland McGratheb9e2e82009-06-02 16:49:22 -0700965 errno = 0;
966 u.val = ptrace(PTRACE_PEEKDATA, pid, (char *)addr, 0);
967 if (errno) {
Roland McGratheb9e2e82009-06-02 16:49:22 -0700968 if (addr != 0 && errno != EIO && errno != ESRCH)
Denys Vlasenko4c65c442012-03-08 11:54:10 +0100969 perror_msg("umovestr: PTRACE_PEEKDATA pid:%d @0x%lx", pid, addr);
Roland McGratheb9e2e82009-06-02 16:49:22 -0700970 return -1;
971 }
Wichert Akkerman5daa0281999-03-15 19:49:42 +0000972 started = 1;
Denys Vlasenkoa47e6b92012-01-21 04:01:56 +0100973 m = MIN(sizeof(long) - n, len);
974 memcpy(laddr, &u.x[n], m);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000975 while (n & (sizeof(long) - 1))
976 if (u.x[n++] == '\0')
Denys Vlasenko6cecba52012-01-20 11:56:00 +0100977 return 1;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000978 addr += sizeof(long), laddr += m, len -= m;
979 }
980 while (len) {
Roland McGratheb9e2e82009-06-02 16:49:22 -0700981 errno = 0;
982 u.val = ptrace(PTRACE_PEEKDATA, pid, (char *)addr, 0);
983 if (errno) {
984 if (started && (errno==EPERM || errno==EIO)) {
985 /* Ran into 'end of memory' - stupid "printpath" */
986 return 0;
987 }
988 if (addr != 0 && errno != EIO && errno != ESRCH)
Denys Vlasenko4c65c442012-03-08 11:54:10 +0100989 perror_msg("umovestr: PTRACE_PEEKDATA pid:%d @0x%lx", pid, addr);
Roland McGratheb9e2e82009-06-02 16:49:22 -0700990 return -1;
991 }
Wichert Akkerman5daa0281999-03-15 19:49:42 +0000992 started = 1;
Denys Vlasenkoa47e6b92012-01-21 04:01:56 +0100993 m = MIN(sizeof(long), len);
994 memcpy(laddr, u.x, m);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000995 for (i = 0; i < sizeof(long); i++)
996 if (u.x[i] == '\0')
Denys Vlasenko6cecba52012-01-20 11:56:00 +0100997 return 1;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000998 addr += sizeof(long), laddr += m, len -= m;
999 }
John Hughesaa09c6b2001-05-15 14:53:43 +00001000 return 0;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001001}
1002
Denys Vlasenko2d1e90f2012-02-25 02:46:14 +01001003#if !defined(SPARC) && !defined(SPARC64)
1004# define PTRACE_WRITETEXT 101
1005# define PTRACE_WRITEDATA 102
1006#endif /* !SPARC && !SPARC64 */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001007
1008int
Denys Vlasenko12014262011-05-30 14:00:14 +02001009upeek(struct tcb *tcp, long off, long *res)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001010{
1011 long val;
1012
Roland McGratheb9e2e82009-06-02 16:49:22 -07001013 errno = 0;
Denys Vlasenko732d1bf2008-12-17 19:21:59 +00001014 val = do_ptrace(PTRACE_PEEKUSER, tcp, (char *) off, 0);
Roland McGratheb9e2e82009-06-02 16:49:22 -07001015 if (val == -1 && errno) {
1016 if (errno != ESRCH) {
Denys Vlasenko4c65c442012-03-08 11:54:10 +01001017 perror_msg("upeek: PTRACE_PEEKUSER pid:%d @0x%lx)", tcp->pid, off);
Roland McGratheb9e2e82009-06-02 16:49:22 -07001018 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001019 return -1;
Roland McGratheb9e2e82009-06-02 16:49:22 -07001020 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001021 *res = val;
1022 return 0;
1023}
1024
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001025void
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001026printcall(struct tcb *tcp)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001027{
Roland McGrath7a918832005-02-02 20:55:23 +00001028#define PRINTBADPC tprintf(sizeof(long) == 4 ? "[????????] " : \
1029 sizeof(long) == 8 ? "[????????????????] " : \
1030 NULL /* crash */)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001031
Denys Vlasenko2d1e90f2012-02-25 02:46:14 +01001032#if defined(I386)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001033 long eip;
1034
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001035 if (upeek(tcp, 4*EIP, &eip) < 0) {
Roland McGrath7a918832005-02-02 20:55:23 +00001036 PRINTBADPC;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001037 return;
1038 }
1039 tprintf("[%08lx] ", eip);
Roland McGratheac26fc2005-02-02 02:48:53 +00001040
Denys Vlasenko2d1e90f2012-02-25 02:46:14 +01001041#elif defined(S390) || defined(S390X)
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001042 long psw;
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001043 if (upeek(tcp, PT_PSWADDR, &psw) < 0) {
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001044 PRINTBADPC;
1045 return;
1046 }
Denys Vlasenko2d1e90f2012-02-25 02:46:14 +01001047# ifdef S390
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001048 tprintf("[%08lx] ", psw);
Denys Vlasenko2d1e90f2012-02-25 02:46:14 +01001049# elif S390X
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001050 tprintf("[%16lx] ", psw);
Denys Vlasenko2d1e90f2012-02-25 02:46:14 +01001051# endif
Roland McGratheac26fc2005-02-02 02:48:53 +00001052
Denys Vlasenko2d1e90f2012-02-25 02:46:14 +01001053#elif defined(X86_64)
Michal Ludvig0e035502002-09-23 15:41:01 +00001054 long rip;
1055
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001056 if (upeek(tcp, 8*RIP, &rip) < 0) {
Roland McGrath7a918832005-02-02 20:55:23 +00001057 PRINTBADPC;
Michal Ludvig0e035502002-09-23 15:41:01 +00001058 return;
1059 }
1060 tprintf("[%16lx] ", rip);
Denys Vlasenko2d1e90f2012-02-25 02:46:14 +01001061#elif defined(IA64)
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00001062 long ip;
1063
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001064 if (upeek(tcp, PT_B0, &ip) < 0) {
Roland McGrath7a918832005-02-02 20:55:23 +00001065 PRINTBADPC;
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00001066 return;
1067 }
1068 tprintf("[%08lx] ", ip);
Denys Vlasenko2d1e90f2012-02-25 02:46:14 +01001069#elif defined(POWERPC)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001070 long pc;
1071
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001072 if (upeek(tcp, sizeof(unsigned long)*PT_NIP, &pc) < 0) {
Andreas Schwabd69fa492010-07-12 21:39:57 +02001073 PRINTBADPC;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001074 return;
1075 }
Denys Vlasenko2d1e90f2012-02-25 02:46:14 +01001076# ifdef POWERPC64
Andreas Schwabd69fa492010-07-12 21:39:57 +02001077 tprintf("[%016lx] ", pc);
Denys Vlasenko2d1e90f2012-02-25 02:46:14 +01001078# else
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001079 tprintf("[%08lx] ", pc);
Denys Vlasenko2d1e90f2012-02-25 02:46:14 +01001080# endif
1081#elif defined(M68K)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001082 long pc;
1083
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001084 if (upeek(tcp, 4*PT_PC, &pc) < 0) {
Denys Vlasenko60fe8c12011-09-01 10:00:28 +02001085 tprints("[????????] ");
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001086 return;
1087 }
1088 tprintf("[%08lx] ", pc);
Denys Vlasenko2d1e90f2012-02-25 02:46:14 +01001089#elif defined(ALPHA)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001090 long pc;
1091
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001092 if (upeek(tcp, REG_PC, &pc) < 0) {
Denys Vlasenko60fe8c12011-09-01 10:00:28 +02001093 tprints("[????????????????] ");
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001094 return;
1095 }
1096 tprintf("[%08lx] ", pc);
Denys Vlasenko2d1e90f2012-02-25 02:46:14 +01001097#elif defined(SPARC) || defined(SPARC64)
Mike Frysinger8566c502009-10-12 11:05:14 -04001098 struct pt_regs regs;
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001099 if (ptrace(PTRACE_GETREGS, tcp->pid, (char *)&regs, 0) < 0) {
Roland McGrath7a918832005-02-02 20:55:23 +00001100 PRINTBADPC;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001101 return;
1102 }
Denys Vlasenko2d1e90f2012-02-25 02:46:14 +01001103# if defined(SPARC64)
Mike Frysinger8566c502009-10-12 11:05:14 -04001104 tprintf("[%08lx] ", regs.tpc);
Denys Vlasenko2d1e90f2012-02-25 02:46:14 +01001105# else
Mike Frysinger8566c502009-10-12 11:05:14 -04001106 tprintf("[%08lx] ", regs.pc);
Denys Vlasenko2d1e90f2012-02-25 02:46:14 +01001107# endif
1108#elif defined(HPPA)
Wichert Akkermanc1652e22001-03-27 12:17:16 +00001109 long pc;
1110
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001111 if (upeek(tcp, PT_IAOQ0, &pc) < 0) {
Denys Vlasenko60fe8c12011-09-01 10:00:28 +02001112 tprints("[????????] ");
Wichert Akkermanc1652e22001-03-27 12:17:16 +00001113 return;
1114 }
1115 tprintf("[%08lx] ", pc);
Denys Vlasenko2d1e90f2012-02-25 02:46:14 +01001116#elif defined(MIPS)
Wichert Akkerman75c422b2001-04-10 10:22:50 +00001117 long pc;
1118
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001119 if (upeek(tcp, REG_EPC, &pc) < 0) {
Denys Vlasenko60fe8c12011-09-01 10:00:28 +02001120 tprints("[????????] ");
Wichert Akkerman75c422b2001-04-10 10:22:50 +00001121 return;
1122 }
1123 tprintf("[%08lx] ", pc);
Denys Vlasenko2d1e90f2012-02-25 02:46:14 +01001124#elif defined(SH)
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001125 long pc;
Wichert Akkermanccef6372002-05-01 16:39:22 +00001126
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001127 if (upeek(tcp, 4*REG_PC, &pc) < 0) {
Denys Vlasenko60fe8c12011-09-01 10:00:28 +02001128 tprints("[????????] ");
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001129 return;
1130 }
1131 tprintf("[%08lx] ", pc);
Denys Vlasenko2d1e90f2012-02-25 02:46:14 +01001132#elif defined(SH64)
Roland McGrathe1e584b2003-06-02 19:18:58 +00001133 long pc;
1134
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001135 if (upeek(tcp, REG_PC, &pc) < 0) {
Denys Vlasenko60fe8c12011-09-01 10:00:28 +02001136 tprints("[????????????????] ");
Roland McGrathe1e584b2003-06-02 19:18:58 +00001137 return;
1138 }
1139 tprintf("[%08lx] ", pc);
Denys Vlasenko2d1e90f2012-02-25 02:46:14 +01001140#elif defined(ARM)
Roland McGrathef388682003-06-03 23:28:59 +00001141 long pc;
Roland McGrathe1e584b2003-06-02 19:18:58 +00001142
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001143 if (upeek(tcp, 4*15, &pc) < 0) {
Roland McGrath7a918832005-02-02 20:55:23 +00001144 PRINTBADPC;
Roland McGrathef388682003-06-03 23:28:59 +00001145 return;
1146 }
1147 tprintf("[%08lx] ", pc);
Denys Vlasenko2d1e90f2012-02-25 02:46:14 +01001148#elif defined(AVR32)
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00001149 long pc;
1150
1151 if (upeek(tcp, REG_PC, &pc) < 0) {
Denys Vlasenko60fe8c12011-09-01 10:00:28 +02001152 tprints("[????????] ");
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00001153 return;
1154 }
1155 tprintf("[%08lx] ", pc);
Denys Vlasenko2d1e90f2012-02-25 02:46:14 +01001156#elif defined(BFIN)
Dmitry V. Levin87ea1f42008-11-10 22:21:41 +00001157 long pc;
1158
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001159 if (upeek(tcp, PT_PC, &pc) < 0) {
Dmitry V. Levin87ea1f42008-11-10 22:21:41 +00001160 PRINTBADPC;
1161 return;
1162 }
1163 tprintf("[%08lx] ", pc);
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001164#elif defined(CRISV10)
1165 long pc;
1166
Edgar E. Iglesiaseeb9ce32009-10-05 14:41:02 +00001167 if (upeek(tcp, 4*PT_IRP, &pc) < 0) {
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001168 PRINTBADPC;
1169 return;
1170 }
1171 tprintf("[%08lx] ", pc);
1172#elif defined(CRISV32)
1173 long pc;
1174
Edgar E. Iglesiaseeb9ce32009-10-05 14:41:02 +00001175 if (upeek(tcp, 4*PT_ERP, &pc) < 0) {
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001176 PRINTBADPC;
1177 return;
1178 }
1179 tprintf("[%08lx] ", pc);
Denys Vlasenko2d1e90f2012-02-25 02:46:14 +01001180#endif /* architecture */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001181}
1182
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001183/*
1184 * These #if's are huge, please indent them correctly.
1185 * It's easy to get confused otherwise.
1186 */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001187
Denys Vlasenko2d1e90f2012-02-25 02:46:14 +01001188#include "syscall.h"
Roland McGrath3291ef22008-05-20 00:34:34 +00001189
Denys Vlasenko2d1e90f2012-02-25 02:46:14 +01001190#include <sys/syscall.h>
1191#ifndef CLONE_PTRACE
1192# define CLONE_PTRACE 0x00002000
1193#endif
1194#ifndef CLONE_VFORK
1195# define CLONE_VFORK 0x00004000
1196#endif
1197#ifndef CLONE_VM
1198# define CLONE_VM 0x00000100
1199#endif
1200#ifndef CLONE_STOPPED
1201# define CLONE_STOPPED 0x02000000
1202#endif
Roland McGrathd81f1d92003-01-09 06:53:34 +00001203
Denys Vlasenko2d1e90f2012-02-25 02:46:14 +01001204#ifdef IA64
Roland McGrathd81f1d92003-01-09 06:53:34 +00001205
1206typedef unsigned long *arg_setup_state;
1207
1208static int
1209arg_setup(struct tcb *tcp, arg_setup_state *state)
1210{
Jan Kratochvil1f942712008-08-06 21:38:52 +00001211 unsigned long cfm, sof, sol;
1212 long bsp;
Roland McGrathd81f1d92003-01-09 06:53:34 +00001213
Jan Kratochvil1f942712008-08-06 21:38:52 +00001214 if (ia32) {
1215 /* Satisfy a false GCC warning. */
1216 *state = NULL;
Roland McGrath08267b82004-02-20 22:56:43 +00001217 return 0;
Jan Kratochvil1f942712008-08-06 21:38:52 +00001218 }
Roland McGrath08267b82004-02-20 22:56:43 +00001219
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001220 if (upeek(tcp, PT_AR_BSP, &bsp) < 0)
Roland McGrathd81f1d92003-01-09 06:53:34 +00001221 return -1;
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001222 if (upeek(tcp, PT_CFM, (long *) &cfm) < 0)
Roland McGrathd81f1d92003-01-09 06:53:34 +00001223 return -1;
1224
1225 sof = (cfm >> 0) & 0x7f;
1226 sol = (cfm >> 7) & 0x7f;
Jan Kratochvil1f942712008-08-06 21:38:52 +00001227 bsp = (long) ia64_rse_skip_regs((unsigned long *) bsp, -sof + sol);
Roland McGrathd81f1d92003-01-09 06:53:34 +00001228
Jan Kratochvil1f942712008-08-06 21:38:52 +00001229 *state = (unsigned long *) bsp;
Roland McGrathd81f1d92003-01-09 06:53:34 +00001230 return 0;
1231}
1232
Denys Vlasenko2d1e90f2012-02-25 02:46:14 +01001233# define arg_finish_change(tcp, state) 0
Roland McGrathd81f1d92003-01-09 06:53:34 +00001234
Roland McGrathd81f1d92003-01-09 06:53:34 +00001235static int
Denys Vlasenko12014262011-05-30 14:00:14 +02001236get_arg0(struct tcb *tcp, arg_setup_state *state, long *valp)
Roland McGrathd81f1d92003-01-09 06:53:34 +00001237{
Roland McGrath08267b82004-02-20 22:56:43 +00001238 int ret;
1239
1240 if (ia32)
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001241 ret = upeek(tcp, PT_R11, valp);
Roland McGrath08267b82004-02-20 22:56:43 +00001242 else
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001243 ret = umoven(tcp,
Roland McGrath08267b82004-02-20 22:56:43 +00001244 (unsigned long) ia64_rse_skip_regs(*state, 0),
1245 sizeof(long), (void *) valp);
1246 return ret;
Roland McGrathd81f1d92003-01-09 06:53:34 +00001247}
1248
1249static int
Denys Vlasenko12014262011-05-30 14:00:14 +02001250get_arg1(struct tcb *tcp, arg_setup_state *state, long *valp)
Roland McGrathd81f1d92003-01-09 06:53:34 +00001251{
Roland McGrath08267b82004-02-20 22:56:43 +00001252 int ret;
1253
1254 if (ia32)
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001255 ret = upeek(tcp, PT_R9, valp);
Roland McGrath08267b82004-02-20 22:56:43 +00001256 else
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001257 ret = umoven(tcp,
Roland McGrath08267b82004-02-20 22:56:43 +00001258 (unsigned long) ia64_rse_skip_regs(*state, 1),
1259 sizeof(long), (void *) valp);
1260 return ret;
Roland McGrathd81f1d92003-01-09 06:53:34 +00001261}
Roland McGrathd81f1d92003-01-09 06:53:34 +00001262
1263static int
Denys Vlasenko12014262011-05-30 14:00:14 +02001264set_arg0(struct tcb *tcp, arg_setup_state *state, long val)
Roland McGrathd81f1d92003-01-09 06:53:34 +00001265{
Roland McGrath08267b82004-02-20 22:56:43 +00001266 int req = PTRACE_POKEDATA;
1267 void *ap;
1268
1269 if (ia32) {
1270 ap = (void *) (intptr_t) PT_R11; /* r11 == EBX */
1271 req = PTRACE_POKEUSER;
1272 } else
1273 ap = ia64_rse_skip_regs(*state, 0);
Roland McGratheb9e2e82009-06-02 16:49:22 -07001274 errno = 0;
1275 ptrace(req, tcp->pid, ap, val);
1276 return errno ? -1 : 0;
Roland McGrathd81f1d92003-01-09 06:53:34 +00001277}
1278
1279static int
Denys Vlasenko12014262011-05-30 14:00:14 +02001280set_arg1(struct tcb *tcp, arg_setup_state *state, long val)
Roland McGrathd81f1d92003-01-09 06:53:34 +00001281{
Roland McGrath08267b82004-02-20 22:56:43 +00001282 int req = PTRACE_POKEDATA;
1283 void *ap;
1284
1285 if (ia32) {
1286 ap = (void *) (intptr_t) PT_R9; /* r9 == ECX */
1287 req = PTRACE_POKEUSER;
1288 } else
1289 ap = ia64_rse_skip_regs(*state, 1);
Roland McGratheb9e2e82009-06-02 16:49:22 -07001290 errno = 0;
1291 ptrace(req, tcp->pid, ap, val);
1292 return errno ? -1 : 0;
Roland McGrathd81f1d92003-01-09 06:53:34 +00001293}
1294
Roland McGrathb659f872008-07-18 01:19:36 +00001295/* ia64 does not return the input arguments from functions (and syscalls)
1296 according to ia64 RSE (Register Stack Engine) behavior. */
1297
Denys Vlasenko2d1e90f2012-02-25 02:46:14 +01001298# define restore_arg0(tcp, state, val) ((void) (state), 0)
1299# define restore_arg1(tcp, state, val) ((void) (state), 0)
Roland McGrathb659f872008-07-18 01:19:36 +00001300
Denys Vlasenko2d1e90f2012-02-25 02:46:14 +01001301#elif defined(SPARC) || defined(SPARC64)
Roland McGrathd81f1d92003-01-09 06:53:34 +00001302
Mike Frysinger8566c502009-10-12 11:05:14 -04001303typedef struct pt_regs arg_setup_state;
Roland McGrathd81f1d92003-01-09 06:53:34 +00001304
Denys Vlasenko2d1e90f2012-02-25 02:46:14 +01001305# define arg_setup(tcp, state) \
1306 (ptrace(PTRACE_GETREGS, (tcp)->pid, (char *) (state), 0))
1307# define arg_finish_change(tcp, state) \
1308 (ptrace(PTRACE_SETREGS, (tcp)->pid, (char *) (state), 0))
Roland McGrathd81f1d92003-01-09 06:53:34 +00001309
Denys Vlasenko2d1e90f2012-02-25 02:46:14 +01001310# define get_arg0(tcp, state, valp) (*(valp) = (state)->u_regs[U_REG_O0], 0)
1311# define get_arg1(tcp, state, valp) (*(valp) = (state)->u_regs[U_REG_O1], 0)
1312# define set_arg0(tcp, state, val) ((state)->u_regs[U_REG_O0] = (val), 0)
1313# define set_arg1(tcp, state, val) ((state)->u_regs[U_REG_O1] = (val), 0)
1314# define restore_arg0(tcp, state, val) 0
Roland McGrathd81f1d92003-01-09 06:53:34 +00001315
Denys Vlasenko2d1e90f2012-02-25 02:46:14 +01001316#else /* other architectures */
Roland McGrathd81f1d92003-01-09 06:53:34 +00001317
Denys Vlasenko2d1e90f2012-02-25 02:46:14 +01001318# if defined S390 || defined S390X
Roland McGrath7b308222003-01-20 09:04:36 +00001319/* Note: this is only true for the `clone' system call, which handles
1320 arguments specially. We could as well say that its first two arguments
1321 are swapped relative to other architectures, but that would just be
1322 another #ifdef in the calls. */
Denys Vlasenko2d1e90f2012-02-25 02:46:14 +01001323# define arg0_offset PT_GPR3
1324# define arg1_offset PT_ORIGGPR2
1325# define restore_arg0(tcp, state, val) ((void) (state), 0)
1326# define restore_arg1(tcp, state, val) ((void) (state), 0)
1327# define arg0_index 1
1328# define arg1_index 0
1329# elif defined(ALPHA) || defined(MIPS)
1330# define arg0_offset REG_A0
1331# define arg1_offset (REG_A0+1)
1332# elif defined(AVR32)
1333# define arg0_offset (REG_R12)
1334# define arg1_offset (REG_R11)
1335# elif defined(POWERPC)
1336# define arg0_offset (sizeof(unsigned long)*PT_R3)
1337# define arg1_offset (sizeof(unsigned long)*PT_R4)
1338# define restore_arg0(tcp, state, val) ((void) (state), 0)
1339# elif defined(HPPA)
1340# define arg0_offset PT_GR26
1341# define arg1_offset (PT_GR26-4)
1342# elif defined(X86_64)
1343# define arg0_offset ((long)(8*(current_personality ? RBX : RDI)))
1344# define arg1_offset ((long)(8*(current_personality ? RCX : RSI)))
1345# elif defined(SH)
1346# define arg0_offset (4*(REG_REG0+4))
1347# define arg1_offset (4*(REG_REG0+5))
1348# elif defined(SH64)
1349 /* ABI defines arg0 & 1 in r2 & r3 */
1350# define arg0_offset (REG_OFFSET+16)
1351# define arg1_offset (REG_OFFSET+24)
1352# define restore_arg0(tcp, state, val) 0
1353# elif defined CRISV10 || defined CRISV32
1354# define arg0_offset (4*PT_R11)
1355# define arg1_offset (4*PT_ORIG_R10)
1356# define restore_arg0(tcp, state, val) 0
1357# define restore_arg1(tcp, state, val) 0
1358# define arg0_index 1
1359# define arg1_index 0
1360# else
1361# define arg0_offset 0
1362# define arg1_offset 4
1363# if defined ARM
1364# define restore_arg0(tcp, state, val) 0
1365# endif
1366# endif
Roland McGrathd81f1d92003-01-09 06:53:34 +00001367
1368typedef int arg_setup_state;
1369
Denys Vlasenko2d1e90f2012-02-25 02:46:14 +01001370# define arg_setup(tcp, state) (0)
1371# define arg_finish_change(tcp, state) 0
1372# define get_arg0(tcp, cookie, valp) (upeek((tcp), arg0_offset, (valp)))
1373# define get_arg1(tcp, cookie, valp) (upeek((tcp), arg1_offset, (valp)))
Roland McGrathd81f1d92003-01-09 06:53:34 +00001374
1375static int
Denys Vlasenko12014262011-05-30 14:00:14 +02001376set_arg0(struct tcb *tcp, void *cookie, long val)
Roland McGrathd81f1d92003-01-09 06:53:34 +00001377{
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001378 return ptrace(PTRACE_POKEUSER, tcp->pid, (char*)arg0_offset, val);
Roland McGrathd81f1d92003-01-09 06:53:34 +00001379}
1380
1381static int
Denys Vlasenko12014262011-05-30 14:00:14 +02001382set_arg1(struct tcb *tcp, void *cookie, long val)
Roland McGrathd81f1d92003-01-09 06:53:34 +00001383{
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001384 return ptrace(PTRACE_POKEUSER, tcp->pid, (char*)arg1_offset, val);
Roland McGrathd81f1d92003-01-09 06:53:34 +00001385}
1386
Denys Vlasenko2d1e90f2012-02-25 02:46:14 +01001387#endif /* architectures */
Roland McGrathd81f1d92003-01-09 06:53:34 +00001388
Denys Vlasenko2d1e90f2012-02-25 02:46:14 +01001389#ifndef restore_arg0
1390# define restore_arg0(tcp, state, val) set_arg0((tcp), (state), (val))
1391#endif
1392#ifndef restore_arg1
1393# define restore_arg1(tcp, state, val) set_arg1((tcp), (state), (val))
1394#endif
Roland McGrathd81f1d92003-01-09 06:53:34 +00001395
Denys Vlasenko2d1e90f2012-02-25 02:46:14 +01001396#ifndef arg0_index
1397# define arg0_index 0
1398# define arg1_index 1
1399#endif
Roland McGrath90d0afd2004-03-01 21:05:16 +00001400
Roland McGrathd81f1d92003-01-09 06:53:34 +00001401int
Denys Vlasenko418d66a2009-01-17 01:52:54 +00001402setbpt(struct tcb *tcp)
Roland McGrathd81f1d92003-01-09 06:53:34 +00001403{
Roland McGrath3291ef22008-05-20 00:34:34 +00001404 static int clone_scno[SUPPORTED_PERSONALITIES] = { SYS_clone };
Roland McGrathd81f1d92003-01-09 06:53:34 +00001405 arg_setup_state state;
1406
1407 if (tcp->flags & TCB_BPTSET) {
1408 fprintf(stderr, "PANIC: TCB already set in pid %u\n", tcp->pid);
1409 return -1;
1410 }
1411
Roland McGrath3291ef22008-05-20 00:34:34 +00001412 /*
1413 * It's a silly kludge to initialize this with a search at runtime.
1414 * But it's better than maintaining another magic thing in the
1415 * godforsaken tables.
1416 */
1417 if (clone_scno[current_personality] == 0) {
1418 int i;
1419 for (i = 0; i < nsyscalls; ++i)
1420 if (sysent[i].sys_func == sys_clone) {
1421 clone_scno[current_personality] = i;
1422 break;
1423 }
1424 }
1425
Dmitry V. Levin0c661512012-02-20 21:17:58 +00001426 if (sysent[tcp->scno].sys_func == sys_fork ||
1427 sysent[tcp->scno].sys_func == sys_vfork) {
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001428 if (arg_setup(tcp, &state) < 0
1429 || get_arg0(tcp, &state, &tcp->inst[0]) < 0
1430 || get_arg1(tcp, &state, &tcp->inst[1]) < 0
Roland McGrath3291ef22008-05-20 00:34:34 +00001431 || change_syscall(tcp, clone_scno[current_personality]) < 0
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001432 || set_arg0(tcp, &state, CLONE_PTRACE|SIGCHLD) < 0
1433 || set_arg1(tcp, &state, 0) < 0
1434 || arg_finish_change(tcp, &state) < 0)
Roland McGrathd81f1d92003-01-09 06:53:34 +00001435 return -1;
Roland McGrathc9dc3c12004-03-01 20:57:09 +00001436 tcp->u_arg[arg0_index] = CLONE_PTRACE|SIGCHLD;
1437 tcp->u_arg[arg1_index] = 0;
Roland McGrathd81f1d92003-01-09 06:53:34 +00001438 tcp->flags |= TCB_BPTSET;
1439 return 0;
Dmitry V. Levin0c661512012-02-20 21:17:58 +00001440 }
Roland McGrathd81f1d92003-01-09 06:53:34 +00001441
Dmitry V. Levin0c661512012-02-20 21:17:58 +00001442 if (sysent[tcp->scno].sys_func == sys_clone) {
Jan Kratochvil8fc95752008-08-06 21:43:35 +00001443 /* ia64 calls directly `clone (CLONE_VFORK | CLONE_VM)'
Dmitry V. Levin0c661512012-02-20 21:17:58 +00001444 contrary to x86 vfork above. Even on x86 we turn the
Jan Kratochvil8fc95752008-08-06 21:43:35 +00001445 vfork semantics into plain fork - each application must not
1446 depend on the vfork specifics according to POSIX. We would
1447 hang waiting for the parent resume otherwise. We need to
1448 clear also CLONE_VM but only in the CLONE_VFORK case as
1449 otherwise we would break pthread_create. */
1450
Denys Vlasenkoc133bf02011-06-23 21:57:54 +02001451 long new_arg0 = (tcp->u_arg[arg0_index] | CLONE_PTRACE);
1452 if (new_arg0 & CLONE_VFORK)
1453 new_arg0 &= ~(unsigned long)(CLONE_VFORK | CLONE_VM);
1454 if (arg_setup(tcp, &state) < 0
1455 || set_arg0(tcp, &state, new_arg0) < 0
1456 || arg_finish_change(tcp, &state) < 0)
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00001457 return -1;
Roland McGrathd81f1d92003-01-09 06:53:34 +00001458 tcp->flags |= TCB_BPTSET;
Roland McGrathc9dc3c12004-03-01 20:57:09 +00001459 tcp->inst[0] = tcp->u_arg[arg0_index];
1460 tcp->inst[1] = tcp->u_arg[arg1_index];
Roland McGrathd81f1d92003-01-09 06:53:34 +00001461 return 0;
Roland McGrathd81f1d92003-01-09 06:53:34 +00001462 }
1463
Dmitry V. Levin0c661512012-02-20 21:17:58 +00001464 fprintf(stderr, "PANIC: setbpt for syscall %ld on %u???\n",
1465 tcp->scno, tcp->pid);
Roland McGrathd81f1d92003-01-09 06:53:34 +00001466 return -1;
1467}
1468
1469int
Denys Vlasenko12014262011-05-30 14:00:14 +02001470clearbpt(struct tcb *tcp)
Roland McGrathd81f1d92003-01-09 06:53:34 +00001471{
1472 arg_setup_state state;
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001473 if (arg_setup(tcp, &state) < 0
1474 || restore_arg0(tcp, &state, tcp->inst[0]) < 0
1475 || restore_arg1(tcp, &state, tcp->inst[1]) < 0
1476 || arg_finish_change(tcp, &state))
Denys Vlasenkoc133bf02011-06-23 21:57:54 +02001477 if (errno != ESRCH)
1478 return -1;
Roland McGrathd81f1d92003-01-09 06:53:34 +00001479 tcp->flags &= ~TCB_BPTSET;
1480 return 0;
1481}