blob: d9ec1b3cfb70efb7e5e63a15134092ccdac97568 [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
772#define PAGMASK (~(PAGSIZ - 1))
773/*
774 * move `len' bytes of data from process `pid'
775 * at address `addr' to our space at `laddr'
776 */
777int
Denys Vlasenkoef2fbf82009-01-06 21:45:06 +0000778umoven(struct tcb *tcp, long addr, int len, char *laddr)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000779{
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000780#ifdef LINUX
Roland McGratheb9e2e82009-06-02 16:49:22 -0700781 int pid = tcp->pid;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000782 int n, m;
Denys Vlasenkoa47e6b92012-01-21 04:01:56 +0100783 int started;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000784 union {
785 long val;
786 char x[sizeof(long)];
787 } u;
788
Dmitry V. Levin856c7ed2011-12-26 20:12:02 +0000789#if SUPPORTED_PERSONALITIES > 1
790 if (personality_wordsize[current_personality] < sizeof(addr))
791 addr &= (1ul << 8 * personality_wordsize[current_personality]) - 1;
792#endif
793
Denys Vlasenkoa47e6b92012-01-21 04:01:56 +0100794 started = 0;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000795 if (addr & (sizeof(long) - 1)) {
796 /* addr not a multiple of sizeof(long) */
797 n = addr - (addr & -sizeof(long)); /* residue */
798 addr &= -sizeof(long); /* residue */
Roland McGratheb9e2e82009-06-02 16:49:22 -0700799 errno = 0;
800 u.val = ptrace(PTRACE_PEEKDATA, pid, (char *) addr, 0);
801 if (errno) {
Roland McGratheb9e2e82009-06-02 16:49:22 -0700802 /* But if not started, we had a bogus address. */
803 if (addr != 0 && errno != EIO && errno != ESRCH)
804 perror("ptrace: umoven");
805 return -1;
806 }
Wichert Akkerman5daa0281999-03-15 19:49:42 +0000807 started = 1;
Denys Vlasenkoa47e6b92012-01-21 04:01:56 +0100808 m = MIN(sizeof(long) - n, len);
809 memcpy(laddr, &u.x[n], m);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000810 addr += sizeof(long), laddr += m, len -= m;
811 }
812 while (len) {
Roland McGratheb9e2e82009-06-02 16:49:22 -0700813 errno = 0;
814 u.val = ptrace(PTRACE_PEEKDATA, pid, (char *) addr, 0);
815 if (errno) {
816 if (started && (errno==EPERM || errno==EIO)) {
817 /* Ran into 'end of memory' - stupid "printpath" */
818 return 0;
819 }
820 if (addr != 0 && errno != EIO && errno != ESRCH)
821 perror("ptrace: umoven");
822 return -1;
823 }
Wichert Akkerman5daa0281999-03-15 19:49:42 +0000824 started = 1;
Denys Vlasenkoa47e6b92012-01-21 04:01:56 +0100825 m = MIN(sizeof(long), len);
826 memcpy(laddr, u.x, m);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000827 addr += sizeof(long), laddr += m, len -= m;
828 }
829#endif /* LINUX */
830
831#ifdef SUNOS4
832 int pid = tcp->pid;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000833 int n;
834
835 while (len) {
836 n = MIN(len, PAGSIZ);
837 n = MIN(n, ((addr + PAGSIZ) & PAGMASK) - addr);
Roland McGratheb9e2e82009-06-02 16:49:22 -0700838 if (ptrace(PTRACE_READDATA, pid,
839 (char *) addr, len, laddr) < 0) {
840 if (errno != ESRCH) {
841 perror("umoven: ptrace(PTRACE_READDATA, ...)");
842 abort();
843 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000844 return -1;
845 }
846 len -= n;
847 addr += n;
848 laddr += n;
849 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000850#endif /* SUNOS4 */
851
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000852#ifdef USE_PROCFS
Wichert Akkermanea78f0f1999-11-29 15:34:02 +0000853#ifdef HAVE_MP_PROCFS
John Hughesaa09c6b2001-05-15 14:53:43 +0000854 int fd = tcp->pfd_as;
Wichert Akkerman9ce1a631999-08-29 23:15:07 +0000855#else
John Hughesaa09c6b2001-05-15 14:53:43 +0000856 int fd = tcp->pfd;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000857#endif
John Hughesaa09c6b2001-05-15 14:53:43 +0000858 lseek(fd, addr, SEEK_SET);
859 if (read(fd, laddr, len) == -1)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000860 return -1;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000861#endif /* USE_PROCFS */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000862
863 return 0;
864}
865
866/*
Denys Vlasenko6cecba52012-01-20 11:56:00 +0100867 * Like `umove' but make the additional effort of looking
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000868 * for a terminating zero byte.
Denys Vlasenko6cecba52012-01-20 11:56:00 +0100869 *
870 * Returns < 0 on error, > 0 if NUL was seen,
871 * (TODO if useful: return count of bytes including NUL),
872 * else 0 if len bytes were read but no NUL byte seen.
873 *
874 * Note: there is no guarantee we won't overwrite some bytes
875 * in laddr[] _after_ terminating NUL (but, of course,
876 * we never write past laddr[len-1]).
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000877 */
878int
Denys Vlasenkoef2fbf82009-01-06 21:45:06 +0000879umovestr(struct tcb *tcp, long addr, int len, char *laddr)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000880{
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000881#ifdef USE_PROCFS
Denys Vlasenkoa47e6b92012-01-21 04:01:56 +0100882# ifdef HAVE_MP_PROCFS
John Hughesaa09c6b2001-05-15 14:53:43 +0000883 int fd = tcp->pfd_as;
Denys Vlasenkoa47e6b92012-01-21 04:01:56 +0100884# else
John Hughesaa09c6b2001-05-15 14:53:43 +0000885 int fd = tcp->pfd;
Denys Vlasenkoa47e6b92012-01-21 04:01:56 +0100886# endif
John Hughesaa09c6b2001-05-15 14:53:43 +0000887 /* Some systems (e.g. FreeBSD) can be upset if we read off the
888 end of valid memory, avoid this by trying to read up
889 to page boundaries. But we don't know what a page is (and
890 getpagesize(2) (if it exists) doesn't necessarily return
891 hardware page size). Assume all pages >= 1024 (a-historical
892 I know) */
893
Denys Vlasenkob63256e2011-06-07 12:13:24 +0200894 int page = 1024; /* How to find this? */
John Hughesaa09c6b2001-05-15 14:53:43 +0000895 int move = page - (addr & (page - 1));
896 int left = len;
897
898 lseek(fd, addr, SEEK_SET);
899
900 while (left) {
Denys Vlasenko5d645812011-08-20 12:48:18 +0200901 if (move > left)
902 move = left;
903 move = read(fd, laddr, move);
904 if (move <= 0)
John Hughesaa09c6b2001-05-15 14:53:43 +0000905 return left != len ? 0 : -1;
Denys Vlasenko5d645812011-08-20 12:48:18 +0200906 if (memchr(laddr, 0, move))
Denys Vlasenko6cecba52012-01-20 11:56:00 +0100907 return 1;
John Hughesaa09c6b2001-05-15 14:53:43 +0000908 left -= move;
909 laddr += move;
910 addr += move;
911 move = page;
912 }
Denys Vlasenkoa47e6b92012-01-21 04:01:56 +0100913 return 0;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000914#else /* !USE_PROCFS */
Denys Vlasenkoa47e6b92012-01-21 04:01:56 +0100915 int started;
Roland McGratheb9e2e82009-06-02 16:49:22 -0700916 int pid = tcp->pid;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000917 int i, n, m;
918 union {
919 long val;
920 char x[sizeof(long)];
921 } u;
922
Dmitry V. Levin856c7ed2011-12-26 20:12:02 +0000923#if SUPPORTED_PERSONALITIES > 1
924 if (personality_wordsize[current_personality] < sizeof(addr))
925 addr &= (1ul << 8 * personality_wordsize[current_personality]) - 1;
926#endif
927
Denys Vlasenkoa47e6b92012-01-21 04:01:56 +0100928 started = 0;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000929 if (addr & (sizeof(long) - 1)) {
930 /* addr not a multiple of sizeof(long) */
931 n = addr - (addr & -sizeof(long)); /* residue */
932 addr &= -sizeof(long); /* residue */
Roland McGratheb9e2e82009-06-02 16:49:22 -0700933 errno = 0;
934 u.val = ptrace(PTRACE_PEEKDATA, pid, (char *)addr, 0);
935 if (errno) {
Roland McGratheb9e2e82009-06-02 16:49:22 -0700936 if (addr != 0 && errno != EIO && errno != ESRCH)
937 perror("umovestr");
938 return -1;
939 }
Wichert Akkerman5daa0281999-03-15 19:49:42 +0000940 started = 1;
Denys Vlasenkoa47e6b92012-01-21 04:01:56 +0100941 m = MIN(sizeof(long) - n, len);
942 memcpy(laddr, &u.x[n], m);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000943 while (n & (sizeof(long) - 1))
944 if (u.x[n++] == '\0')
Denys Vlasenko6cecba52012-01-20 11:56:00 +0100945 return 1;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000946 addr += sizeof(long), laddr += m, len -= m;
947 }
948 while (len) {
Roland McGratheb9e2e82009-06-02 16:49:22 -0700949 errno = 0;
950 u.val = ptrace(PTRACE_PEEKDATA, pid, (char *)addr, 0);
951 if (errno) {
952 if (started && (errno==EPERM || errno==EIO)) {
953 /* Ran into 'end of memory' - stupid "printpath" */
954 return 0;
955 }
956 if (addr != 0 && errno != EIO && errno != ESRCH)
957 perror("umovestr");
958 return -1;
959 }
Wichert Akkerman5daa0281999-03-15 19:49:42 +0000960 started = 1;
Denys Vlasenkoa47e6b92012-01-21 04:01:56 +0100961 m = MIN(sizeof(long), len);
962 memcpy(laddr, u.x, m);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000963 for (i = 0; i < sizeof(long); i++)
964 if (u.x[i] == '\0')
Denys Vlasenko6cecba52012-01-20 11:56:00 +0100965 return 1;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000966 addr += sizeof(long), laddr += m, len -= m;
967 }
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000968#endif /* !USE_PROCFS */
John Hughesaa09c6b2001-05-15 14:53:43 +0000969 return 0;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000970}
971
972#ifdef LINUX
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +0000973# if !defined (SPARC) && !defined(SPARC64)
974# define PTRACE_WRITETEXT 101
975# define PTRACE_WRITEDATA 102
976# endif /* !SPARC && !SPARC64 */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000977#endif /* LINUX */
978
979#ifdef SUNOS4
980
981static int
Denys Vlasenko12014262011-05-30 14:00:14 +0200982uload(int cmd, int pid, long addr, int len, char *laddr)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000983{
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000984 int peek, poke;
985 int n, m;
986 union {
987 long val;
988 char x[sizeof(long)];
989 } u;
990
991 if (cmd == PTRACE_WRITETEXT) {
992 peek = PTRACE_PEEKTEXT;
993 poke = PTRACE_POKETEXT;
994 }
995 else {
996 peek = PTRACE_PEEKDATA;
997 poke = PTRACE_POKEDATA;
998 }
999 if (addr & (sizeof(long) - 1)) {
1000 /* addr not a multiple of sizeof(long) */
1001 n = addr - (addr & -sizeof(long)); /* residue */
1002 addr &= -sizeof(long);
Roland McGratheb9e2e82009-06-02 16:49:22 -07001003 errno = 0;
1004 u.val = ptrace(peek, pid, (char *) addr, 0);
1005 if (errno) {
1006 perror("uload: POKE");
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001007 return -1;
1008 }
Denys Vlasenkoa47e6b92012-01-21 04:01:56 +01001009 m = MIN(sizeof(long) - n, len);
1010 memcpy(&u.x[n], laddr, m);
Roland McGratheb9e2e82009-06-02 16:49:22 -07001011 if (ptrace(poke, pid, (char *)addr, u.val) < 0) {
1012 perror("uload: POKE");
1013 return -1;
1014 }
1015 addr += sizeof(long), laddr += m, len -= m;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001016 }
1017 while (len) {
1018 if (len < sizeof(long))
Roland McGratheb9e2e82009-06-02 16:49:22 -07001019 u.val = ptrace(peek, pid, (char *) addr, 0);
Denys Vlasenkoa47e6b92012-01-21 04:01:56 +01001020 m = MIN(sizeof(long), len);
1021 memcpy(u.x, laddr, m);
Roland McGratheb9e2e82009-06-02 16:49:22 -07001022 if (ptrace(poke, pid, (char *) addr, u.val) < 0) {
1023 perror("uload: POKE");
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001024 return -1;
1025 }
Roland McGratheb9e2e82009-06-02 16:49:22 -07001026 addr += sizeof(long), laddr += m, len -= m;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001027 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001028 return 0;
1029}
1030
Roland McGratheb9e2e82009-06-02 16:49:22 -07001031int
Denys Vlasenko12014262011-05-30 14:00:14 +02001032tload(int pid, int addr, int len, char *laddr)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001033{
Roland McGratheb9e2e82009-06-02 16:49:22 -07001034 return uload(PTRACE_WRITETEXT, pid, addr, len, laddr);
1035}
1036
1037int
Denys Vlasenko12014262011-05-30 14:00:14 +02001038dload(int pid, int addr, int len, char *laddr)
Roland McGratheb9e2e82009-06-02 16:49:22 -07001039{
1040 return uload(PTRACE_WRITEDATA, pid, addr, len, laddr);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001041}
1042
1043#endif /* SUNOS4 */
1044
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001045#ifndef USE_PROCFS
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001046
1047int
Denys Vlasenko12014262011-05-30 14:00:14 +02001048upeek(struct tcb *tcp, long off, long *res)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001049{
1050 long val;
1051
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001052# ifdef SUNOS4_KERNEL_ARCH_KLUDGE
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001053 {
1054 static int is_sun4m = -1;
1055 struct utsname name;
1056
1057 /* Round up the usual suspects. */
1058 if (is_sun4m == -1) {
1059 if (uname(&name) < 0) {
1060 perror("upeek: uname?");
1061 exit(1);
1062 }
1063 is_sun4m = strcmp(name.machine, "sun4m") == 0;
1064 if (is_sun4m) {
Roland McGrathd9f816f2004-09-04 03:39:20 +00001065 const struct xlat *x;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001066
1067 for (x = struct_user_offsets; x->str; x++)
1068 x->val += 1024;
1069 }
1070 }
1071 if (is_sun4m)
1072 off += 1024;
1073 }
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001074# endif /* SUNOS4_KERNEL_ARCH_KLUDGE */
Roland McGratheb9e2e82009-06-02 16:49:22 -07001075 errno = 0;
Denys Vlasenko732d1bf2008-12-17 19:21:59 +00001076 val = do_ptrace(PTRACE_PEEKUSER, tcp, (char *) off, 0);
Roland McGratheb9e2e82009-06-02 16:49:22 -07001077 if (val == -1 && errno) {
1078 if (errno != ESRCH) {
1079 char buf[60];
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001080 sprintf(buf, "upeek: ptrace(PTRACE_PEEKUSER,%d,%lu,0)", tcp->pid, off);
Roland McGratheb9e2e82009-06-02 16:49:22 -07001081 perror(buf);
1082 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001083 return -1;
Roland McGratheb9e2e82009-06-02 16:49:22 -07001084 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001085 *res = val;
1086 return 0;
1087}
1088
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001089#endif /* !USE_PROCFS */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001090
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001091void
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001092printcall(struct tcb *tcp)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001093{
Roland McGrath7a918832005-02-02 20:55:23 +00001094#define PRINTBADPC tprintf(sizeof(long) == 4 ? "[????????] " : \
1095 sizeof(long) == 8 ? "[????????????????] " : \
1096 NULL /* crash */)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001097
1098#ifdef LINUX
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001099# ifdef I386
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001100 long eip;
1101
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001102 if (upeek(tcp, 4*EIP, &eip) < 0) {
Roland McGrath7a918832005-02-02 20:55:23 +00001103 PRINTBADPC;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001104 return;
1105 }
1106 tprintf("[%08lx] ", eip);
Roland McGratheac26fc2005-02-02 02:48:53 +00001107
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001108# elif defined(S390) || defined(S390X)
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001109 long psw;
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001110 if (upeek(tcp, PT_PSWADDR, &psw) < 0) {
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001111 PRINTBADPC;
1112 return;
1113 }
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001114# ifdef S390
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001115 tprintf("[%08lx] ", psw);
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001116# elif S390X
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001117 tprintf("[%16lx] ", psw);
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001118# endif
Roland McGratheac26fc2005-02-02 02:48:53 +00001119
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001120# elif defined(X86_64)
Michal Ludvig0e035502002-09-23 15:41:01 +00001121 long rip;
1122
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001123 if (upeek(tcp, 8*RIP, &rip) < 0) {
Roland McGrath7a918832005-02-02 20:55:23 +00001124 PRINTBADPC;
Michal Ludvig0e035502002-09-23 15:41:01 +00001125 return;
1126 }
1127 tprintf("[%16lx] ", rip);
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001128# elif defined(IA64)
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00001129 long ip;
1130
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001131 if (upeek(tcp, PT_B0, &ip) < 0) {
Roland McGrath7a918832005-02-02 20:55:23 +00001132 PRINTBADPC;
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00001133 return;
1134 }
1135 tprintf("[%08lx] ", ip);
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001136# elif defined(POWERPC)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001137 long pc;
1138
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001139 if (upeek(tcp, sizeof(unsigned long)*PT_NIP, &pc) < 0) {
Andreas Schwabd69fa492010-07-12 21:39:57 +02001140 PRINTBADPC;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001141 return;
1142 }
Andreas Schwabd69fa492010-07-12 21:39:57 +02001143# ifdef POWERPC64
1144 tprintf("[%016lx] ", pc);
1145# else
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001146 tprintf("[%08lx] ", pc);
Andreas Schwabd69fa492010-07-12 21:39:57 +02001147# endif
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001148# elif defined(M68K)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001149 long pc;
1150
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001151 if (upeek(tcp, 4*PT_PC, &pc) < 0) {
Denys Vlasenko60fe8c12011-09-01 10:00:28 +02001152 tprints("[????????] ");
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001153 return;
1154 }
1155 tprintf("[%08lx] ", pc);
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001156# elif defined(ALPHA)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001157 long pc;
1158
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001159 if (upeek(tcp, REG_PC, &pc) < 0) {
Denys Vlasenko60fe8c12011-09-01 10:00:28 +02001160 tprints("[????????????????] ");
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001161 return;
1162 }
1163 tprintf("[%08lx] ", pc);
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001164# elif defined(SPARC) || defined(SPARC64)
Mike Frysinger8566c502009-10-12 11:05:14 -04001165 struct pt_regs regs;
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001166 if (ptrace(PTRACE_GETREGS, tcp->pid, (char *)&regs, 0) < 0) {
Roland McGrath7a918832005-02-02 20:55:23 +00001167 PRINTBADPC;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001168 return;
1169 }
Mike Frysinger8566c502009-10-12 11:05:14 -04001170# if defined(SPARC64)
1171 tprintf("[%08lx] ", regs.tpc);
1172# else
1173 tprintf("[%08lx] ", regs.pc);
1174# endif
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001175# elif defined(HPPA)
Wichert Akkermanc1652e22001-03-27 12:17:16 +00001176 long pc;
1177
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001178 if (upeek(tcp, PT_IAOQ0, &pc) < 0) {
Denys Vlasenko60fe8c12011-09-01 10:00:28 +02001179 tprints("[????????] ");
Wichert Akkermanc1652e22001-03-27 12:17:16 +00001180 return;
1181 }
1182 tprintf("[%08lx] ", pc);
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001183# elif defined(MIPS)
Wichert Akkerman75c422b2001-04-10 10:22:50 +00001184 long pc;
1185
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001186 if (upeek(tcp, REG_EPC, &pc) < 0) {
Denys Vlasenko60fe8c12011-09-01 10:00:28 +02001187 tprints("[????????] ");
Wichert Akkerman75c422b2001-04-10 10:22:50 +00001188 return;
1189 }
1190 tprintf("[%08lx] ", pc);
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001191# elif defined(SH)
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001192 long pc;
Wichert Akkermanccef6372002-05-01 16:39:22 +00001193
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001194 if (upeek(tcp, 4*REG_PC, &pc) < 0) {
Denys Vlasenko60fe8c12011-09-01 10:00:28 +02001195 tprints("[????????] ");
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001196 return;
1197 }
1198 tprintf("[%08lx] ", pc);
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001199# elif defined(SH64)
Roland McGrathe1e584b2003-06-02 19:18:58 +00001200 long pc;
1201
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001202 if (upeek(tcp, REG_PC, &pc) < 0) {
Denys Vlasenko60fe8c12011-09-01 10:00:28 +02001203 tprints("[????????????????] ");
Roland McGrathe1e584b2003-06-02 19:18:58 +00001204 return;
1205 }
1206 tprintf("[%08lx] ", pc);
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001207# elif defined(ARM)
Roland McGrathef388682003-06-03 23:28:59 +00001208 long pc;
Roland McGrathe1e584b2003-06-02 19:18:58 +00001209
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001210 if (upeek(tcp, 4*15, &pc) < 0) {
Roland McGrath7a918832005-02-02 20:55:23 +00001211 PRINTBADPC;
Roland McGrathef388682003-06-03 23:28:59 +00001212 return;
1213 }
1214 tprintf("[%08lx] ", pc);
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00001215# elif defined(AVR32)
1216 long pc;
1217
1218 if (upeek(tcp, REG_PC, &pc) < 0) {
Denys Vlasenko60fe8c12011-09-01 10:00:28 +02001219 tprints("[????????] ");
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00001220 return;
1221 }
1222 tprintf("[%08lx] ", pc);
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001223# elif defined(BFIN)
Dmitry V. Levin87ea1f42008-11-10 22:21:41 +00001224 long pc;
1225
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001226 if (upeek(tcp, PT_PC, &pc) < 0) {
Dmitry V. Levin87ea1f42008-11-10 22:21:41 +00001227 PRINTBADPC;
1228 return;
1229 }
1230 tprintf("[%08lx] ", pc);
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001231#elif defined(CRISV10)
1232 long pc;
1233
Edgar E. Iglesiaseeb9ce32009-10-05 14:41:02 +00001234 if (upeek(tcp, 4*PT_IRP, &pc) < 0) {
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001235 PRINTBADPC;
1236 return;
1237 }
1238 tprintf("[%08lx] ", pc);
1239#elif defined(CRISV32)
1240 long pc;
1241
Edgar E. Iglesiaseeb9ce32009-10-05 14:41:02 +00001242 if (upeek(tcp, 4*PT_ERP, &pc) < 0) {
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001243 PRINTBADPC;
1244 return;
1245 }
1246 tprintf("[%08lx] ", pc);
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001247# endif /* architecture */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001248#endif /* LINUX */
1249
1250#ifdef SUNOS4
1251 struct regs regs;
1252
Roland McGratheb9e2e82009-06-02 16:49:22 -07001253 if (ptrace(PTRACE_GETREGS, tcp->pid, (char *) &regs, 0) < 0) {
1254 perror("printcall: ptrace(PTRACE_GETREGS, ...)");
Roland McGrath7a918832005-02-02 20:55:23 +00001255 PRINTBADPC;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001256 return;
1257 }
1258 tprintf("[%08x] ", regs.r_o7);
1259#endif /* SUNOS4 */
1260
1261#ifdef SVR4
1262 /* XXX */
Roland McGrath7a918832005-02-02 20:55:23 +00001263 PRINTBADPC;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001264#endif
1265
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001266#ifdef FREEBSD
1267 struct reg regs;
1268 pread(tcp->pfd_reg, &regs, sizeof(regs), 0);
1269 tprintf("[%08x] ", regs.r_eip);
1270#endif /* FREEBSD */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001271}
1272
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001273
1274/*
1275 * These #if's are huge, please indent them correctly.
1276 * It's easy to get confused otherwise.
1277 */
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001278#ifndef USE_PROCFS
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001279
Denys Vlasenkoe7c90242011-06-22 00:09:25 +02001280# ifdef LINUX
Roland McGrathd81f1d92003-01-09 06:53:34 +00001281
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001282# include "syscall.h"
Roland McGrath3291ef22008-05-20 00:34:34 +00001283
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001284# include <sys/syscall.h>
1285# ifndef CLONE_PTRACE
1286# define CLONE_PTRACE 0x00002000
1287# endif
1288# ifndef CLONE_VFORK
1289# define CLONE_VFORK 0x00004000
1290# endif
1291# ifndef CLONE_VM
1292# define CLONE_VM 0x00000100
1293# endif
1294# ifndef CLONE_STOPPED
1295# define CLONE_STOPPED 0x02000000
1296# endif
Roland McGrathd81f1d92003-01-09 06:53:34 +00001297
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001298# ifdef IA64
Roland McGrathd81f1d92003-01-09 06:53:34 +00001299
Roland McGrath08267b82004-02-20 22:56:43 +00001300/* We don't have fork()/vfork() syscalls on ia64 itself, but the ia32
1301 subsystem has them for x86... */
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001302# define SYS_fork 2
1303# define SYS_vfork 190
Roland McGrath08267b82004-02-20 22:56:43 +00001304
Roland McGrathd81f1d92003-01-09 06:53:34 +00001305typedef unsigned long *arg_setup_state;
1306
1307static int
1308arg_setup(struct tcb *tcp, arg_setup_state *state)
1309{
Jan Kratochvil1f942712008-08-06 21:38:52 +00001310 unsigned long cfm, sof, sol;
1311 long bsp;
Roland McGrathd81f1d92003-01-09 06:53:34 +00001312
Jan Kratochvil1f942712008-08-06 21:38:52 +00001313 if (ia32) {
1314 /* Satisfy a false GCC warning. */
1315 *state = NULL;
Roland McGrath08267b82004-02-20 22:56:43 +00001316 return 0;
Jan Kratochvil1f942712008-08-06 21:38:52 +00001317 }
Roland McGrath08267b82004-02-20 22:56:43 +00001318
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001319 if (upeek(tcp, PT_AR_BSP, &bsp) < 0)
Roland McGrathd81f1d92003-01-09 06:53:34 +00001320 return -1;
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001321 if (upeek(tcp, PT_CFM, (long *) &cfm) < 0)
Roland McGrathd81f1d92003-01-09 06:53:34 +00001322 return -1;
1323
1324 sof = (cfm >> 0) & 0x7f;
1325 sol = (cfm >> 7) & 0x7f;
Jan Kratochvil1f942712008-08-06 21:38:52 +00001326 bsp = (long) ia64_rse_skip_regs((unsigned long *) bsp, -sof + sol);
Roland McGrathd81f1d92003-01-09 06:53:34 +00001327
Jan Kratochvil1f942712008-08-06 21:38:52 +00001328 *state = (unsigned long *) bsp;
Roland McGrathd81f1d92003-01-09 06:53:34 +00001329 return 0;
1330}
1331
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001332# define arg_finish_change(tcp, state) 0
Roland McGrathd81f1d92003-01-09 06:53:34 +00001333
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001334# ifdef SYS_fork
Roland McGrathd81f1d92003-01-09 06:53:34 +00001335static int
Denys Vlasenko12014262011-05-30 14:00:14 +02001336get_arg0(struct tcb *tcp, arg_setup_state *state, long *valp)
Roland McGrathd81f1d92003-01-09 06:53:34 +00001337{
Roland McGrath08267b82004-02-20 22:56:43 +00001338 int ret;
1339
1340 if (ia32)
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001341 ret = upeek(tcp, PT_R11, valp);
Roland McGrath08267b82004-02-20 22:56:43 +00001342 else
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001343 ret = umoven(tcp,
Roland McGrath08267b82004-02-20 22:56:43 +00001344 (unsigned long) ia64_rse_skip_regs(*state, 0),
1345 sizeof(long), (void *) valp);
1346 return ret;
Roland McGrathd81f1d92003-01-09 06:53:34 +00001347}
1348
1349static int
Denys Vlasenko12014262011-05-30 14:00:14 +02001350get_arg1(struct tcb *tcp, arg_setup_state *state, long *valp)
Roland McGrathd81f1d92003-01-09 06:53:34 +00001351{
Roland McGrath08267b82004-02-20 22:56:43 +00001352 int ret;
1353
1354 if (ia32)
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001355 ret = upeek(tcp, PT_R9, valp);
Roland McGrath08267b82004-02-20 22:56:43 +00001356 else
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001357 ret = umoven(tcp,
Roland McGrath08267b82004-02-20 22:56:43 +00001358 (unsigned long) ia64_rse_skip_regs(*state, 1),
1359 sizeof(long), (void *) valp);
1360 return ret;
Roland McGrathd81f1d92003-01-09 06:53:34 +00001361}
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001362# endif
Roland McGrathd81f1d92003-01-09 06:53:34 +00001363
1364static int
Denys Vlasenko12014262011-05-30 14:00:14 +02001365set_arg0(struct tcb *tcp, arg_setup_state *state, long val)
Roland McGrathd81f1d92003-01-09 06:53:34 +00001366{
Roland McGrath08267b82004-02-20 22:56:43 +00001367 int req = PTRACE_POKEDATA;
1368 void *ap;
1369
1370 if (ia32) {
1371 ap = (void *) (intptr_t) PT_R11; /* r11 == EBX */
1372 req = PTRACE_POKEUSER;
1373 } else
1374 ap = ia64_rse_skip_regs(*state, 0);
Roland McGratheb9e2e82009-06-02 16:49:22 -07001375 errno = 0;
1376 ptrace(req, tcp->pid, ap, val);
1377 return errno ? -1 : 0;
Roland McGrathd81f1d92003-01-09 06:53:34 +00001378}
1379
1380static int
Denys Vlasenko12014262011-05-30 14:00:14 +02001381set_arg1(struct tcb *tcp, arg_setup_state *state, long val)
Roland McGrathd81f1d92003-01-09 06:53:34 +00001382{
Roland McGrath08267b82004-02-20 22:56:43 +00001383 int req = PTRACE_POKEDATA;
1384 void *ap;
1385
1386 if (ia32) {
1387 ap = (void *) (intptr_t) PT_R9; /* r9 == ECX */
1388 req = PTRACE_POKEUSER;
1389 } else
1390 ap = ia64_rse_skip_regs(*state, 1);
Roland McGratheb9e2e82009-06-02 16:49:22 -07001391 errno = 0;
1392 ptrace(req, tcp->pid, ap, val);
1393 return errno ? -1 : 0;
Roland McGrathd81f1d92003-01-09 06:53:34 +00001394}
1395
Roland McGrathb659f872008-07-18 01:19:36 +00001396/* ia64 does not return the input arguments from functions (and syscalls)
1397 according to ia64 RSE (Register Stack Engine) behavior. */
1398
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001399# define restore_arg0(tcp, state, val) ((void) (state), 0)
1400# define restore_arg1(tcp, state, val) ((void) (state), 0)
Roland McGrathb659f872008-07-18 01:19:36 +00001401
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001402# elif defined (SPARC) || defined (SPARC64)
Roland McGrathd81f1d92003-01-09 06:53:34 +00001403
Mike Frysinger8566c502009-10-12 11:05:14 -04001404typedef struct pt_regs arg_setup_state;
Roland McGrathd81f1d92003-01-09 06:53:34 +00001405
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001406# define arg_setup(tcp, state) \
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001407 (ptrace(PTRACE_GETREGS, tcp->pid, (char *) (state), 0))
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001408# define arg_finish_change(tcp, state) \
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001409 (ptrace(PTRACE_SETREGS, tcp->pid, (char *) (state), 0))
Roland McGrathd81f1d92003-01-09 06:53:34 +00001410
Mike Frysinger8566c502009-10-12 11:05:14 -04001411# define get_arg0(tcp, state, valp) (*(valp) = (state)->u_regs[U_REG_O0], 0)
1412# define get_arg1(tcp, state, valp) (*(valp) = (state)->u_regs[U_REG_O1], 0)
1413# define set_arg0(tcp, state, val) ((state)->u_regs[U_REG_O0] = (val), 0)
1414# define set_arg1(tcp, state, val) ((state)->u_regs[U_REG_O1] = (val), 0)
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001415# define restore_arg0(tcp, state, val) 0
Roland McGrathd81f1d92003-01-09 06:53:34 +00001416
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001417# else /* other architectures */
Roland McGrathd81f1d92003-01-09 06:53:34 +00001418
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001419# if defined S390 || defined S390X
Roland McGrath7b308222003-01-20 09:04:36 +00001420/* Note: this is only true for the `clone' system call, which handles
1421 arguments specially. We could as well say that its first two arguments
1422 are swapped relative to other architectures, but that would just be
1423 another #ifdef in the calls. */
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001424# define arg0_offset PT_GPR3
1425# define arg1_offset PT_ORIGGPR2
1426# define restore_arg0(tcp, state, val) ((void) (state), 0)
1427# define restore_arg1(tcp, state, val) ((void) (state), 0)
1428# define arg0_index 1
1429# define arg1_index 0
1430# elif defined (ALPHA) || defined (MIPS)
1431# define arg0_offset REG_A0
1432# define arg1_offset (REG_A0+1)
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00001433# elif defined (AVR32)
1434# define arg0_offset (REG_R12)
1435# define arg1_offset (REG_R11)
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001436# elif defined (POWERPC)
1437# define arg0_offset (sizeof(unsigned long)*PT_R3)
1438# define arg1_offset (sizeof(unsigned long)*PT_R4)
1439# define restore_arg0(tcp, state, val) ((void) (state), 0)
1440# elif defined (HPPA)
1441# define arg0_offset PT_GR26
1442# define arg1_offset (PT_GR26-4)
1443# elif defined (X86_64)
1444# define arg0_offset ((long)(8*(current_personality ? RBX : RDI)))
1445# define arg1_offset ((long)(8*(current_personality ? RCX : RSI)))
1446# elif defined (SH)
1447# define arg0_offset (4*(REG_REG0+4))
1448# define arg1_offset (4*(REG_REG0+5))
1449# elif defined (SH64)
1450 /* ABI defines arg0 & 1 in r2 & r3 */
1451# define arg0_offset (REG_OFFSET+16)
1452# define arg1_offset (REG_OFFSET+24)
1453# define restore_arg0(tcp, state, val) 0
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001454# elif defined CRISV10 || defined CRISV32
1455# define arg0_offset (4*PT_R11)
1456# define arg1_offset (4*PT_ORIG_R10)
1457# define restore_arg0(tcp, state, val) 0
1458# define restore_arg1(tcp, state, val) 0
1459# define arg0_index 1
1460# define arg1_index 0
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001461# else
1462# define arg0_offset 0
1463# define arg1_offset 4
1464# if defined ARM
1465# define restore_arg0(tcp, state, val) 0
1466# endif
1467# endif
Roland McGrathd81f1d92003-01-09 06:53:34 +00001468
1469typedef int arg_setup_state;
1470
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001471# define arg_setup(tcp, state) (0)
1472# define arg_finish_change(tcp, state) 0
1473# define get_arg0(tcp, cookie, valp) \
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001474 (upeek((tcp), arg0_offset, (valp)))
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001475# define get_arg1(tcp, cookie, valp) \
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001476 (upeek((tcp), arg1_offset, (valp)))
Roland McGrathd81f1d92003-01-09 06:53:34 +00001477
1478static int
Denys Vlasenko12014262011-05-30 14:00:14 +02001479set_arg0(struct tcb *tcp, void *cookie, long val)
Roland McGrathd81f1d92003-01-09 06:53:34 +00001480{
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001481 return ptrace(PTRACE_POKEUSER, tcp->pid, (char*)arg0_offset, val);
Roland McGrathd81f1d92003-01-09 06:53:34 +00001482}
1483
1484static int
Denys Vlasenko12014262011-05-30 14:00:14 +02001485set_arg1(struct tcb *tcp, void *cookie, long val)
Roland McGrathd81f1d92003-01-09 06:53:34 +00001486{
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001487 return ptrace(PTRACE_POKEUSER, tcp->pid, (char*)arg1_offset, val);
Roland McGrathd81f1d92003-01-09 06:53:34 +00001488}
1489
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001490# endif /* architectures */
Roland McGrathd81f1d92003-01-09 06:53:34 +00001491
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001492# ifndef restore_arg0
1493# define restore_arg0(tcp, state, val) set_arg0((tcp), (state), (val))
1494# endif
1495# ifndef restore_arg1
1496# define restore_arg1(tcp, state, val) set_arg1((tcp), (state), (val))
1497# endif
Roland McGrathd81f1d92003-01-09 06:53:34 +00001498
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001499# ifndef arg0_index
1500# define arg0_index 0
1501# define arg1_index 1
1502# endif
Roland McGrath90d0afd2004-03-01 21:05:16 +00001503
Roland McGrathd81f1d92003-01-09 06:53:34 +00001504int
Denys Vlasenko418d66a2009-01-17 01:52:54 +00001505setbpt(struct tcb *tcp)
Roland McGrathd81f1d92003-01-09 06:53:34 +00001506{
Roland McGrath3291ef22008-05-20 00:34:34 +00001507 static int clone_scno[SUPPORTED_PERSONALITIES] = { SYS_clone };
Roland McGrathd81f1d92003-01-09 06:53:34 +00001508 arg_setup_state state;
1509
1510 if (tcp->flags & TCB_BPTSET) {
1511 fprintf(stderr, "PANIC: TCB already set in pid %u\n", tcp->pid);
1512 return -1;
1513 }
1514
Roland McGrath3291ef22008-05-20 00:34:34 +00001515 /*
1516 * It's a silly kludge to initialize this with a search at runtime.
1517 * But it's better than maintaining another magic thing in the
1518 * godforsaken tables.
1519 */
1520 if (clone_scno[current_personality] == 0) {
1521 int i;
1522 for (i = 0; i < nsyscalls; ++i)
1523 if (sysent[i].sys_func == sys_clone) {
1524 clone_scno[current_personality] = i;
1525 break;
1526 }
1527 }
1528
Roland McGrath76989d72005-06-07 23:21:31 +00001529 switch (known_scno(tcp)) {
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001530# ifdef SYS_vfork
Roland McGrath9383c6c2003-01-18 00:19:31 +00001531 case SYS_vfork:
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001532# endif
1533# ifdef SYS_fork
Roland McGrathd81f1d92003-01-09 06:53:34 +00001534 case SYS_fork:
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001535# endif
1536# if defined SYS_fork || defined SYS_vfork
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001537 if (arg_setup(tcp, &state) < 0
1538 || get_arg0(tcp, &state, &tcp->inst[0]) < 0
1539 || get_arg1(tcp, &state, &tcp->inst[1]) < 0
Roland McGrath3291ef22008-05-20 00:34:34 +00001540 || change_syscall(tcp, clone_scno[current_personality]) < 0
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001541 || set_arg0(tcp, &state, CLONE_PTRACE|SIGCHLD) < 0
1542 || set_arg1(tcp, &state, 0) < 0
1543 || arg_finish_change(tcp, &state) < 0)
Roland McGrathd81f1d92003-01-09 06:53:34 +00001544 return -1;
Roland McGrathc9dc3c12004-03-01 20:57:09 +00001545 tcp->u_arg[arg0_index] = CLONE_PTRACE|SIGCHLD;
1546 tcp->u_arg[arg1_index] = 0;
Roland McGrathd81f1d92003-01-09 06:53:34 +00001547 tcp->flags |= TCB_BPTSET;
1548 return 0;
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001549# endif
Roland McGrathd81f1d92003-01-09 06:53:34 +00001550
Denys Vlasenkoc133bf02011-06-23 21:57:54 +02001551 case SYS_clone: ;
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001552# ifdef SYS_clone2
Denys Vlasenkoc133bf02011-06-23 21:57:54 +02001553 case SYS_clone2: ;
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001554# endif
Jan Kratochvil8fc95752008-08-06 21:43:35 +00001555 /* ia64 calls directly `clone (CLONE_VFORK | CLONE_VM)'
1556 contrary to x86 SYS_vfork above. Even on x86 we turn the
1557 vfork semantics into plain fork - each application must not
1558 depend on the vfork specifics according to POSIX. We would
1559 hang waiting for the parent resume otherwise. We need to
1560 clear also CLONE_VM but only in the CLONE_VFORK case as
1561 otherwise we would break pthread_create. */
1562
Denys Vlasenkoc133bf02011-06-23 21:57:54 +02001563 long new_arg0 = (tcp->u_arg[arg0_index] | CLONE_PTRACE);
1564 if (new_arg0 & CLONE_VFORK)
1565 new_arg0 &= ~(unsigned long)(CLONE_VFORK | CLONE_VM);
1566 if (arg_setup(tcp, &state) < 0
1567 || set_arg0(tcp, &state, new_arg0) < 0
1568 || arg_finish_change(tcp, &state) < 0)
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00001569 return -1;
Roland McGrathd81f1d92003-01-09 06:53:34 +00001570 tcp->flags |= TCB_BPTSET;
Roland McGrathc9dc3c12004-03-01 20:57:09 +00001571 tcp->inst[0] = tcp->u_arg[arg0_index];
1572 tcp->inst[1] = tcp->u_arg[arg1_index];
Roland McGrathd81f1d92003-01-09 06:53:34 +00001573 return 0;
1574
1575 default:
1576 fprintf(stderr, "PANIC: setbpt for syscall %ld on %u???\n",
1577 tcp->scno, tcp->pid);
1578 break;
1579 }
1580
1581 return -1;
1582}
1583
1584int
Denys Vlasenko12014262011-05-30 14:00:14 +02001585clearbpt(struct tcb *tcp)
Roland McGrathd81f1d92003-01-09 06:53:34 +00001586{
1587 arg_setup_state state;
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001588 if (arg_setup(tcp, &state) < 0
1589 || restore_arg0(tcp, &state, tcp->inst[0]) < 0
1590 || restore_arg1(tcp, &state, tcp->inst[1]) < 0
1591 || arg_finish_change(tcp, &state))
Denys Vlasenkoc133bf02011-06-23 21:57:54 +02001592 if (errno != ESRCH)
1593 return -1;
Roland McGrathd81f1d92003-01-09 06:53:34 +00001594 tcp->flags &= ~TCB_BPTSET;
1595 return 0;
1596}
1597
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001598# else /* !defined LINUX */
Roland McGrathd81f1d92003-01-09 06:53:34 +00001599
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001600int
Denys Vlasenko12014262011-05-30 14:00:14 +02001601setbpt(struct tcb *tcp)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001602{
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001603# ifdef SUNOS4
1604# ifdef SPARC /* This code is slightly sparc specific */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001605
Wichert Akkermane6f876c1999-06-22 15:28:30 +00001606 struct regs regs;
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001607# define BPT 0x91d02001 /* ta 1 */
1608# define LOOP 0x10800000 /* ba 0 */
1609# define LOOPA 0x30800000 /* ba,a 0 */
1610# define NOP 0x01000000
1611# if LOOPA
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001612 static int loopdeloop[1] = {LOOPA};
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001613# else
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001614 static int loopdeloop[2] = {LOOP, NOP};
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001615# endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001616
1617 if (tcp->flags & TCB_BPTSET) {
1618 fprintf(stderr, "PANIC: TCB already set in pid %u\n", tcp->pid);
1619 return -1;
1620 }
Roland McGratheb9e2e82009-06-02 16:49:22 -07001621 if (ptrace(PTRACE_GETREGS, tcp->pid, (char *)&regs, 0) < 0) {
1622 perror("setbpt: ptrace(PTRACE_GETREGS, ...)");
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001623 return -1;
1624 }
1625 tcp->baddr = regs.r_o7 + 8;
Roland McGratheb9e2e82009-06-02 16:49:22 -07001626 if (ptrace(PTRACE_READTEXT, tcp->pid, (char *)tcp->baddr,
1627 sizeof tcp->inst, (char *)tcp->inst) < 0) {
1628 perror("setbpt: ptrace(PTRACE_READTEXT, ...)");
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001629 return -1;
1630 }
1631
1632 /*
1633 * XXX - BRUTAL MODE ON
1634 * We cannot set a real BPT in the child, since it will not be
1635 * traced at the moment it will reach the trap and would probably
1636 * die with a core dump.
1637 * Thus, we are force our way in by taking out two instructions
1638 * and insert an eternal loop in stead, in expectance of the SIGSTOP
1639 * generated by out PTRACE_ATTACH.
1640 * Of cause, if we evaporate ourselves in the middle of all this...
1641 */
Roland McGratheb9e2e82009-06-02 16:49:22 -07001642 if (ptrace(PTRACE_WRITETEXT, tcp->pid, (char *) tcp->baddr,
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001643 sizeof loopdeloop, (char *) loopdeloop) < 0) {
Roland McGratheb9e2e82009-06-02 16:49:22 -07001644 perror("setbpt: ptrace(PTRACE_WRITETEXT, ...)");
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001645 return -1;
1646 }
1647 tcp->flags |= TCB_BPTSET;
1648
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001649# endif /* SPARC */
1650# endif /* SUNOS4 */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001651
1652 return 0;
1653}
1654
1655int
Denys Vlasenko12014262011-05-30 14:00:14 +02001656clearbpt(struct tcb *tcp)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001657{
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001658# ifdef SUNOS4
1659# ifdef SPARC
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001660
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001661# if !LOOPA
Wichert Akkermane6f876c1999-06-22 15:28:30 +00001662 struct regs regs;
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001663# endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001664
1665 if (!(tcp->flags & TCB_BPTSET)) {
1666 fprintf(stderr, "PANIC: TCB not set in pid %u\n", tcp->pid);
1667 return -1;
1668 }
Roland McGratheb9e2e82009-06-02 16:49:22 -07001669 if (ptrace(PTRACE_WRITETEXT, tcp->pid, (char *) tcp->baddr,
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001670 sizeof tcp->inst, (char *) tcp->inst) < 0) {
Roland McGratheb9e2e82009-06-02 16:49:22 -07001671 perror("clearbtp: ptrace(PTRACE_WRITETEXT, ...)");
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001672 return -1;
1673 }
1674 tcp->flags &= ~TCB_BPTSET;
1675
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001676# if !LOOPA
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001677 /*
1678 * Since we don't have a single instruction breakpoint, we may have
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001679 * to adjust the program counter after removing our `breakpoint'.
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001680 */
Roland McGratheb9e2e82009-06-02 16:49:22 -07001681 if (ptrace(PTRACE_GETREGS, tcp->pid, (char *)&regs, 0) < 0) {
1682 perror("clearbpt: ptrace(PTRACE_GETREGS, ...)");
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001683 return -1;
1684 }
Roland McGratheb9e2e82009-06-02 16:49:22 -07001685 if ((regs.r_pc < tcp->baddr) ||
1686 (regs.r_pc > tcp->baddr + 4)) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001687 /* The breakpoint has not been reached yet */
1688 if (debug)
1689 fprintf(stderr,
1690 "NOTE: PC not at bpt (pc %#x baddr %#x)\n",
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001691 regs.r_pc, tcp->baddr);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001692 return 0;
1693 }
1694 if (regs.r_pc != tcp->baddr)
1695 if (debug)
1696 fprintf(stderr, "NOTE: PC adjusted (%#x -> %#x\n",
1697 regs.r_pc, tcp->baddr);
1698
1699 regs.r_pc = tcp->baddr;
Roland McGratheb9e2e82009-06-02 16:49:22 -07001700 if (ptrace(PTRACE_SETREGS, tcp->pid, (char *)&regs, 0) < 0) {
1701 perror("clearbpt: ptrace(PTRACE_SETREGS, ...)");
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001702 return -1;
1703 }
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001704# endif /* LOOPA */
1705# endif /* SPARC */
1706# endif /* SUNOS4 */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001707
1708 return 0;
1709}
1710
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001711# endif /* !defined LINUX */
Roland McGrathd81f1d92003-01-09 06:53:34 +00001712
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001713#endif /* !USE_PROCFS */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001714
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001715
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001716#ifdef SUNOS4
1717
1718static int
Denys Vlasenko12014262011-05-30 14:00:14 +02001719getex(struct tcb *tcp, struct exec *hdr)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001720{
1721 int n;
1722
1723 for (n = 0; n < sizeof *hdr; n += 4) {
1724 long res;
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001725 if (upeek(tcp, uoff(u_exdata) + n, &res) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001726 return -1;
1727 memcpy(((char *) hdr) + n, &res, 4);
1728 }
1729 if (debug) {
1730 fprintf(stderr, "[struct exec: magic: %o version %u Mach %o\n",
1731 hdr->a_magic, hdr->a_toolversion, hdr->a_machtype);
1732 fprintf(stderr, "Text %lu Data %lu Bss %lu Syms %lu Entry %#lx]\n",
1733 hdr->a_text, hdr->a_data, hdr->a_bss, hdr->a_syms, hdr->a_entry);
1734 }
1735 return 0;
1736}
1737
1738int
Denys Vlasenko12014262011-05-30 14:00:14 +02001739fixvfork(struct tcb *tcp)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001740{
1741 int pid = tcp->pid;
1742 /*
1743 * Change `vfork' in a freshly exec'ed dynamically linked
1744 * executable's (internal) symbol table to plain old `fork'
1745 */
1746
1747 struct exec hdr;
1748 struct link_dynamic dyn;
1749 struct link_dynamic_2 ld;
1750 char *strtab, *cp;
1751
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001752 if (getex(tcp, &hdr) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001753 return -1;
1754 if (!hdr.a_dynamic)
1755 return -1;
1756
1757 if (umove(tcp, (int) N_DATADDR(hdr), &dyn) < 0) {
1758 fprintf(stderr, "Cannot read DYNAMIC\n");
1759 return -1;
1760 }
1761 if (umove(tcp, (int) dyn.ld_un.ld_2, &ld) < 0) {
1762 fprintf(stderr, "Cannot read link_dynamic_2\n");
1763 return -1;
1764 }
Denys Vlasenko5d645812011-08-20 12:48:18 +02001765 strtab = malloc((unsigned)ld.ld_symb_size);
Denys Vlasenko1d46ba52011-08-31 14:00:02 +02001766 if (!strtab)
1767 die_out_of_memory();
Roland McGratheb9e2e82009-06-02 16:49:22 -07001768 if (umoven(tcp, (int)ld.ld_symbols+(int)N_TXTADDR(hdr),
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001769 (int)ld.ld_symb_size, strtab) < 0)
1770 goto err;
1771
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001772 for (cp = strtab; cp < strtab + ld.ld_symb_size; ) {
1773 if (strcmp(cp, "_vfork") == 0) {
1774 if (debug)
1775 fprintf(stderr, "fixvfork: FOUND _vfork\n");
1776 strcpy(cp, "_fork");
1777 break;
1778 }
1779 cp += strlen(cp)+1;
1780 }
1781 if (cp < strtab + ld.ld_symb_size)
1782 /*
1783 * Write entire symbol table back to avoid
1784 * memory alignment bugs in ptrace
1785 */
Roland McGratheb9e2e82009-06-02 16:49:22 -07001786 if (tload(pid, (int)ld.ld_symbols+(int)N_TXTADDR(hdr),
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001787 (int)ld.ld_symb_size, strtab) < 0)
1788 goto err;
1789
1790 free(strtab);
1791 return 0;
1792
1793err:
1794 free(strtab);
1795 return -1;
1796}
1797
1798#endif /* SUNOS4 */