blob: 73c09ca9966bc5732d854f86812088d2dbe1cd89 [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
44#include <sys/uio.h>
45#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +000046#ifdef SUNOS4
47#include <machine/reg.h>
48#include <a.out.h>
49#include <link.h>
50#endif /* SUNOS4 */
Wichert Akkerman36915a11999-07-13 15:45:02 +000051
Wichert Akkerman43a74822000-06-27 17:33:32 +000052#if defined(linux) && (__GLIBC__ < 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ < 1))
Wichert Akkerman36915a11999-07-13 15:45:02 +000053#include <linux/ptrace.h>
Roland McGrath1e85cf92002-12-16 20:40:54 +000054#endif
Wichert Akkerman36915a11999-07-13 15:45:02 +000055
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +000056#if defined(LINUX) && defined(IA64)
Roland McGrathd81f1d92003-01-09 06:53:34 +000057# include <asm/ptrace_offsets.h>
58# include <asm/rse.h>
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +000059#endif
60
Wichert Akkerman36915a11999-07-13 15:45:02 +000061#ifdef HAVE_SYS_REG_H
62#include <sys/reg.h>
Wichert Akkerman76baf7c1999-02-19 00:21:36 +000063# define PTRACE_PEEKUSR PTRACE_PEEKUSER
Wichert Akkermanfaf72222000-02-19 23:59:03 +000064#elif defined(HAVE_LINUX_PTRACE_H)
65#undef PTRACE_SYSCALL
Roland McGrathce9f0742004-03-01 21:29:22 +000066# ifdef HAVE_STRUCT_IA64_FPREG
67# define ia64_fpreg XXX_ia64_fpreg
68# endif
69# ifdef HAVE_STRUCT_PT_ALL_USER_REGS
70# define pt_all_user_regs XXX_pt_all_user_regs
71# endif
Wichert Akkermanfaf72222000-02-19 23:59:03 +000072#include <linux/ptrace.h>
Roland McGrathce9f0742004-03-01 21:29:22 +000073# undef ia64_fpreg
74# undef pt_all_user_regs
Wichert Akkerman2e2553a1999-05-09 00:29:58 +000075#endif
76
Wichert Akkerman76baf7c1999-02-19 00:21:36 +000077#ifdef SUNOS4_KERNEL_ARCH_KLUDGE
78#include <sys/utsname.h>
79#endif /* SUNOS4_KERNEL_ARCH_KLUDGE */
80
Mike Frysinger8566c502009-10-12 11:05:14 -040081#if defined(LINUXSPARC) && defined (SPARC64)
Roland McGrath6d1a65c2004-07-12 07:44:08 +000082# undef PTRACE_GETREGS
83# define PTRACE_GETREGS PTRACE_GETREGS64
84# undef PTRACE_SETREGS
85# define PTRACE_SETREGS PTRACE_SETREGS64
Wichert Akkerman9ce1a631999-08-29 23:15:07 +000086#endif
87
Wichert Akkerman76baf7c1999-02-19 00:21:36 +000088/* macros */
89#ifndef MAX
90#define MAX(a,b) (((a) > (b)) ? (a) : (b))
91#endif
92#ifndef MIN
93#define MIN(a,b) (((a) < (b)) ? (a) : (b))
94#endif
95
Wichert Akkerman76baf7c1999-02-19 00:21:36 +000096int
Denys Vlasenko12014262011-05-30 14:00:14 +020097tv_nz(struct timeval *a)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +000098{
99 return a->tv_sec || a->tv_usec;
100}
101
102int
Denys Vlasenko12014262011-05-30 14:00:14 +0200103tv_cmp(struct timeval *a, struct timeval *b)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000104{
105 if (a->tv_sec < b->tv_sec
106 || (a->tv_sec == b->tv_sec && a->tv_usec < b->tv_usec))
107 return -1;
108 if (a->tv_sec > b->tv_sec
109 || (a->tv_sec == b->tv_sec && a->tv_usec > b->tv_usec))
110 return 1;
111 return 0;
112}
113
114double
Denys Vlasenko12014262011-05-30 14:00:14 +0200115tv_float(struct timeval *tv)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000116{
117 return tv->tv_sec + tv->tv_usec/1000000.0;
118}
119
120void
Denys Vlasenko12014262011-05-30 14:00:14 +0200121tv_add(struct timeval *tv, struct timeval *a, struct timeval *b)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000122{
123 tv->tv_sec = a->tv_sec + b->tv_sec;
124 tv->tv_usec = a->tv_usec + b->tv_usec;
Roland McGrath58372f52007-07-24 01:38:22 +0000125 if (tv->tv_usec >= 1000000) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000126 tv->tv_sec++;
127 tv->tv_usec -= 1000000;
128 }
129}
130
131void
Denys Vlasenko12014262011-05-30 14:00:14 +0200132tv_sub(struct timeval *tv, struct timeval *a, struct timeval *b)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000133{
134 tv->tv_sec = a->tv_sec - b->tv_sec;
135 tv->tv_usec = a->tv_usec - b->tv_usec;
136 if (((long) tv->tv_usec) < 0) {
137 tv->tv_sec--;
138 tv->tv_usec += 1000000;
139 }
140}
141
142void
Denys Vlasenko12014262011-05-30 14:00:14 +0200143tv_div(struct timeval *tv, struct timeval *a, int n)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000144{
145 tv->tv_usec = (a->tv_sec % n * 1000000 + a->tv_usec + n / 2) / n;
146 tv->tv_sec = a->tv_sec / n + tv->tv_usec / 1000000;
147 tv->tv_usec %= 1000000;
148}
149
150void
Denys Vlasenko12014262011-05-30 14:00:14 +0200151tv_mul(struct timeval *tv, struct timeval *a, int n)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000152{
153 tv->tv_usec = a->tv_usec * n;
Dmitry V. Levinfefdd972007-06-29 21:25:56 +0000154 tv->tv_sec = a->tv_sec * n + tv->tv_usec / 1000000;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000155 tv->tv_usec %= 1000000;
156}
157
Dmitry V. Levinab9008b2007-01-11 22:05:04 +0000158const char *
159xlookup(const struct xlat *xlat, int val)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000160{
161 for (; xlat->str != NULL; xlat++)
162 if (xlat->val == val)
163 return xlat->str;
164 return NULL;
165}
166
Denys Vlasenko0a295bc2011-09-01 16:31:48 +0200167#if !defined HAVE_STPCPY
Denys Vlasenko52845572011-08-31 12:07:38 +0200168char *
169stpcpy(char *dst, const char *src)
170{
171 while ((*dst = *src++) != '\0')
172 dst++;
173 return dst;
174}
Denys Vlasenko0a295bc2011-09-01 16:31:48 +0200175#endif
Denys Vlasenko52845572011-08-31 12:07:38 +0200176
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000177/*
Roland McGratheb9e2e82009-06-02 16:49:22 -0700178 * Generic ptrace wrapper which tracks ESRCH errors
179 * by setting tcp->ptrace_errno to ESRCH.
Denys Vlasenko732d1bf2008-12-17 19:21:59 +0000180 *
181 * We assume that ESRCH indicates likely process death (SIGKILL?),
182 * modulo bugs where process somehow ended up not stopped.
183 * Unfortunately kernel uses ESRCH for that case too. Oh well.
Roland McGratheb9e2e82009-06-02 16:49:22 -0700184 *
185 * Currently used by upeek() only.
186 * TODO: use this in all other ptrace() calls while decoding.
Denys Vlasenko732d1bf2008-12-17 19:21:59 +0000187 */
Denys Vlasenko4dedd562009-02-24 15:17:53 +0000188long
Roland McGratheb9e2e82009-06-02 16:49:22 -0700189do_ptrace(int request, struct tcb *tcp, void *addr, void *data)
Denys Vlasenko4dedd562009-02-24 15:17:53 +0000190{
Denys Vlasenko732d1bf2008-12-17 19:21:59 +0000191 long l;
192
193 errno = 0;
Mike Frysinger09a13c22009-10-07 01:13:39 -0400194 l = ptrace(request, tcp->pid, addr, (long) data);
Roland McGratheb9e2e82009-06-02 16:49:22 -0700195 /* Non-ESRCH errors might be our invalid reg/mem accesses,
196 * we do not record them. */
197 if (errno == ESRCH)
198 tcp->ptrace_errno = ESRCH;
Denys Vlasenko732d1bf2008-12-17 19:21:59 +0000199 return l;
200}
201
202/*
203 * Used when we want to unblock stopped traced process.
204 * Should be only used with PTRACE_CONT, PTRACE_DETACH and PTRACE_SYSCALL.
205 * Returns 0 on success or if error was ESRCH
206 * (presumably process was killed while we talk to it).
207 * Otherwise prints error message and returns -1.
208 */
209int
Roland McGratheb9e2e82009-06-02 16:49:22 -0700210ptrace_restart(int op, struct tcb *tcp, int sig)
Denys Vlasenko732d1bf2008-12-17 19:21:59 +0000211{
212 int err;
Roland McGratheb9e2e82009-06-02 16:49:22 -0700213 const char *msg;
Denys Vlasenko732d1bf2008-12-17 19:21:59 +0000214
215 errno = 0;
Mike Frysinger09a13c22009-10-07 01:13:39 -0400216 ptrace(op, tcp->pid, (void *) 1, (long) sig);
Denys Vlasenko732d1bf2008-12-17 19:21:59 +0000217 err = errno;
218 if (!err || err == ESRCH)
219 return 0;
220
221 tcp->ptrace_errno = err;
Roland McGratheb9e2e82009-06-02 16:49:22 -0700222 msg = "SYSCALL";
223 if (op == PTRACE_CONT)
224 msg = "CONT";
225 if (op == PTRACE_DETACH)
226 msg = "DETACH";
Denys Vlasenko014ca3a2011-09-02 16:19:30 +0200227 perror_msg("ptrace(PTRACE_%s,1,%d)", msg, sig);
Denys Vlasenko732d1bf2008-12-17 19:21:59 +0000228 return -1;
229}
230
231/*
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000232 * Print entry in struct xlat table, if there.
233 */
234void
Dmitry V. Levinab9008b2007-01-11 22:05:04 +0000235printxval(const struct xlat *xlat, int val, const char *dflt)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000236{
Dmitry V. Levinab9008b2007-01-11 22:05:04 +0000237 const char *str = xlookup(xlat, val);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000238
239 if (str)
Denys Vlasenko5940e652011-09-01 09:55:05 +0200240 tprints(str);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000241 else
242 tprintf("%#x /* %s */", val, dflt);
243}
244
Andreas Schwabb5600fc2009-11-04 17:08:34 +0100245#if HAVE_LONG_LONG
246/*
247 * Print 64bit argument at position llarg and return the index of the next
248 * argument.
249 */
250int
251printllval(struct tcb *tcp, const char *format, int llarg)
252{
253# if defined(FREEBSD) \
Andreas Schwabd69fa492010-07-12 21:39:57 +0200254 || (defined(LINUX) && defined(POWERPC) && !defined(POWERPC64)) \
Dmitry V. Levin7a5b08f2011-05-28 20:47:43 +0000255 || defined(LINUX_MIPSO32) \
256 || defined(__ARM_EABI__)
Andreas Schwabb5600fc2009-11-04 17:08:34 +0100257 /* Align 64bit argument to 64bit boundary. */
Denys Vlasenko4b08df42011-08-19 15:58:24 +0200258 llarg = (llarg + 1) & 0x1e;
Andreas Schwabb5600fc2009-11-04 17:08:34 +0100259# endif
Andreas Schwabd69fa492010-07-12 21:39:57 +0200260# if defined LINUX && (defined X86_64 || defined POWERPC64)
Andreas Schwabb5600fc2009-11-04 17:08:34 +0100261 if (current_personality == 0) {
262 tprintf(format, tcp->u_arg[llarg]);
263 llarg++;
264 } else {
Andreas Schwabd69fa492010-07-12 21:39:57 +0200265# ifdef POWERPC64
266 /* Align 64bit argument to 64bit boundary. */
Denys Vlasenko4b08df42011-08-19 15:58:24 +0200267 llarg = (llarg + 1) & 0x1e;
Andreas Schwabd69fa492010-07-12 21:39:57 +0200268# endif
Andreas Schwabb5600fc2009-11-04 17:08:34 +0100269 tprintf(format, LONG_LONG(tcp->u_arg[llarg], tcp->u_arg[llarg + 1]));
270 llarg += 2;
271 }
Andreas Schwabd69fa492010-07-12 21:39:57 +0200272# elif defined IA64 || defined ALPHA
Andreas Schwabb5600fc2009-11-04 17:08:34 +0100273 tprintf(format, tcp->u_arg[llarg]);
274 llarg++;
275# elif defined LINUX_MIPSN32
276 tprintf(format, tcp->ext_arg[llarg]);
277 llarg++;
278# else
279 tprintf(format, LONG_LONG(tcp->u_arg[llarg], tcp->u_arg[llarg + 1]));
280 llarg += 2;
281# endif
282 return llarg;
283}
284#endif
285
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000286/*
287 * Interpret `xlat' as an array of flags
288 * print the entries whose bits are on in `flags'
289 * return # of flags printed.
290 */
Denys Vlasenko4924dbd2011-08-19 18:06:46 +0200291void
Denys Vlasenko12014262011-05-30 14:00:14 +0200292addflags(const struct xlat *xlat, int flags)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000293{
Denys Vlasenko4924dbd2011-08-19 18:06:46 +0200294 for (; xlat->str; xlat++) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000295 if (xlat->val && (flags & xlat->val) == xlat->val) {
296 tprintf("|%s", xlat->str);
297 flags &= ~xlat->val;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000298 }
299 }
300 if (flags) {
301 tprintf("|%#x", flags);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000302 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000303}
304
Roland McGratha6c0d8c2007-11-01 21:46:22 +0000305/*
Denys Vlasenko4924dbd2011-08-19 18:06:46 +0200306 * Interpret `xlat' as an array of flags.
Roland McGratha6c0d8c2007-11-01 21:46:22 +0000307 * Print to static string the entries whose bits are on in `flags'
308 * Return static string.
309 */
310const char *
311sprintflags(const char *prefix, const struct xlat *xlat, int flags)
312{
313 static char outstr[1024];
Denys Vlasenko52845572011-08-31 12:07:38 +0200314 char *outptr;
Roland McGratha6c0d8c2007-11-01 21:46:22 +0000315 int found = 0;
316
Denys Vlasenko52845572011-08-31 12:07:38 +0200317 outptr = stpcpy(outstr, prefix);
Roland McGratha6c0d8c2007-11-01 21:46:22 +0000318
319 for (; xlat->str; xlat++) {
320 if ((flags & xlat->val) == xlat->val) {
321 if (found)
Denys Vlasenko52845572011-08-31 12:07:38 +0200322 *outptr++ = '|';
323 outptr = stpcpy(outptr, xlat->str);
Roland McGratha6c0d8c2007-11-01 21:46:22 +0000324 flags &= ~xlat->val;
325 found = 1;
326 }
327 }
328 if (flags) {
329 if (found)
Denys Vlasenko52845572011-08-31 12:07:38 +0200330 *outptr++ = '|';
331 outptr += sprintf(outptr, "%#x", flags);
Roland McGratha6c0d8c2007-11-01 21:46:22 +0000332 }
333
334 return outstr;
335}
336
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000337int
Dmitry V. Levin30145dd2010-09-06 22:08:24 +0000338printflags(const struct xlat *xlat, int flags, const char *dflt)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000339{
340 int n;
Dmitry V. Levin30145dd2010-09-06 22:08:24 +0000341 const char *sep;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000342
343 if (flags == 0 && xlat->val == 0) {
Denys Vlasenko5940e652011-09-01 09:55:05 +0200344 tprints(xlat->str);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000345 return 1;
346 }
347
348 sep = "";
349 for (n = 0; xlat->str; xlat++) {
350 if (xlat->val && (flags & xlat->val) == xlat->val) {
351 tprintf("%s%s", sep, xlat->str);
352 flags &= ~xlat->val;
353 sep = "|";
354 n++;
355 }
356 }
Roland McGrathb2dee132005-06-01 19:02:36 +0000357
358 if (n) {
359 if (flags) {
360 tprintf("%s%#x", sep, flags);
361 n++;
362 }
363 } else {
364 if (flags) {
365 tprintf("%#x", flags);
366 if (dflt)
367 tprintf(" /* %s */", dflt);
368 } else {
369 if (dflt)
Denys Vlasenko60fe8c12011-09-01 10:00:28 +0200370 tprints("0");
Roland McGrathb2dee132005-06-01 19:02:36 +0000371 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000372 }
Roland McGrathb2dee132005-06-01 19:02:36 +0000373
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000374 return n;
375}
376
377void
Dmitry V. Levin30145dd2010-09-06 22:08:24 +0000378printnum(struct tcb *tcp, long addr, const char *fmt)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000379{
Roland McGratheb285352003-01-14 09:59:00 +0000380 long num;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000381
382 if (!addr) {
Denys Vlasenko60fe8c12011-09-01 10:00:28 +0200383 tprints("NULL");
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000384 return;
385 }
386 if (umove(tcp, addr, &num) < 0) {
387 tprintf("%#lx", addr);
388 return;
389 }
Denys Vlasenko60fe8c12011-09-01 10:00:28 +0200390 tprints("[");
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000391 tprintf(fmt, num);
Denys Vlasenko60fe8c12011-09-01 10:00:28 +0200392 tprints("]");
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000393}
394
Roland McGrath6bc12202003-11-13 22:32:27 +0000395void
Dmitry V. Levin30145dd2010-09-06 22:08:24 +0000396printnum_int(struct tcb *tcp, long addr, const char *fmt)
Roland McGrath9814a942005-07-04 23:28:10 +0000397{
398 int num;
399
400 if (!addr) {
Denys Vlasenko60fe8c12011-09-01 10:00:28 +0200401 tprints("NULL");
Roland McGrath9814a942005-07-04 23:28:10 +0000402 return;
403 }
404 if (umove(tcp, addr, &num) < 0) {
405 tprintf("%#lx", addr);
406 return;
407 }
Denys Vlasenko60fe8c12011-09-01 10:00:28 +0200408 tprints("[");
Roland McGrath9814a942005-07-04 23:28:10 +0000409 tprintf(fmt, num);
Denys Vlasenko60fe8c12011-09-01 10:00:28 +0200410 tprints("]");
Roland McGrath9814a942005-07-04 23:28:10 +0000411}
412
413void
Dmitry V. Levin31382132011-03-04 05:08:02 +0300414printfd(struct tcb *tcp, int fd)
415{
Grant Edwards8a082772011-04-07 20:25:40 +0000416 const char *p;
417
418 if (show_fd_path && (p = getfdpath(tcp, fd)))
419 tprintf("%d<%s>", fd, p);
420 else
421 tprintf("%d", fd);
Dmitry V. Levin31382132011-03-04 05:08:02 +0300422}
423
424void
Denys Vlasenko12014262011-05-30 14:00:14 +0200425printuid(const char *text, unsigned long uid)
Roland McGrath6bc12202003-11-13 22:32:27 +0000426{
Denys Vlasenko5940e652011-09-01 09:55:05 +0200427 tprintf((uid == -1) ? "%s%ld" : "%s%lu", text, uid);
Roland McGrath6bc12202003-11-13 22:32:27 +0000428}
429
Dmitry V. Levina501f142008-11-10 23:19:13 +0000430/*
431 * Quote string `instr' of length `size'
432 * Write up to (3 + `size' * 4) bytes to `outstr' buffer.
433 * If `len' < 0, treat `instr' as a NUL-terminated string
434 * and quote at most (`size' - 1) bytes.
Denys Vlasenko6cecba52012-01-20 11:56:00 +0100435 *
436 * Returns 0 if len < 0 and NUL was seen, 1 otherwise.
437 * Note that if len >= 0, always returns 1.
Dmitry V. Levina501f142008-11-10 23:19:13 +0000438 */
Roland McGrath6d970322007-11-01 23:53:59 +0000439static int
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000440string_quote(const char *instr, char *outstr, int len, int size)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000441{
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000442 const unsigned char *ustr = (const unsigned char *) instr;
443 char *s = outstr;
Denys Vlasenko8778bff2011-08-31 12:22:56 +0200444 int usehex, c, i, eol;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000445
Denys Vlasenko8778bff2011-08-31 12:22:56 +0200446 eol = 0x100; /* this can never match a char */
447 if (len < 0) {
448 size--;
449 eol = '\0';
450 }
451
452 usehex = 0;
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000453 if (xflag > 1)
454 usehex = 1;
455 else if (xflag) {
Dmitry V. Levina501f142008-11-10 23:19:13 +0000456 /* Check for presence of symbol which require
457 to hex-quote the whole string. */
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000458 for (i = 0; i < size; ++i) {
459 c = ustr[i];
Dmitry V. Levina501f142008-11-10 23:19:13 +0000460 /* Check for NUL-terminated string. */
Denys Vlasenko8778bff2011-08-31 12:22:56 +0200461 if (c == eol)
462 break;
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000463 if (!isprint(c) && !isspace(c)) {
464 usehex = 1;
465 break;
466 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000467 }
468 }
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000469
470 *s++ = '\"';
471
472 if (usehex) {
Dmitry V. Levina501f142008-11-10 23:19:13 +0000473 /* Hex-quote the whole string. */
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000474 for (i = 0; i < size; ++i) {
475 c = ustr[i];
Dmitry V. Levina501f142008-11-10 23:19:13 +0000476 /* Check for NUL-terminated string. */
Denys Vlasenko8778bff2011-08-31 12:22:56 +0200477 if (c == eol)
478 goto asciz_ended;
479 *s++ = '\\';
480 *s++ = 'x';
481 *s++ = "0123456789abcdef"[c >> 4];
482 *s++ = "0123456789abcdef"[c & 0xf];
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000483 }
484 } else {
485 for (i = 0; i < size; ++i) {
486 c = ustr[i];
Dmitry V. Levina501f142008-11-10 23:19:13 +0000487 /* Check for NUL-terminated string. */
Denys Vlasenko8778bff2011-08-31 12:22:56 +0200488 if (c == eol)
489 goto asciz_ended;
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000490 switch (c) {
491 case '\"': case '\\':
492 *s++ = '\\';
493 *s++ = c;
494 break;
495 case '\f':
496 *s++ = '\\';
497 *s++ = 'f';
498 break;
499 case '\n':
500 *s++ = '\\';
501 *s++ = 'n';
502 break;
503 case '\r':
504 *s++ = '\\';
505 *s++ = 'r';
506 break;
507 case '\t':
508 *s++ = '\\';
509 *s++ = 't';
510 break;
511 case '\v':
512 *s++ = '\\';
513 *s++ = 'v';
514 break;
515 default:
516 if (isprint(c))
517 *s++ = c;
Denys Vlasenko8778bff2011-08-31 12:22:56 +0200518 else {
519 /* Print \octal */
520 *s++ = '\\';
521 if (i + 1 < size
522 && ustr[i + 1] >= '0'
523 && ustr[i + 1] <= '9'
524 ) {
525 /* Print \ooo */
526 *s++ = '0' + (c >> 6);
527 *s++ = '0' + ((c >> 3) & 0x7);
528 } else {
529 /* Print \[[o]o]o */
530 if ((c >> 3) != 0) {
531 if ((c >> 6) != 0)
532 *s++ = '0' + (c >> 6);
533 *s++ = '0' + ((c >> 3) & 0x7);
534 }
535 }
536 *s++ = '0' + (c & 0x7);
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000537 }
538 break;
539 }
540 }
541 }
542
543 *s++ = '\"';
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000544 *s = '\0';
Roland McGrath6d970322007-11-01 23:53:59 +0000545
Denys Vlasenko8778bff2011-08-31 12:22:56 +0200546 /* Return zero if we printed entire ASCIZ string (didn't truncate it) */
547 if (len < 0 && ustr[i] == '\0') {
548 /* We didn't see NUL yet (otherwise we'd jump to 'asciz_ended')
549 * but next char is NUL.
550 */
551 return 0;
552 }
553
554 return 1;
555
556 asciz_ended:
557 *s++ = '\"';
558 *s = '\0';
559 /* Return zero: we printed entire ASCIZ string (didn't truncate it) */
560 return 0;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000561}
562
Dmitry V. Levina501f142008-11-10 23:19:13 +0000563/*
564 * Print path string specified by address `addr' and length `n'.
565 * If path length exceeds `n', append `...' to the output.
566 */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000567void
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000568printpathn(struct tcb *tcp, long addr, int n)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000569{
Denys Vlasenkob3c52cf2012-01-19 17:20:23 +0100570 char path[MAXPATHLEN + 1];
Denys Vlasenko6cecba52012-01-20 11:56:00 +0100571 int nul_seen;
Denys Vlasenkob3c52cf2012-01-19 17:20:23 +0100572
Dmitry V. Levina501f142008-11-10 23:19:13 +0000573 if (!addr) {
Denys Vlasenko60fe8c12011-09-01 10:00:28 +0200574 tprints("NULL");
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000575 return;
576 }
577
Denys Vlasenko6cecba52012-01-20 11:56:00 +0100578 /* Cap path length to the path buffer size */
Dmitry V. Levina501f142008-11-10 23:19:13 +0000579 if (n > sizeof path - 1)
580 n = sizeof path - 1;
Dmitry V. Levina501f142008-11-10 23:19:13 +0000581
582 /* Fetch one byte more to find out whether path length > n. */
Denys Vlasenko6cecba52012-01-20 11:56:00 +0100583 nul_seen = umovestr(tcp, addr, n + 1, path);
584 if (nul_seen < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000585 tprintf("%#lx", addr);
586 else {
Denys Vlasenkob3c52cf2012-01-19 17:20:23 +0100587 char *outstr;
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000588
Denys Vlasenko6cecba52012-01-20 11:56:00 +0100589 path[n] = '\0';
Denys Vlasenkob3c52cf2012-01-19 17:20:23 +0100590 n++;
Denys Vlasenko6cecba52012-01-20 11:56:00 +0100591 outstr = alloca(4 * n); /* 4*(n-1) + 3 for quotes and NUL */
Denys Vlasenkob3c52cf2012-01-19 17:20:23 +0100592 string_quote(path, outstr, -1, n);
593 tprints(outstr);
Denys Vlasenko6cecba52012-01-20 11:56:00 +0100594 if (!nul_seen)
Denys Vlasenkob3c52cf2012-01-19 17:20:23 +0100595 tprints("...");
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000596 }
597}
598
599void
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000600printpath(struct tcb *tcp, long addr)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000601{
Denys Vlasenkob3c52cf2012-01-19 17:20:23 +0100602 /* Size must correspond to char path[] size in printpathn */
603 printpathn(tcp, addr, MAXPATHLEN);
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000604}
605
Dmitry V. Levina501f142008-11-10 23:19:13 +0000606/*
607 * Print string specified by address `addr' and length `len'.
608 * If `len' < 0, treat the string as a NUL-terminated string.
609 * If string length exceeds `max_strlen', append `...' to the output.
610 */
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000611void
612printstr(struct tcb *tcp, long addr, int len)
613{
614 static char *str = NULL;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000615 static char *outstr;
Roland McGrath6d970322007-11-01 23:53:59 +0000616 int size;
Denys Vlasenkob3c52cf2012-01-19 17:20:23 +0100617 int ellipsis;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000618
619 if (!addr) {
Denys Vlasenko60fe8c12011-09-01 10:00:28 +0200620 tprints("NULL");
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000621 return;
622 }
Dmitry V. Levina501f142008-11-10 23:19:13 +0000623 /* Allocate static buffers if they are not allocated yet. */
Denys Vlasenko1d46ba52011-08-31 14:00:02 +0200624 if (!str) {
Dmitry V. Levina501f142008-11-10 23:19:13 +0000625 str = malloc(max_strlen + 1);
Denys Vlasenko1d46ba52011-08-31 14:00:02 +0200626 if (!str)
627 die_out_of_memory();
Denys Vlasenko6cecba52012-01-20 11:56:00 +0100628 outstr = malloc(4 * max_strlen + /*for quotes and NUL:*/ 3);
Denys Vlasenko1d46ba52011-08-31 14:00:02 +0200629 if (!outstr)
630 die_out_of_memory();
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000631 }
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000632
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000633 if (len < 0) {
Dmitry V. Levina501f142008-11-10 23:19:13 +0000634 /*
635 * Treat as a NUL-terminated string: fetch one byte more
636 * because string_quote() quotes one byte less.
637 */
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000638 size = max_strlen + 1;
639 if (umovestr(tcp, addr, size, str) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000640 tprintf("%#lx", addr);
641 return;
642 }
643 }
644 else {
Dmitry V. Levina501f142008-11-10 23:19:13 +0000645 size = MIN(len, max_strlen);
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000646 if (umoven(tcp, addr, size, str) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000647 tprintf("%#lx", addr);
648 return;
649 }
650 }
651
Denys Vlasenko6cecba52012-01-20 11:56:00 +0100652 /* If string_quote didn't see NUL and (it was supposed to be ASCIZ str
653 * or we were requested to print more than -s NUM chars)...
654 */
Denys Vlasenkob3c52cf2012-01-19 17:20:23 +0100655 ellipsis = (string_quote(str, outstr, len, size) &&
656 (len < 0 || len > max_strlen));
Roland McGratha503dcf2007-08-02 02:06:26 +0000657
Denys Vlasenkob3c52cf2012-01-19 17:20:23 +0100658 tprints(outstr);
659 if (ellipsis)
660 tprints("...");
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000661}
662
John Hughes1d08dcf2001-07-10 13:48:44 +0000663#if HAVE_SYS_UIO_H
664void
Denys Vlasenko12014262011-05-30 14:00:14 +0200665dumpiov(struct tcb *tcp, int len, long addr)
John Hughes1d08dcf2001-07-10 13:48:44 +0000666{
Dmitry V. Levin4ebb4e32006-12-13 17:08:08 +0000667#if defined(LINUX) && SUPPORTED_PERSONALITIES > 1
668 union {
669 struct { u_int32_t base; u_int32_t len; } *iov32;
670 struct { u_int64_t base; u_int64_t len; } *iov64;
671 } iovu;
672#define iov iovu.iov64
673#define sizeof_iov \
674 (personality_wordsize[current_personality] == 4 \
675 ? sizeof(*iovu.iov32) : sizeof(*iovu.iov64))
676#define iov_iov_base(i) \
677 (personality_wordsize[current_personality] == 4 \
678 ? (u_int64_t) iovu.iov32[i].base : iovu.iov64[i].base)
679#define iov_iov_len(i) \
680 (personality_wordsize[current_personality] == 4 \
681 ? (u_int64_t) iovu.iov32[i].len : iovu.iov64[i].len)
682#else
John Hughes1d08dcf2001-07-10 13:48:44 +0000683 struct iovec *iov;
Dmitry V. Levin4ebb4e32006-12-13 17:08:08 +0000684#define sizeof_iov sizeof(*iov)
685#define iov_iov_base(i) iov[i].iov_base
686#define iov_iov_len(i) iov[i].iov_len
687#endif
John Hughes1d08dcf2001-07-10 13:48:44 +0000688 int i;
Denys Vlasenko79a79ea2011-09-01 16:35:44 +0200689 unsigned size;
John Hughes1d08dcf2001-07-10 13:48:44 +0000690
Denys Vlasenko79a79ea2011-09-01 16:35:44 +0200691 size = sizeof_iov * len;
692 /* Assuming no sane program has millions of iovs */
693 if ((unsigned)len > 1024*1024 /* insane or negative size? */
Dmitry V. Levin4ebb4e32006-12-13 17:08:08 +0000694 || (iov = malloc(size)) == NULL) {
Denys Vlasenko79a79ea2011-09-01 16:35:44 +0200695 fprintf(stderr, "Out of memory\n");
696 return;
John Hughes1d08dcf2001-07-10 13:48:44 +0000697 }
Roland McGrathaa524c82005-06-01 19:22:06 +0000698 if (umoven(tcp, addr, size, (char *) iov) >= 0) {
John Hughes1d08dcf2001-07-10 13:48:44 +0000699 for (i = 0; i < len; i++) {
Denys Vlasenkoadedb512008-12-30 18:47:55 +0000700 /* include the buffer number to make it easy to
701 * match up the trace with the source */
702 tprintf(" * %lu bytes in buffer %d\n",
703 (unsigned long)iov_iov_len(i), i);
704 dumpstr(tcp, (long) iov_iov_base(i),
705 iov_iov_len(i));
706 }
John Hughes1d08dcf2001-07-10 13:48:44 +0000707 }
Denys Vlasenko79a79ea2011-09-01 16:35:44 +0200708 free(iov);
Dmitry V. Levin4ebb4e32006-12-13 17:08:08 +0000709#undef sizeof_iov
710#undef iov_iov_base
711#undef iov_iov_len
712#undef iov
John Hughes1d08dcf2001-07-10 13:48:44 +0000713}
714#endif
715
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000716void
Denys Vlasenko12014262011-05-30 14:00:14 +0200717dumpstr(struct tcb *tcp, long addr, int len)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000718{
719 static int strsize = -1;
720 static unsigned char *str;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000721 char *s;
722 int i, j;
723
724 if (strsize < len) {
Denys Vlasenko5d645812011-08-20 12:48:18 +0200725 free(str);
726 str = malloc(len);
Denys Vlasenko79a79ea2011-09-01 16:35:44 +0200727 if (!str) {
728 strsize = -1;
729 fprintf(stderr, "Out of memory\n");
730 return;
731 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000732 strsize = len;
733 }
734
735 if (umoven(tcp, addr, len, (char *) str) < 0)
736 return;
737
738 for (i = 0; i < len; i += 16) {
Denys Vlasenko1d46ba52011-08-31 14:00:02 +0200739 char outstr[80];
740
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000741 s = outstr;
742 sprintf(s, " | %05x ", i);
743 s += 9;
744 for (j = 0; j < 16; j++) {
745 if (j == 8)
746 *s++ = ' ';
747 if (i + j < len) {
748 sprintf(s, " %02x", str[i + j]);
749 s += 3;
750 }
751 else {
752 *s++ = ' '; *s++ = ' '; *s++ = ' ';
753 }
754 }
755 *s++ = ' '; *s++ = ' ';
756 for (j = 0; j < 16; j++) {
757 if (j == 8)
758 *s++ = ' ';
759 if (i + j < len) {
760 if (isprint(str[i + j]))
761 *s++ = str[i + j];
762 else
763 *s++ = '.';
764 }
765 else
766 *s++ = ' ';
767 }
768 tprintf("%s |\n", outstr);
769 }
770}
771
Denys Vlasenko3af224c2012-01-28 01:46:33 +0100772
773/* Need to do this since process_vm_readv() is not yet available in libc.
774 * When libc is be updated, only "static bool process_vm_readv_not_supported"
775 * line should remain.
776 */
777#if !defined(__NR_process_vm_readv)
778# if defined(I386)
779# define __NR_process_vm_readv 347
780# elif defined(X86_64)
781# define __NR_process_vm_readv 310
782# elif defined(POWERPC)
783# define __NR_process_vm_readv 351
784# endif
785#endif
786
787#if defined(__NR_process_vm_readv)
788static bool process_vm_readv_not_supported = 0;
789static ssize_t process_vm_readv(pid_t pid,
790 const struct iovec *lvec,
791 unsigned long liovcnt,
792 const struct iovec *rvec,
793 unsigned long riovcnt,
794 unsigned long flags)
795{
796 return syscall(__NR_process_vm_readv, (long)pid, lvec, liovcnt, rvec, riovcnt, flags);
797}
798#else
799static bool process_vm_readv_not_supported = 1;
800# define process_vm_readv(...) (errno = ENOSYS, -1)
801#endif
802/* end of hack */
803
804
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000805#define PAGMASK (~(PAGSIZ - 1))
806/*
807 * move `len' bytes of data from process `pid'
808 * at address `addr' to our space at `laddr'
809 */
810int
Denys Vlasenkoef2fbf82009-01-06 21:45:06 +0000811umoven(struct tcb *tcp, long addr, int len, char *laddr)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000812{
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000813#ifdef LINUX
Roland McGratheb9e2e82009-06-02 16:49:22 -0700814 int pid = tcp->pid;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000815 int n, m;
Denys Vlasenkoa47e6b92012-01-21 04:01:56 +0100816 int started;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000817 union {
818 long val;
819 char x[sizeof(long)];
820 } u;
821
Denys Vlasenko3af224c2012-01-28 01:46:33 +0100822 if (!process_vm_readv_not_supported) {
823 struct iovec local[1], remote[1];
824 int r;
825
826 local[0].iov_base = laddr;
827 remote[0].iov_base = (void*)addr;
828 local[0].iov_len = remote[0].iov_len = len;
829 r = process_vm_readv(pid,
830 local, 1,
831 remote, 1,
832 /*flags:*/ 0
833 );
834 if (r < 0) {
835 if (errno == ENOSYS)
836 process_vm_readv_not_supported = 1;
Denys Vlasenko29456392012-01-28 02:49:48 +0100837 else if (errno != EINVAL) /* EINVAL is seen if process is gone */
838 /* strange... */
Denys Vlasenko3af224c2012-01-28 01:46:33 +0100839 perror("process_vm_readv");
840 goto vm_readv_didnt_work;
841 }
842 return r;
843 }
844 vm_readv_didnt_work:
845
Dmitry V. Levin856c7ed2011-12-26 20:12:02 +0000846#if SUPPORTED_PERSONALITIES > 1
847 if (personality_wordsize[current_personality] < sizeof(addr))
848 addr &= (1ul << 8 * personality_wordsize[current_personality]) - 1;
849#endif
850
Denys Vlasenkoa47e6b92012-01-21 04:01:56 +0100851 started = 0;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000852 if (addr & (sizeof(long) - 1)) {
853 /* addr not a multiple of sizeof(long) */
854 n = addr - (addr & -sizeof(long)); /* residue */
855 addr &= -sizeof(long); /* residue */
Roland McGratheb9e2e82009-06-02 16:49:22 -0700856 errno = 0;
857 u.val = ptrace(PTRACE_PEEKDATA, pid, (char *) addr, 0);
858 if (errno) {
Roland McGratheb9e2e82009-06-02 16:49:22 -0700859 /* But if not started, we had a bogus address. */
860 if (addr != 0 && errno != EIO && errno != ESRCH)
861 perror("ptrace: umoven");
862 return -1;
863 }
Wichert Akkerman5daa0281999-03-15 19:49:42 +0000864 started = 1;
Denys Vlasenkoa47e6b92012-01-21 04:01:56 +0100865 m = MIN(sizeof(long) - n, len);
866 memcpy(laddr, &u.x[n], m);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000867 addr += sizeof(long), laddr += m, len -= m;
868 }
869 while (len) {
Roland McGratheb9e2e82009-06-02 16:49:22 -0700870 errno = 0;
871 u.val = ptrace(PTRACE_PEEKDATA, pid, (char *) addr, 0);
872 if (errno) {
873 if (started && (errno==EPERM || errno==EIO)) {
874 /* Ran into 'end of memory' - stupid "printpath" */
875 return 0;
876 }
877 if (addr != 0 && errno != EIO && errno != ESRCH)
878 perror("ptrace: umoven");
879 return -1;
880 }
Wichert Akkerman5daa0281999-03-15 19:49:42 +0000881 started = 1;
Denys Vlasenkoa47e6b92012-01-21 04:01:56 +0100882 m = MIN(sizeof(long), len);
883 memcpy(laddr, u.x, m);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000884 addr += sizeof(long), laddr += m, len -= m;
885 }
886#endif /* LINUX */
887
888#ifdef SUNOS4
889 int pid = tcp->pid;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000890 int n;
891
892 while (len) {
893 n = MIN(len, PAGSIZ);
894 n = MIN(n, ((addr + PAGSIZ) & PAGMASK) - addr);
Roland McGratheb9e2e82009-06-02 16:49:22 -0700895 if (ptrace(PTRACE_READDATA, pid,
896 (char *) addr, len, laddr) < 0) {
897 if (errno != ESRCH) {
898 perror("umoven: ptrace(PTRACE_READDATA, ...)");
899 abort();
900 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000901 return -1;
902 }
903 len -= n;
904 addr += n;
905 laddr += n;
906 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000907#endif /* SUNOS4 */
908
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000909#ifdef USE_PROCFS
Wichert Akkermanea78f0f1999-11-29 15:34:02 +0000910#ifdef HAVE_MP_PROCFS
John Hughesaa09c6b2001-05-15 14:53:43 +0000911 int fd = tcp->pfd_as;
Wichert Akkerman9ce1a631999-08-29 23:15:07 +0000912#else
John Hughesaa09c6b2001-05-15 14:53:43 +0000913 int fd = tcp->pfd;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000914#endif
John Hughesaa09c6b2001-05-15 14:53:43 +0000915 lseek(fd, addr, SEEK_SET);
916 if (read(fd, laddr, len) == -1)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000917 return -1;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000918#endif /* USE_PROCFS */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000919
920 return 0;
921}
922
923/*
Denys Vlasenko6cecba52012-01-20 11:56:00 +0100924 * Like `umove' but make the additional effort of looking
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000925 * for a terminating zero byte.
Denys Vlasenko6cecba52012-01-20 11:56:00 +0100926 *
927 * Returns < 0 on error, > 0 if NUL was seen,
928 * (TODO if useful: return count of bytes including NUL),
929 * else 0 if len bytes were read but no NUL byte seen.
930 *
931 * Note: there is no guarantee we won't overwrite some bytes
932 * in laddr[] _after_ terminating NUL (but, of course,
933 * we never write past laddr[len-1]).
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000934 */
935int
Denys Vlasenkoef2fbf82009-01-06 21:45:06 +0000936umovestr(struct tcb *tcp, long addr, int len, char *laddr)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000937{
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000938#ifdef USE_PROCFS
Denys Vlasenkoa47e6b92012-01-21 04:01:56 +0100939# ifdef HAVE_MP_PROCFS
John Hughesaa09c6b2001-05-15 14:53:43 +0000940 int fd = tcp->pfd_as;
Denys Vlasenkoa47e6b92012-01-21 04:01:56 +0100941# else
John Hughesaa09c6b2001-05-15 14:53:43 +0000942 int fd = tcp->pfd;
Denys Vlasenkoa47e6b92012-01-21 04:01:56 +0100943# endif
John Hughesaa09c6b2001-05-15 14:53:43 +0000944 /* Some systems (e.g. FreeBSD) can be upset if we read off the
945 end of valid memory, avoid this by trying to read up
946 to page boundaries. But we don't know what a page is (and
947 getpagesize(2) (if it exists) doesn't necessarily return
948 hardware page size). Assume all pages >= 1024 (a-historical
949 I know) */
950
Denys Vlasenkob63256e2011-06-07 12:13:24 +0200951 int page = 1024; /* How to find this? */
John Hughesaa09c6b2001-05-15 14:53:43 +0000952 int move = page - (addr & (page - 1));
953 int left = len;
954
955 lseek(fd, addr, SEEK_SET);
956
957 while (left) {
Denys Vlasenko5d645812011-08-20 12:48:18 +0200958 if (move > left)
959 move = left;
960 move = read(fd, laddr, move);
961 if (move <= 0)
John Hughesaa09c6b2001-05-15 14:53:43 +0000962 return left != len ? 0 : -1;
Denys Vlasenko5d645812011-08-20 12:48:18 +0200963 if (memchr(laddr, 0, move))
Denys Vlasenko6cecba52012-01-20 11:56:00 +0100964 return 1;
John Hughesaa09c6b2001-05-15 14:53:43 +0000965 left -= move;
966 laddr += move;
967 addr += move;
968 move = page;
969 }
Denys Vlasenkoa47e6b92012-01-21 04:01:56 +0100970 return 0;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000971#else /* !USE_PROCFS */
Denys Vlasenkoa47e6b92012-01-21 04:01:56 +0100972 int started;
Roland McGratheb9e2e82009-06-02 16:49:22 -0700973 int pid = tcp->pid;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000974 int i, n, m;
975 union {
976 long val;
977 char x[sizeof(long)];
978 } u;
979
Dmitry V. Levin856c7ed2011-12-26 20:12:02 +0000980#if SUPPORTED_PERSONALITIES > 1
981 if (personality_wordsize[current_personality] < sizeof(addr))
982 addr &= (1ul << 8 * personality_wordsize[current_personality]) - 1;
983#endif
984
Denys Vlasenko3af224c2012-01-28 01:46:33 +0100985 if (!process_vm_readv_not_supported) {
986 struct iovec local[1], remote[1];
987
988 local[0].iov_base = laddr;
989 remote[0].iov_base = (void*)addr;
990
991 while (len > 0) {
992 int end_in_page;
993 int r;
994 int chunk_len;
995
996 /* Don't read kilobytes: most strings are short */
997 chunk_len = len;
998 if (chunk_len > 256)
999 chunk_len = 256;
1000 /* Don't cross pages. I guess otherwise we can get EFAULT
1001 * and fail to notice that terminating NUL lies
1002 * in the existing (first) page.
1003 * (I hope there aren't arches with pages < 4K)
1004 */
1005 end_in_page = ((addr + chunk_len) & 4095);
1006 r = chunk_len - end_in_page;
1007 if (r > 0) /* if chunk_len > end_in_page */
1008 chunk_len = r; /* chunk_len -= end_in_page */
1009
1010 local[0].iov_len = remote[0].iov_len = chunk_len;
1011 r = process_vm_readv(pid,
1012 local, 1,
1013 remote, 1,
1014 /*flags:*/ 0
1015 );
1016 if (r < 0) {
1017 if (errno == ENOSYS)
1018 process_vm_readv_not_supported = 1;
Denys Vlasenko29456392012-01-28 02:49:48 +01001019 else if (errno != EINVAL) /* EINVAL is seen if process is gone */
1020 /* strange... */
Denys Vlasenko3af224c2012-01-28 01:46:33 +01001021 perror("process_vm_readv");
1022 goto vm_readv_didnt_work;
1023 }
1024 if (memchr(local[0].iov_base, '\0', r))
1025 return 1;
1026 local[0].iov_base += r;
1027 remote[0].iov_base += r;
1028 len -= r;
1029 }
1030 return 0;
1031 }
1032 vm_readv_didnt_work:
1033
Denys Vlasenkoa47e6b92012-01-21 04:01:56 +01001034 started = 0;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001035 if (addr & (sizeof(long) - 1)) {
1036 /* addr not a multiple of sizeof(long) */
1037 n = addr - (addr & -sizeof(long)); /* residue */
1038 addr &= -sizeof(long); /* residue */
Roland McGratheb9e2e82009-06-02 16:49:22 -07001039 errno = 0;
1040 u.val = ptrace(PTRACE_PEEKDATA, pid, (char *)addr, 0);
1041 if (errno) {
Roland McGratheb9e2e82009-06-02 16:49:22 -07001042 if (addr != 0 && errno != EIO && errno != ESRCH)
1043 perror("umovestr");
1044 return -1;
1045 }
Wichert Akkerman5daa0281999-03-15 19:49:42 +00001046 started = 1;
Denys Vlasenkoa47e6b92012-01-21 04:01:56 +01001047 m = MIN(sizeof(long) - n, len);
1048 memcpy(laddr, &u.x[n], m);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001049 while (n & (sizeof(long) - 1))
1050 if (u.x[n++] == '\0')
Denys Vlasenko6cecba52012-01-20 11:56:00 +01001051 return 1;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001052 addr += sizeof(long), laddr += m, len -= m;
1053 }
1054 while (len) {
Roland McGratheb9e2e82009-06-02 16:49:22 -07001055 errno = 0;
1056 u.val = ptrace(PTRACE_PEEKDATA, pid, (char *)addr, 0);
1057 if (errno) {
1058 if (started && (errno==EPERM || errno==EIO)) {
1059 /* Ran into 'end of memory' - stupid "printpath" */
1060 return 0;
1061 }
1062 if (addr != 0 && errno != EIO && errno != ESRCH)
1063 perror("umovestr");
1064 return -1;
1065 }
Wichert Akkerman5daa0281999-03-15 19:49:42 +00001066 started = 1;
Denys Vlasenkoa47e6b92012-01-21 04:01:56 +01001067 m = MIN(sizeof(long), len);
1068 memcpy(laddr, u.x, m);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001069 for (i = 0; i < sizeof(long); i++)
1070 if (u.x[i] == '\0')
Denys Vlasenko6cecba52012-01-20 11:56:00 +01001071 return 1;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001072 addr += sizeof(long), laddr += m, len -= m;
1073 }
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001074#endif /* !USE_PROCFS */
John Hughesaa09c6b2001-05-15 14:53:43 +00001075 return 0;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001076}
1077
1078#ifdef LINUX
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001079# if !defined (SPARC) && !defined(SPARC64)
1080# define PTRACE_WRITETEXT 101
1081# define PTRACE_WRITEDATA 102
1082# endif /* !SPARC && !SPARC64 */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001083#endif /* LINUX */
1084
1085#ifdef SUNOS4
1086
1087static int
Denys Vlasenko12014262011-05-30 14:00:14 +02001088uload(int cmd, int pid, long addr, int len, char *laddr)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001089{
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001090 int peek, poke;
1091 int n, m;
1092 union {
1093 long val;
1094 char x[sizeof(long)];
1095 } u;
1096
1097 if (cmd == PTRACE_WRITETEXT) {
1098 peek = PTRACE_PEEKTEXT;
1099 poke = PTRACE_POKETEXT;
1100 }
1101 else {
1102 peek = PTRACE_PEEKDATA;
1103 poke = PTRACE_POKEDATA;
1104 }
1105 if (addr & (sizeof(long) - 1)) {
1106 /* addr not a multiple of sizeof(long) */
1107 n = addr - (addr & -sizeof(long)); /* residue */
1108 addr &= -sizeof(long);
Roland McGratheb9e2e82009-06-02 16:49:22 -07001109 errno = 0;
1110 u.val = ptrace(peek, pid, (char *) addr, 0);
1111 if (errno) {
1112 perror("uload: POKE");
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001113 return -1;
1114 }
Denys Vlasenkoa47e6b92012-01-21 04:01:56 +01001115 m = MIN(sizeof(long) - n, len);
1116 memcpy(&u.x[n], laddr, m);
Roland McGratheb9e2e82009-06-02 16:49:22 -07001117 if (ptrace(poke, pid, (char *)addr, u.val) < 0) {
1118 perror("uload: POKE");
1119 return -1;
1120 }
1121 addr += sizeof(long), laddr += m, len -= m;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001122 }
1123 while (len) {
1124 if (len < sizeof(long))
Roland McGratheb9e2e82009-06-02 16:49:22 -07001125 u.val = ptrace(peek, pid, (char *) addr, 0);
Denys Vlasenkoa47e6b92012-01-21 04:01:56 +01001126 m = MIN(sizeof(long), len);
1127 memcpy(u.x, laddr, m);
Roland McGratheb9e2e82009-06-02 16:49:22 -07001128 if (ptrace(poke, pid, (char *) addr, u.val) < 0) {
1129 perror("uload: POKE");
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001130 return -1;
1131 }
Roland McGratheb9e2e82009-06-02 16:49:22 -07001132 addr += sizeof(long), laddr += m, len -= m;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001133 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001134 return 0;
1135}
1136
Roland McGratheb9e2e82009-06-02 16:49:22 -07001137int
Denys Vlasenko12014262011-05-30 14:00:14 +02001138tload(int pid, int addr, int len, char *laddr)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001139{
Roland McGratheb9e2e82009-06-02 16:49:22 -07001140 return uload(PTRACE_WRITETEXT, pid, addr, len, laddr);
1141}
1142
1143int
Denys Vlasenko12014262011-05-30 14:00:14 +02001144dload(int pid, int addr, int len, char *laddr)
Roland McGratheb9e2e82009-06-02 16:49:22 -07001145{
1146 return uload(PTRACE_WRITEDATA, pid, addr, len, laddr);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001147}
1148
1149#endif /* SUNOS4 */
1150
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001151#ifndef USE_PROCFS
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001152
1153int
Denys Vlasenko12014262011-05-30 14:00:14 +02001154upeek(struct tcb *tcp, long off, long *res)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001155{
1156 long val;
1157
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001158# ifdef SUNOS4_KERNEL_ARCH_KLUDGE
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001159 {
1160 static int is_sun4m = -1;
1161 struct utsname name;
1162
1163 /* Round up the usual suspects. */
1164 if (is_sun4m == -1) {
1165 if (uname(&name) < 0) {
1166 perror("upeek: uname?");
1167 exit(1);
1168 }
1169 is_sun4m = strcmp(name.machine, "sun4m") == 0;
1170 if (is_sun4m) {
Roland McGrathd9f816f2004-09-04 03:39:20 +00001171 const struct xlat *x;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001172
1173 for (x = struct_user_offsets; x->str; x++)
1174 x->val += 1024;
1175 }
1176 }
1177 if (is_sun4m)
1178 off += 1024;
1179 }
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001180# endif /* SUNOS4_KERNEL_ARCH_KLUDGE */
Roland McGratheb9e2e82009-06-02 16:49:22 -07001181 errno = 0;
Denys Vlasenko732d1bf2008-12-17 19:21:59 +00001182 val = do_ptrace(PTRACE_PEEKUSER, tcp, (char *) off, 0);
Roland McGratheb9e2e82009-06-02 16:49:22 -07001183 if (val == -1 && errno) {
1184 if (errno != ESRCH) {
1185 char buf[60];
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001186 sprintf(buf, "upeek: ptrace(PTRACE_PEEKUSER,%d,%lu,0)", tcp->pid, off);
Roland McGratheb9e2e82009-06-02 16:49:22 -07001187 perror(buf);
1188 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001189 return -1;
Roland McGratheb9e2e82009-06-02 16:49:22 -07001190 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001191 *res = val;
1192 return 0;
1193}
1194
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001195#endif /* !USE_PROCFS */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001196
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001197void
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001198printcall(struct tcb *tcp)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001199{
Roland McGrath7a918832005-02-02 20:55:23 +00001200#define PRINTBADPC tprintf(sizeof(long) == 4 ? "[????????] " : \
1201 sizeof(long) == 8 ? "[????????????????] " : \
1202 NULL /* crash */)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001203
1204#ifdef LINUX
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001205# ifdef I386
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001206 long eip;
1207
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001208 if (upeek(tcp, 4*EIP, &eip) < 0) {
Roland McGrath7a918832005-02-02 20:55:23 +00001209 PRINTBADPC;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001210 return;
1211 }
1212 tprintf("[%08lx] ", eip);
Roland McGratheac26fc2005-02-02 02:48:53 +00001213
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001214# elif defined(S390) || defined(S390X)
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001215 long psw;
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001216 if (upeek(tcp, PT_PSWADDR, &psw) < 0) {
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001217 PRINTBADPC;
1218 return;
1219 }
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001220# ifdef S390
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001221 tprintf("[%08lx] ", psw);
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001222# elif S390X
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001223 tprintf("[%16lx] ", psw);
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001224# endif
Roland McGratheac26fc2005-02-02 02:48:53 +00001225
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001226# elif defined(X86_64)
Michal Ludvig0e035502002-09-23 15:41:01 +00001227 long rip;
1228
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001229 if (upeek(tcp, 8*RIP, &rip) < 0) {
Roland McGrath7a918832005-02-02 20:55:23 +00001230 PRINTBADPC;
Michal Ludvig0e035502002-09-23 15:41:01 +00001231 return;
1232 }
1233 tprintf("[%16lx] ", rip);
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001234# elif defined(IA64)
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00001235 long ip;
1236
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001237 if (upeek(tcp, PT_B0, &ip) < 0) {
Roland McGrath7a918832005-02-02 20:55:23 +00001238 PRINTBADPC;
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00001239 return;
1240 }
1241 tprintf("[%08lx] ", ip);
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001242# elif defined(POWERPC)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001243 long pc;
1244
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001245 if (upeek(tcp, sizeof(unsigned long)*PT_NIP, &pc) < 0) {
Andreas Schwabd69fa492010-07-12 21:39:57 +02001246 PRINTBADPC;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001247 return;
1248 }
Andreas Schwabd69fa492010-07-12 21:39:57 +02001249# ifdef POWERPC64
1250 tprintf("[%016lx] ", pc);
1251# else
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001252 tprintf("[%08lx] ", pc);
Andreas Schwabd69fa492010-07-12 21:39:57 +02001253# endif
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001254# elif defined(M68K)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001255 long pc;
1256
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001257 if (upeek(tcp, 4*PT_PC, &pc) < 0) {
Denys Vlasenko60fe8c12011-09-01 10:00:28 +02001258 tprints("[????????] ");
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001259 return;
1260 }
1261 tprintf("[%08lx] ", pc);
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001262# elif defined(ALPHA)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001263 long pc;
1264
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001265 if (upeek(tcp, REG_PC, &pc) < 0) {
Denys Vlasenko60fe8c12011-09-01 10:00:28 +02001266 tprints("[????????????????] ");
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001267 return;
1268 }
1269 tprintf("[%08lx] ", pc);
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001270# elif defined(SPARC) || defined(SPARC64)
Mike Frysinger8566c502009-10-12 11:05:14 -04001271 struct pt_regs regs;
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001272 if (ptrace(PTRACE_GETREGS, tcp->pid, (char *)&regs, 0) < 0) {
Roland McGrath7a918832005-02-02 20:55:23 +00001273 PRINTBADPC;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001274 return;
1275 }
Mike Frysinger8566c502009-10-12 11:05:14 -04001276# if defined(SPARC64)
1277 tprintf("[%08lx] ", regs.tpc);
1278# else
1279 tprintf("[%08lx] ", regs.pc);
1280# endif
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001281# elif defined(HPPA)
Wichert Akkermanc1652e22001-03-27 12:17:16 +00001282 long pc;
1283
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001284 if (upeek(tcp, PT_IAOQ0, &pc) < 0) {
Denys Vlasenko60fe8c12011-09-01 10:00:28 +02001285 tprints("[????????] ");
Wichert Akkermanc1652e22001-03-27 12:17:16 +00001286 return;
1287 }
1288 tprintf("[%08lx] ", pc);
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001289# elif defined(MIPS)
Wichert Akkerman75c422b2001-04-10 10:22:50 +00001290 long pc;
1291
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001292 if (upeek(tcp, REG_EPC, &pc) < 0) {
Denys Vlasenko60fe8c12011-09-01 10:00:28 +02001293 tprints("[????????] ");
Wichert Akkerman75c422b2001-04-10 10:22:50 +00001294 return;
1295 }
1296 tprintf("[%08lx] ", pc);
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001297# elif defined(SH)
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001298 long pc;
Wichert Akkermanccef6372002-05-01 16:39:22 +00001299
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001300 if (upeek(tcp, 4*REG_PC, &pc) < 0) {
Denys Vlasenko60fe8c12011-09-01 10:00:28 +02001301 tprints("[????????] ");
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001302 return;
1303 }
1304 tprintf("[%08lx] ", pc);
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001305# elif defined(SH64)
Roland McGrathe1e584b2003-06-02 19:18:58 +00001306 long pc;
1307
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001308 if (upeek(tcp, REG_PC, &pc) < 0) {
Denys Vlasenko60fe8c12011-09-01 10:00:28 +02001309 tprints("[????????????????] ");
Roland McGrathe1e584b2003-06-02 19:18:58 +00001310 return;
1311 }
1312 tprintf("[%08lx] ", pc);
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001313# elif defined(ARM)
Roland McGrathef388682003-06-03 23:28:59 +00001314 long pc;
Roland McGrathe1e584b2003-06-02 19:18:58 +00001315
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001316 if (upeek(tcp, 4*15, &pc) < 0) {
Roland McGrath7a918832005-02-02 20:55:23 +00001317 PRINTBADPC;
Roland McGrathef388682003-06-03 23:28:59 +00001318 return;
1319 }
1320 tprintf("[%08lx] ", pc);
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00001321# elif defined(AVR32)
1322 long pc;
1323
1324 if (upeek(tcp, REG_PC, &pc) < 0) {
Denys Vlasenko60fe8c12011-09-01 10:00:28 +02001325 tprints("[????????] ");
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00001326 return;
1327 }
1328 tprintf("[%08lx] ", pc);
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001329# elif defined(BFIN)
Dmitry V. Levin87ea1f42008-11-10 22:21:41 +00001330 long pc;
1331
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001332 if (upeek(tcp, PT_PC, &pc) < 0) {
Dmitry V. Levin87ea1f42008-11-10 22:21:41 +00001333 PRINTBADPC;
1334 return;
1335 }
1336 tprintf("[%08lx] ", pc);
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001337#elif defined(CRISV10)
1338 long pc;
1339
Edgar E. Iglesiaseeb9ce32009-10-05 14:41:02 +00001340 if (upeek(tcp, 4*PT_IRP, &pc) < 0) {
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001341 PRINTBADPC;
1342 return;
1343 }
1344 tprintf("[%08lx] ", pc);
1345#elif defined(CRISV32)
1346 long pc;
1347
Edgar E. Iglesiaseeb9ce32009-10-05 14:41:02 +00001348 if (upeek(tcp, 4*PT_ERP, &pc) < 0) {
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001349 PRINTBADPC;
1350 return;
1351 }
1352 tprintf("[%08lx] ", pc);
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001353# endif /* architecture */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001354#endif /* LINUX */
1355
1356#ifdef SUNOS4
1357 struct regs regs;
1358
Roland McGratheb9e2e82009-06-02 16:49:22 -07001359 if (ptrace(PTRACE_GETREGS, tcp->pid, (char *) &regs, 0) < 0) {
1360 perror("printcall: ptrace(PTRACE_GETREGS, ...)");
Roland McGrath7a918832005-02-02 20:55:23 +00001361 PRINTBADPC;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001362 return;
1363 }
1364 tprintf("[%08x] ", regs.r_o7);
1365#endif /* SUNOS4 */
1366
1367#ifdef SVR4
1368 /* XXX */
Roland McGrath7a918832005-02-02 20:55:23 +00001369 PRINTBADPC;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001370#endif
1371
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001372#ifdef FREEBSD
1373 struct reg regs;
1374 pread(tcp->pfd_reg, &regs, sizeof(regs), 0);
1375 tprintf("[%08x] ", regs.r_eip);
1376#endif /* FREEBSD */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001377}
1378
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001379
1380/*
1381 * These #if's are huge, please indent them correctly.
1382 * It's easy to get confused otherwise.
1383 */
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001384#ifndef USE_PROCFS
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001385
Denys Vlasenkoe7c90242011-06-22 00:09:25 +02001386# ifdef LINUX
Roland McGrathd81f1d92003-01-09 06:53:34 +00001387
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001388# include "syscall.h"
Roland McGrath3291ef22008-05-20 00:34:34 +00001389
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001390# include <sys/syscall.h>
1391# ifndef CLONE_PTRACE
1392# define CLONE_PTRACE 0x00002000
1393# endif
1394# ifndef CLONE_VFORK
1395# define CLONE_VFORK 0x00004000
1396# endif
1397# ifndef CLONE_VM
1398# define CLONE_VM 0x00000100
1399# endif
1400# ifndef CLONE_STOPPED
1401# define CLONE_STOPPED 0x02000000
1402# endif
Roland McGrathd81f1d92003-01-09 06:53:34 +00001403
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001404# ifdef IA64
Roland McGrathd81f1d92003-01-09 06:53:34 +00001405
Roland McGrath08267b82004-02-20 22:56:43 +00001406/* We don't have fork()/vfork() syscalls on ia64 itself, but the ia32
1407 subsystem has them for x86... */
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001408# define SYS_fork 2
1409# define SYS_vfork 190
Roland McGrath08267b82004-02-20 22:56:43 +00001410
Roland McGrathd81f1d92003-01-09 06:53:34 +00001411typedef unsigned long *arg_setup_state;
1412
1413static int
1414arg_setup(struct tcb *tcp, arg_setup_state *state)
1415{
Jan Kratochvil1f942712008-08-06 21:38:52 +00001416 unsigned long cfm, sof, sol;
1417 long bsp;
Roland McGrathd81f1d92003-01-09 06:53:34 +00001418
Jan Kratochvil1f942712008-08-06 21:38:52 +00001419 if (ia32) {
1420 /* Satisfy a false GCC warning. */
1421 *state = NULL;
Roland McGrath08267b82004-02-20 22:56:43 +00001422 return 0;
Jan Kratochvil1f942712008-08-06 21:38:52 +00001423 }
Roland McGrath08267b82004-02-20 22:56:43 +00001424
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001425 if (upeek(tcp, PT_AR_BSP, &bsp) < 0)
Roland McGrathd81f1d92003-01-09 06:53:34 +00001426 return -1;
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001427 if (upeek(tcp, PT_CFM, (long *) &cfm) < 0)
Roland McGrathd81f1d92003-01-09 06:53:34 +00001428 return -1;
1429
1430 sof = (cfm >> 0) & 0x7f;
1431 sol = (cfm >> 7) & 0x7f;
Jan Kratochvil1f942712008-08-06 21:38:52 +00001432 bsp = (long) ia64_rse_skip_regs((unsigned long *) bsp, -sof + sol);
Roland McGrathd81f1d92003-01-09 06:53:34 +00001433
Jan Kratochvil1f942712008-08-06 21:38:52 +00001434 *state = (unsigned long *) bsp;
Roland McGrathd81f1d92003-01-09 06:53:34 +00001435 return 0;
1436}
1437
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001438# define arg_finish_change(tcp, state) 0
Roland McGrathd81f1d92003-01-09 06:53:34 +00001439
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001440# ifdef SYS_fork
Roland McGrathd81f1d92003-01-09 06:53:34 +00001441static int
Denys Vlasenko12014262011-05-30 14:00:14 +02001442get_arg0(struct tcb *tcp, arg_setup_state *state, long *valp)
Roland McGrathd81f1d92003-01-09 06:53:34 +00001443{
Roland McGrath08267b82004-02-20 22:56:43 +00001444 int ret;
1445
1446 if (ia32)
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001447 ret = upeek(tcp, PT_R11, valp);
Roland McGrath08267b82004-02-20 22:56:43 +00001448 else
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001449 ret = umoven(tcp,
Roland McGrath08267b82004-02-20 22:56:43 +00001450 (unsigned long) ia64_rse_skip_regs(*state, 0),
1451 sizeof(long), (void *) valp);
1452 return ret;
Roland McGrathd81f1d92003-01-09 06:53:34 +00001453}
1454
1455static int
Denys Vlasenko12014262011-05-30 14:00:14 +02001456get_arg1(struct tcb *tcp, arg_setup_state *state, long *valp)
Roland McGrathd81f1d92003-01-09 06:53:34 +00001457{
Roland McGrath08267b82004-02-20 22:56:43 +00001458 int ret;
1459
1460 if (ia32)
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001461 ret = upeek(tcp, PT_R9, valp);
Roland McGrath08267b82004-02-20 22:56:43 +00001462 else
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001463 ret = umoven(tcp,
Roland McGrath08267b82004-02-20 22:56:43 +00001464 (unsigned long) ia64_rse_skip_regs(*state, 1),
1465 sizeof(long), (void *) valp);
1466 return ret;
Roland McGrathd81f1d92003-01-09 06:53:34 +00001467}
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001468# endif
Roland McGrathd81f1d92003-01-09 06:53:34 +00001469
1470static int
Denys Vlasenko12014262011-05-30 14:00:14 +02001471set_arg0(struct tcb *tcp, arg_setup_state *state, long val)
Roland McGrathd81f1d92003-01-09 06:53:34 +00001472{
Roland McGrath08267b82004-02-20 22:56:43 +00001473 int req = PTRACE_POKEDATA;
1474 void *ap;
1475
1476 if (ia32) {
1477 ap = (void *) (intptr_t) PT_R11; /* r11 == EBX */
1478 req = PTRACE_POKEUSER;
1479 } else
1480 ap = ia64_rse_skip_regs(*state, 0);
Roland McGratheb9e2e82009-06-02 16:49:22 -07001481 errno = 0;
1482 ptrace(req, tcp->pid, ap, val);
1483 return errno ? -1 : 0;
Roland McGrathd81f1d92003-01-09 06:53:34 +00001484}
1485
1486static int
Denys Vlasenko12014262011-05-30 14:00:14 +02001487set_arg1(struct tcb *tcp, arg_setup_state *state, long val)
Roland McGrathd81f1d92003-01-09 06:53:34 +00001488{
Roland McGrath08267b82004-02-20 22:56:43 +00001489 int req = PTRACE_POKEDATA;
1490 void *ap;
1491
1492 if (ia32) {
1493 ap = (void *) (intptr_t) PT_R9; /* r9 == ECX */
1494 req = PTRACE_POKEUSER;
1495 } else
1496 ap = ia64_rse_skip_regs(*state, 1);
Roland McGratheb9e2e82009-06-02 16:49:22 -07001497 errno = 0;
1498 ptrace(req, tcp->pid, ap, val);
1499 return errno ? -1 : 0;
Roland McGrathd81f1d92003-01-09 06:53:34 +00001500}
1501
Roland McGrathb659f872008-07-18 01:19:36 +00001502/* ia64 does not return the input arguments from functions (and syscalls)
1503 according to ia64 RSE (Register Stack Engine) behavior. */
1504
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001505# define restore_arg0(tcp, state, val) ((void) (state), 0)
1506# define restore_arg1(tcp, state, val) ((void) (state), 0)
Roland McGrathb659f872008-07-18 01:19:36 +00001507
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001508# elif defined (SPARC) || defined (SPARC64)
Roland McGrathd81f1d92003-01-09 06:53:34 +00001509
Mike Frysinger8566c502009-10-12 11:05:14 -04001510typedef struct pt_regs arg_setup_state;
Roland McGrathd81f1d92003-01-09 06:53:34 +00001511
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001512# define arg_setup(tcp, state) \
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001513 (ptrace(PTRACE_GETREGS, tcp->pid, (char *) (state), 0))
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001514# define arg_finish_change(tcp, state) \
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001515 (ptrace(PTRACE_SETREGS, tcp->pid, (char *) (state), 0))
Roland McGrathd81f1d92003-01-09 06:53:34 +00001516
Mike Frysinger8566c502009-10-12 11:05:14 -04001517# define get_arg0(tcp, state, valp) (*(valp) = (state)->u_regs[U_REG_O0], 0)
1518# define get_arg1(tcp, state, valp) (*(valp) = (state)->u_regs[U_REG_O1], 0)
1519# define set_arg0(tcp, state, val) ((state)->u_regs[U_REG_O0] = (val), 0)
1520# define set_arg1(tcp, state, val) ((state)->u_regs[U_REG_O1] = (val), 0)
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001521# define restore_arg0(tcp, state, val) 0
Roland McGrathd81f1d92003-01-09 06:53:34 +00001522
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001523# else /* other architectures */
Roland McGrathd81f1d92003-01-09 06:53:34 +00001524
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001525# if defined S390 || defined S390X
Roland McGrath7b308222003-01-20 09:04:36 +00001526/* Note: this is only true for the `clone' system call, which handles
1527 arguments specially. We could as well say that its first two arguments
1528 are swapped relative to other architectures, but that would just be
1529 another #ifdef in the calls. */
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001530# define arg0_offset PT_GPR3
1531# define arg1_offset PT_ORIGGPR2
1532# define restore_arg0(tcp, state, val) ((void) (state), 0)
1533# define restore_arg1(tcp, state, val) ((void) (state), 0)
1534# define arg0_index 1
1535# define arg1_index 0
1536# elif defined (ALPHA) || defined (MIPS)
1537# define arg0_offset REG_A0
1538# define arg1_offset (REG_A0+1)
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00001539# elif defined (AVR32)
1540# define arg0_offset (REG_R12)
1541# define arg1_offset (REG_R11)
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001542# elif defined (POWERPC)
1543# define arg0_offset (sizeof(unsigned long)*PT_R3)
1544# define arg1_offset (sizeof(unsigned long)*PT_R4)
1545# define restore_arg0(tcp, state, val) ((void) (state), 0)
1546# elif defined (HPPA)
1547# define arg0_offset PT_GR26
1548# define arg1_offset (PT_GR26-4)
1549# elif defined (X86_64)
1550# define arg0_offset ((long)(8*(current_personality ? RBX : RDI)))
1551# define arg1_offset ((long)(8*(current_personality ? RCX : RSI)))
1552# elif defined (SH)
1553# define arg0_offset (4*(REG_REG0+4))
1554# define arg1_offset (4*(REG_REG0+5))
1555# elif defined (SH64)
1556 /* ABI defines arg0 & 1 in r2 & r3 */
1557# define arg0_offset (REG_OFFSET+16)
1558# define arg1_offset (REG_OFFSET+24)
1559# define restore_arg0(tcp, state, val) 0
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001560# elif defined CRISV10 || defined CRISV32
1561# define arg0_offset (4*PT_R11)
1562# define arg1_offset (4*PT_ORIG_R10)
1563# define restore_arg0(tcp, state, val) 0
1564# define restore_arg1(tcp, state, val) 0
1565# define arg0_index 1
1566# define arg1_index 0
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001567# else
1568# define arg0_offset 0
1569# define arg1_offset 4
1570# if defined ARM
1571# define restore_arg0(tcp, state, val) 0
1572# endif
1573# endif
Roland McGrathd81f1d92003-01-09 06:53:34 +00001574
1575typedef int arg_setup_state;
1576
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001577# define arg_setup(tcp, state) (0)
1578# define arg_finish_change(tcp, state) 0
1579# define get_arg0(tcp, cookie, valp) \
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001580 (upeek((tcp), arg0_offset, (valp)))
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001581# define get_arg1(tcp, cookie, valp) \
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001582 (upeek((tcp), arg1_offset, (valp)))
Roland McGrathd81f1d92003-01-09 06:53:34 +00001583
1584static int
Denys Vlasenko12014262011-05-30 14:00:14 +02001585set_arg0(struct tcb *tcp, void *cookie, long val)
Roland McGrathd81f1d92003-01-09 06:53:34 +00001586{
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001587 return ptrace(PTRACE_POKEUSER, tcp->pid, (char*)arg0_offset, val);
Roland McGrathd81f1d92003-01-09 06:53:34 +00001588}
1589
1590static int
Denys Vlasenko12014262011-05-30 14:00:14 +02001591set_arg1(struct tcb *tcp, void *cookie, long val)
Roland McGrathd81f1d92003-01-09 06:53:34 +00001592{
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001593 return ptrace(PTRACE_POKEUSER, tcp->pid, (char*)arg1_offset, val);
Roland McGrathd81f1d92003-01-09 06:53:34 +00001594}
1595
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001596# endif /* architectures */
Roland McGrathd81f1d92003-01-09 06:53:34 +00001597
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001598# ifndef restore_arg0
1599# define restore_arg0(tcp, state, val) set_arg0((tcp), (state), (val))
1600# endif
1601# ifndef restore_arg1
1602# define restore_arg1(tcp, state, val) set_arg1((tcp), (state), (val))
1603# endif
Roland McGrathd81f1d92003-01-09 06:53:34 +00001604
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001605# ifndef arg0_index
1606# define arg0_index 0
1607# define arg1_index 1
1608# endif
Roland McGrath90d0afd2004-03-01 21:05:16 +00001609
Roland McGrathd81f1d92003-01-09 06:53:34 +00001610int
Denys Vlasenko418d66a2009-01-17 01:52:54 +00001611setbpt(struct tcb *tcp)
Roland McGrathd81f1d92003-01-09 06:53:34 +00001612{
Roland McGrath3291ef22008-05-20 00:34:34 +00001613 static int clone_scno[SUPPORTED_PERSONALITIES] = { SYS_clone };
Roland McGrathd81f1d92003-01-09 06:53:34 +00001614 arg_setup_state state;
1615
1616 if (tcp->flags & TCB_BPTSET) {
1617 fprintf(stderr, "PANIC: TCB already set in pid %u\n", tcp->pid);
1618 return -1;
1619 }
1620
Roland McGrath3291ef22008-05-20 00:34:34 +00001621 /*
1622 * It's a silly kludge to initialize this with a search at runtime.
1623 * But it's better than maintaining another magic thing in the
1624 * godforsaken tables.
1625 */
1626 if (clone_scno[current_personality] == 0) {
1627 int i;
1628 for (i = 0; i < nsyscalls; ++i)
1629 if (sysent[i].sys_func == sys_clone) {
1630 clone_scno[current_personality] = i;
1631 break;
1632 }
1633 }
1634
Roland McGrath76989d72005-06-07 23:21:31 +00001635 switch (known_scno(tcp)) {
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001636# ifdef SYS_vfork
Roland McGrath9383c6c2003-01-18 00:19:31 +00001637 case SYS_vfork:
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001638# endif
1639# ifdef SYS_fork
Roland McGrathd81f1d92003-01-09 06:53:34 +00001640 case SYS_fork:
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001641# endif
1642# if defined SYS_fork || defined SYS_vfork
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001643 if (arg_setup(tcp, &state) < 0
1644 || get_arg0(tcp, &state, &tcp->inst[0]) < 0
1645 || get_arg1(tcp, &state, &tcp->inst[1]) < 0
Roland McGrath3291ef22008-05-20 00:34:34 +00001646 || change_syscall(tcp, clone_scno[current_personality]) < 0
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001647 || set_arg0(tcp, &state, CLONE_PTRACE|SIGCHLD) < 0
1648 || set_arg1(tcp, &state, 0) < 0
1649 || arg_finish_change(tcp, &state) < 0)
Roland McGrathd81f1d92003-01-09 06:53:34 +00001650 return -1;
Roland McGrathc9dc3c12004-03-01 20:57:09 +00001651 tcp->u_arg[arg0_index] = CLONE_PTRACE|SIGCHLD;
1652 tcp->u_arg[arg1_index] = 0;
Roland McGrathd81f1d92003-01-09 06:53:34 +00001653 tcp->flags |= TCB_BPTSET;
1654 return 0;
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001655# endif
Roland McGrathd81f1d92003-01-09 06:53:34 +00001656
Denys Vlasenkoc133bf02011-06-23 21:57:54 +02001657 case SYS_clone: ;
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001658# ifdef SYS_clone2
Denys Vlasenkoc133bf02011-06-23 21:57:54 +02001659 case SYS_clone2: ;
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001660# endif
Jan Kratochvil8fc95752008-08-06 21:43:35 +00001661 /* ia64 calls directly `clone (CLONE_VFORK | CLONE_VM)'
1662 contrary to x86 SYS_vfork above. Even on x86 we turn the
1663 vfork semantics into plain fork - each application must not
1664 depend on the vfork specifics according to POSIX. We would
1665 hang waiting for the parent resume otherwise. We need to
1666 clear also CLONE_VM but only in the CLONE_VFORK case as
1667 otherwise we would break pthread_create. */
1668
Denys Vlasenkoc133bf02011-06-23 21:57:54 +02001669 long new_arg0 = (tcp->u_arg[arg0_index] | CLONE_PTRACE);
1670 if (new_arg0 & CLONE_VFORK)
1671 new_arg0 &= ~(unsigned long)(CLONE_VFORK | CLONE_VM);
1672 if (arg_setup(tcp, &state) < 0
1673 || set_arg0(tcp, &state, new_arg0) < 0
1674 || arg_finish_change(tcp, &state) < 0)
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00001675 return -1;
Roland McGrathd81f1d92003-01-09 06:53:34 +00001676 tcp->flags |= TCB_BPTSET;
Roland McGrathc9dc3c12004-03-01 20:57:09 +00001677 tcp->inst[0] = tcp->u_arg[arg0_index];
1678 tcp->inst[1] = tcp->u_arg[arg1_index];
Roland McGrathd81f1d92003-01-09 06:53:34 +00001679 return 0;
1680
1681 default:
1682 fprintf(stderr, "PANIC: setbpt for syscall %ld on %u???\n",
1683 tcp->scno, tcp->pid);
1684 break;
1685 }
1686
1687 return -1;
1688}
1689
1690int
Denys Vlasenko12014262011-05-30 14:00:14 +02001691clearbpt(struct tcb *tcp)
Roland McGrathd81f1d92003-01-09 06:53:34 +00001692{
1693 arg_setup_state state;
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001694 if (arg_setup(tcp, &state) < 0
1695 || restore_arg0(tcp, &state, tcp->inst[0]) < 0
1696 || restore_arg1(tcp, &state, tcp->inst[1]) < 0
1697 || arg_finish_change(tcp, &state))
Denys Vlasenkoc133bf02011-06-23 21:57:54 +02001698 if (errno != ESRCH)
1699 return -1;
Roland McGrathd81f1d92003-01-09 06:53:34 +00001700 tcp->flags &= ~TCB_BPTSET;
1701 return 0;
1702}
1703
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001704# else /* !defined LINUX */
Roland McGrathd81f1d92003-01-09 06:53:34 +00001705
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001706int
Denys Vlasenko12014262011-05-30 14:00:14 +02001707setbpt(struct tcb *tcp)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001708{
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001709# ifdef SUNOS4
1710# ifdef SPARC /* This code is slightly sparc specific */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001711
Wichert Akkermane6f876c1999-06-22 15:28:30 +00001712 struct regs regs;
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001713# define BPT 0x91d02001 /* ta 1 */
1714# define LOOP 0x10800000 /* ba 0 */
1715# define LOOPA 0x30800000 /* ba,a 0 */
1716# define NOP 0x01000000
1717# if LOOPA
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001718 static int loopdeloop[1] = {LOOPA};
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001719# else
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001720 static int loopdeloop[2] = {LOOP, NOP};
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001721# endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001722
1723 if (tcp->flags & TCB_BPTSET) {
1724 fprintf(stderr, "PANIC: TCB already set in pid %u\n", tcp->pid);
1725 return -1;
1726 }
Roland McGratheb9e2e82009-06-02 16:49:22 -07001727 if (ptrace(PTRACE_GETREGS, tcp->pid, (char *)&regs, 0) < 0) {
1728 perror("setbpt: ptrace(PTRACE_GETREGS, ...)");
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001729 return -1;
1730 }
1731 tcp->baddr = regs.r_o7 + 8;
Roland McGratheb9e2e82009-06-02 16:49:22 -07001732 if (ptrace(PTRACE_READTEXT, tcp->pid, (char *)tcp->baddr,
1733 sizeof tcp->inst, (char *)tcp->inst) < 0) {
1734 perror("setbpt: ptrace(PTRACE_READTEXT, ...)");
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001735 return -1;
1736 }
1737
1738 /*
1739 * XXX - BRUTAL MODE ON
1740 * We cannot set a real BPT in the child, since it will not be
1741 * traced at the moment it will reach the trap and would probably
1742 * die with a core dump.
1743 * Thus, we are force our way in by taking out two instructions
1744 * and insert an eternal loop in stead, in expectance of the SIGSTOP
1745 * generated by out PTRACE_ATTACH.
1746 * Of cause, if we evaporate ourselves in the middle of all this...
1747 */
Roland McGratheb9e2e82009-06-02 16:49:22 -07001748 if (ptrace(PTRACE_WRITETEXT, tcp->pid, (char *) tcp->baddr,
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001749 sizeof loopdeloop, (char *) loopdeloop) < 0) {
Roland McGratheb9e2e82009-06-02 16:49:22 -07001750 perror("setbpt: ptrace(PTRACE_WRITETEXT, ...)");
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001751 return -1;
1752 }
1753 tcp->flags |= TCB_BPTSET;
1754
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001755# endif /* SPARC */
1756# endif /* SUNOS4 */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001757
1758 return 0;
1759}
1760
1761int
Denys Vlasenko12014262011-05-30 14:00:14 +02001762clearbpt(struct tcb *tcp)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001763{
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001764# ifdef SUNOS4
1765# ifdef SPARC
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001766
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001767# if !LOOPA
Wichert Akkermane6f876c1999-06-22 15:28:30 +00001768 struct regs regs;
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001769# endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001770
1771 if (!(tcp->flags & TCB_BPTSET)) {
1772 fprintf(stderr, "PANIC: TCB not set in pid %u\n", tcp->pid);
1773 return -1;
1774 }
Roland McGratheb9e2e82009-06-02 16:49:22 -07001775 if (ptrace(PTRACE_WRITETEXT, tcp->pid, (char *) tcp->baddr,
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001776 sizeof tcp->inst, (char *) tcp->inst) < 0) {
Roland McGratheb9e2e82009-06-02 16:49:22 -07001777 perror("clearbtp: ptrace(PTRACE_WRITETEXT, ...)");
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001778 return -1;
1779 }
1780 tcp->flags &= ~TCB_BPTSET;
1781
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001782# if !LOOPA
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001783 /*
1784 * Since we don't have a single instruction breakpoint, we may have
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001785 * to adjust the program counter after removing our `breakpoint'.
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001786 */
Roland McGratheb9e2e82009-06-02 16:49:22 -07001787 if (ptrace(PTRACE_GETREGS, tcp->pid, (char *)&regs, 0) < 0) {
1788 perror("clearbpt: ptrace(PTRACE_GETREGS, ...)");
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001789 return -1;
1790 }
Roland McGratheb9e2e82009-06-02 16:49:22 -07001791 if ((regs.r_pc < tcp->baddr) ||
1792 (regs.r_pc > tcp->baddr + 4)) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001793 /* The breakpoint has not been reached yet */
1794 if (debug)
1795 fprintf(stderr,
1796 "NOTE: PC not at bpt (pc %#x baddr %#x)\n",
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001797 regs.r_pc, tcp->baddr);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001798 return 0;
1799 }
1800 if (regs.r_pc != tcp->baddr)
1801 if (debug)
1802 fprintf(stderr, "NOTE: PC adjusted (%#x -> %#x\n",
1803 regs.r_pc, tcp->baddr);
1804
1805 regs.r_pc = tcp->baddr;
Roland McGratheb9e2e82009-06-02 16:49:22 -07001806 if (ptrace(PTRACE_SETREGS, tcp->pid, (char *)&regs, 0) < 0) {
1807 perror("clearbpt: ptrace(PTRACE_SETREGS, ...)");
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001808 return -1;
1809 }
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001810# endif /* LOOPA */
1811# endif /* SPARC */
1812# endif /* SUNOS4 */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001813
1814 return 0;
1815}
1816
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001817# endif /* !defined LINUX */
Roland McGrathd81f1d92003-01-09 06:53:34 +00001818
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001819#endif /* !USE_PROCFS */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001820
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001821
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001822#ifdef SUNOS4
1823
1824static int
Denys Vlasenko12014262011-05-30 14:00:14 +02001825getex(struct tcb *tcp, struct exec *hdr)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001826{
1827 int n;
1828
1829 for (n = 0; n < sizeof *hdr; n += 4) {
1830 long res;
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001831 if (upeek(tcp, uoff(u_exdata) + n, &res) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001832 return -1;
1833 memcpy(((char *) hdr) + n, &res, 4);
1834 }
1835 if (debug) {
1836 fprintf(stderr, "[struct exec: magic: %o version %u Mach %o\n",
1837 hdr->a_magic, hdr->a_toolversion, hdr->a_machtype);
1838 fprintf(stderr, "Text %lu Data %lu Bss %lu Syms %lu Entry %#lx]\n",
1839 hdr->a_text, hdr->a_data, hdr->a_bss, hdr->a_syms, hdr->a_entry);
1840 }
1841 return 0;
1842}
1843
1844int
Denys Vlasenko12014262011-05-30 14:00:14 +02001845fixvfork(struct tcb *tcp)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001846{
1847 int pid = tcp->pid;
1848 /*
1849 * Change `vfork' in a freshly exec'ed dynamically linked
1850 * executable's (internal) symbol table to plain old `fork'
1851 */
1852
1853 struct exec hdr;
1854 struct link_dynamic dyn;
1855 struct link_dynamic_2 ld;
1856 char *strtab, *cp;
1857
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001858 if (getex(tcp, &hdr) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001859 return -1;
1860 if (!hdr.a_dynamic)
1861 return -1;
1862
1863 if (umove(tcp, (int) N_DATADDR(hdr), &dyn) < 0) {
1864 fprintf(stderr, "Cannot read DYNAMIC\n");
1865 return -1;
1866 }
1867 if (umove(tcp, (int) dyn.ld_un.ld_2, &ld) < 0) {
1868 fprintf(stderr, "Cannot read link_dynamic_2\n");
1869 return -1;
1870 }
Denys Vlasenko5d645812011-08-20 12:48:18 +02001871 strtab = malloc((unsigned)ld.ld_symb_size);
Denys Vlasenko1d46ba52011-08-31 14:00:02 +02001872 if (!strtab)
1873 die_out_of_memory();
Roland McGratheb9e2e82009-06-02 16:49:22 -07001874 if (umoven(tcp, (int)ld.ld_symbols+(int)N_TXTADDR(hdr),
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001875 (int)ld.ld_symb_size, strtab) < 0)
1876 goto err;
1877
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001878 for (cp = strtab; cp < strtab + ld.ld_symb_size; ) {
1879 if (strcmp(cp, "_vfork") == 0) {
1880 if (debug)
1881 fprintf(stderr, "fixvfork: FOUND _vfork\n");
1882 strcpy(cp, "_fork");
1883 break;
1884 }
1885 cp += strlen(cp)+1;
1886 }
1887 if (cp < strtab + ld.ld_symb_size)
1888 /*
1889 * Write entire symbol table back to avoid
1890 * memory alignment bugs in ptrace
1891 */
Roland McGratheb9e2e82009-06-02 16:49:22 -07001892 if (tload(pid, (int)ld.ld_symbols+(int)N_TXTADDR(hdr),
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001893 (int)ld.ld_symb_size, strtab) < 0)
1894 goto err;
1895
1896 free(strtab);
1897 return 0;
1898
1899err:
1900 free(strtab);
1901 return -1;
1902}
1903
1904#endif /* SUNOS4 */