blob: 64c1f8a05bc9922a141e90c81dba321e22f70874 [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;
Wichert Akkerman5daa0281999-03-15 19:49:42 +0000783 int started = 0;
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
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000794 if (addr & (sizeof(long) - 1)) {
795 /* addr not a multiple of sizeof(long) */
796 n = addr - (addr & -sizeof(long)); /* residue */
797 addr &= -sizeof(long); /* residue */
Roland McGratheb9e2e82009-06-02 16:49:22 -0700798 errno = 0;
799 u.val = ptrace(PTRACE_PEEKDATA, pid, (char *) addr, 0);
800 if (errno) {
Roland McGratheb9e2e82009-06-02 16:49:22 -0700801 /* But if not started, we had a bogus address. */
802 if (addr != 0 && errno != EIO && errno != ESRCH)
803 perror("ptrace: umoven");
804 return -1;
805 }
Wichert Akkerman5daa0281999-03-15 19:49:42 +0000806 started = 1;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000807 memcpy(laddr, &u.x[n], m = MIN(sizeof(long) - n, len));
808 addr += sizeof(long), laddr += m, len -= m;
809 }
810 while (len) {
Roland McGratheb9e2e82009-06-02 16:49:22 -0700811 errno = 0;
812 u.val = ptrace(PTRACE_PEEKDATA, pid, (char *) addr, 0);
813 if (errno) {
814 if (started && (errno==EPERM || errno==EIO)) {
815 /* Ran into 'end of memory' - stupid "printpath" */
816 return 0;
817 }
818 if (addr != 0 && errno != EIO && errno != ESRCH)
819 perror("ptrace: umoven");
820 return -1;
821 }
Wichert Akkerman5daa0281999-03-15 19:49:42 +0000822 started = 1;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000823 memcpy(laddr, u.x, m = MIN(sizeof(long), len));
824 addr += sizeof(long), laddr += m, len -= m;
825 }
826#endif /* LINUX */
827
828#ifdef SUNOS4
829 int pid = tcp->pid;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000830 int n;
831
832 while (len) {
833 n = MIN(len, PAGSIZ);
834 n = MIN(n, ((addr + PAGSIZ) & PAGMASK) - addr);
Roland McGratheb9e2e82009-06-02 16:49:22 -0700835 if (ptrace(PTRACE_READDATA, pid,
836 (char *) addr, len, laddr) < 0) {
837 if (errno != ESRCH) {
838 perror("umoven: ptrace(PTRACE_READDATA, ...)");
839 abort();
840 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000841 return -1;
842 }
843 len -= n;
844 addr += n;
845 laddr += n;
846 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000847#endif /* SUNOS4 */
848
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000849#ifdef USE_PROCFS
Wichert Akkermanea78f0f1999-11-29 15:34:02 +0000850#ifdef HAVE_MP_PROCFS
John Hughesaa09c6b2001-05-15 14:53:43 +0000851 int fd = tcp->pfd_as;
Wichert Akkerman9ce1a631999-08-29 23:15:07 +0000852#else
John Hughesaa09c6b2001-05-15 14:53:43 +0000853 int fd = tcp->pfd;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000854#endif
John Hughesaa09c6b2001-05-15 14:53:43 +0000855 lseek(fd, addr, SEEK_SET);
856 if (read(fd, laddr, len) == -1)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000857 return -1;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000858#endif /* USE_PROCFS */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000859
860 return 0;
861}
862
863/*
Denys Vlasenko6cecba52012-01-20 11:56:00 +0100864 * Like `umove' but make the additional effort of looking
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000865 * for a terminating zero byte.
Denys Vlasenko6cecba52012-01-20 11:56:00 +0100866 *
867 * Returns < 0 on error, > 0 if NUL was seen,
868 * (TODO if useful: return count of bytes including NUL),
869 * else 0 if len bytes were read but no NUL byte seen.
870 *
871 * Note: there is no guarantee we won't overwrite some bytes
872 * in laddr[] _after_ terminating NUL (but, of course,
873 * we never write past laddr[len-1]).
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000874 */
875int
Denys Vlasenkoef2fbf82009-01-06 21:45:06 +0000876umovestr(struct tcb *tcp, long addr, int len, char *laddr)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000877{
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000878#ifdef USE_PROCFS
John Hughesaa09c6b2001-05-15 14:53:43 +0000879#ifdef HAVE_MP_PROCFS
880 int fd = tcp->pfd_as;
881#else
882 int fd = tcp->pfd;
883#endif
884 /* Some systems (e.g. FreeBSD) can be upset if we read off the
885 end of valid memory, avoid this by trying to read up
886 to page boundaries. But we don't know what a page is (and
887 getpagesize(2) (if it exists) doesn't necessarily return
888 hardware page size). Assume all pages >= 1024 (a-historical
889 I know) */
890
Denys Vlasenkob63256e2011-06-07 12:13:24 +0200891 int page = 1024; /* How to find this? */
John Hughesaa09c6b2001-05-15 14:53:43 +0000892 int move = page - (addr & (page - 1));
893 int left = len;
894
895 lseek(fd, addr, SEEK_SET);
896
897 while (left) {
Denys Vlasenko5d645812011-08-20 12:48:18 +0200898 if (move > left)
899 move = left;
900 move = read(fd, laddr, move);
901 if (move <= 0)
John Hughesaa09c6b2001-05-15 14:53:43 +0000902 return left != len ? 0 : -1;
Denys Vlasenko5d645812011-08-20 12:48:18 +0200903 if (memchr(laddr, 0, move))
Denys Vlasenko6cecba52012-01-20 11:56:00 +0100904 return 1;
John Hughesaa09c6b2001-05-15 14:53:43 +0000905 left -= move;
906 laddr += move;
907 addr += move;
908 move = page;
909 }
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000910#else /* !USE_PROCFS */
Wichert Akkerman5daa0281999-03-15 19:49:42 +0000911 int started = 0;
Roland McGratheb9e2e82009-06-02 16:49:22 -0700912 int pid = tcp->pid;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000913 int i, n, m;
914 union {
915 long val;
916 char x[sizeof(long)];
917 } u;
918
Dmitry V. Levin856c7ed2011-12-26 20:12:02 +0000919#if SUPPORTED_PERSONALITIES > 1
920 if (personality_wordsize[current_personality] < sizeof(addr))
921 addr &= (1ul << 8 * personality_wordsize[current_personality]) - 1;
922#endif
923
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000924 if (addr & (sizeof(long) - 1)) {
925 /* addr not a multiple of sizeof(long) */
926 n = addr - (addr & -sizeof(long)); /* residue */
927 addr &= -sizeof(long); /* residue */
Roland McGratheb9e2e82009-06-02 16:49:22 -0700928 errno = 0;
929 u.val = ptrace(PTRACE_PEEKDATA, pid, (char *)addr, 0);
930 if (errno) {
Roland McGratheb9e2e82009-06-02 16:49:22 -0700931 if (addr != 0 && errno != EIO && errno != ESRCH)
932 perror("umovestr");
933 return -1;
934 }
Wichert Akkerman5daa0281999-03-15 19:49:42 +0000935 started = 1;
Denys Vlasenkob63256e2011-06-07 12:13:24 +0200936 memcpy(laddr, &u.x[n], m = MIN(sizeof(long)-n, len));
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000937 while (n & (sizeof(long) - 1))
938 if (u.x[n++] == '\0')
Denys Vlasenko6cecba52012-01-20 11:56:00 +0100939 return 1;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000940 addr += sizeof(long), laddr += m, len -= m;
941 }
942 while (len) {
Roland McGratheb9e2e82009-06-02 16:49:22 -0700943 errno = 0;
944 u.val = ptrace(PTRACE_PEEKDATA, pid, (char *)addr, 0);
945 if (errno) {
946 if (started && (errno==EPERM || errno==EIO)) {
947 /* Ran into 'end of memory' - stupid "printpath" */
948 return 0;
949 }
950 if (addr != 0 && errno != EIO && errno != ESRCH)
951 perror("umovestr");
952 return -1;
953 }
Wichert Akkerman5daa0281999-03-15 19:49:42 +0000954 started = 1;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000955 memcpy(laddr, u.x, m = MIN(sizeof(long), len));
956 for (i = 0; i < sizeof(long); i++)
957 if (u.x[i] == '\0')
Denys Vlasenko6cecba52012-01-20 11:56:00 +0100958 return 1;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000959
960 addr += sizeof(long), laddr += m, len -= m;
961 }
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000962#endif /* !USE_PROCFS */
John Hughesaa09c6b2001-05-15 14:53:43 +0000963 return 0;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000964}
965
966#ifdef LINUX
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +0000967# if !defined (SPARC) && !defined(SPARC64)
968# define PTRACE_WRITETEXT 101
969# define PTRACE_WRITEDATA 102
970# endif /* !SPARC && !SPARC64 */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000971#endif /* LINUX */
972
973#ifdef SUNOS4
974
975static int
Denys Vlasenko12014262011-05-30 14:00:14 +0200976uload(int cmd, int pid, long addr, int len, char *laddr)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000977{
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000978 int peek, poke;
979 int n, m;
980 union {
981 long val;
982 char x[sizeof(long)];
983 } u;
984
985 if (cmd == PTRACE_WRITETEXT) {
986 peek = PTRACE_PEEKTEXT;
987 poke = PTRACE_POKETEXT;
988 }
989 else {
990 peek = PTRACE_PEEKDATA;
991 poke = PTRACE_POKEDATA;
992 }
993 if (addr & (sizeof(long) - 1)) {
994 /* addr not a multiple of sizeof(long) */
995 n = addr - (addr & -sizeof(long)); /* residue */
996 addr &= -sizeof(long);
Roland McGratheb9e2e82009-06-02 16:49:22 -0700997 errno = 0;
998 u.val = ptrace(peek, pid, (char *) addr, 0);
999 if (errno) {
1000 perror("uload: POKE");
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001001 return -1;
1002 }
Roland McGratheb9e2e82009-06-02 16:49:22 -07001003 memcpy(&u.x[n], laddr, m = MIN(sizeof(long) - n, len));
1004 if (ptrace(poke, pid, (char *)addr, u.val) < 0) {
1005 perror("uload: POKE");
1006 return -1;
1007 }
1008 addr += sizeof(long), laddr += m, len -= m;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001009 }
1010 while (len) {
1011 if (len < sizeof(long))
Roland McGratheb9e2e82009-06-02 16:49:22 -07001012 u.val = ptrace(peek, pid, (char *) addr, 0);
1013 memcpy(u.x, laddr, m = MIN(sizeof(long), len));
1014 if (ptrace(poke, pid, (char *) addr, u.val) < 0) {
1015 perror("uload: POKE");
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001016 return -1;
1017 }
Roland McGratheb9e2e82009-06-02 16:49:22 -07001018 addr += sizeof(long), laddr += m, len -= m;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001019 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001020 return 0;
1021}
1022
Roland McGratheb9e2e82009-06-02 16:49:22 -07001023int
Denys Vlasenko12014262011-05-30 14:00:14 +02001024tload(int pid, int addr, int len, char *laddr)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001025{
Roland McGratheb9e2e82009-06-02 16:49:22 -07001026 return uload(PTRACE_WRITETEXT, pid, addr, len, laddr);
1027}
1028
1029int
Denys Vlasenko12014262011-05-30 14:00:14 +02001030dload(int pid, int addr, int len, char *laddr)
Roland McGratheb9e2e82009-06-02 16:49:22 -07001031{
1032 return uload(PTRACE_WRITEDATA, pid, addr, len, laddr);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001033}
1034
1035#endif /* SUNOS4 */
1036
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001037#ifndef USE_PROCFS
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001038
1039int
Denys Vlasenko12014262011-05-30 14:00:14 +02001040upeek(struct tcb *tcp, long off, long *res)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001041{
1042 long val;
1043
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001044# ifdef SUNOS4_KERNEL_ARCH_KLUDGE
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001045 {
1046 static int is_sun4m = -1;
1047 struct utsname name;
1048
1049 /* Round up the usual suspects. */
1050 if (is_sun4m == -1) {
1051 if (uname(&name) < 0) {
1052 perror("upeek: uname?");
1053 exit(1);
1054 }
1055 is_sun4m = strcmp(name.machine, "sun4m") == 0;
1056 if (is_sun4m) {
Roland McGrathd9f816f2004-09-04 03:39:20 +00001057 const struct xlat *x;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001058
1059 for (x = struct_user_offsets; x->str; x++)
1060 x->val += 1024;
1061 }
1062 }
1063 if (is_sun4m)
1064 off += 1024;
1065 }
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001066# endif /* SUNOS4_KERNEL_ARCH_KLUDGE */
Roland McGratheb9e2e82009-06-02 16:49:22 -07001067 errno = 0;
Denys Vlasenko732d1bf2008-12-17 19:21:59 +00001068 val = do_ptrace(PTRACE_PEEKUSER, tcp, (char *) off, 0);
Roland McGratheb9e2e82009-06-02 16:49:22 -07001069 if (val == -1 && errno) {
1070 if (errno != ESRCH) {
1071 char buf[60];
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001072 sprintf(buf, "upeek: ptrace(PTRACE_PEEKUSER,%d,%lu,0)", tcp->pid, off);
Roland McGratheb9e2e82009-06-02 16:49:22 -07001073 perror(buf);
1074 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001075 return -1;
Roland McGratheb9e2e82009-06-02 16:49:22 -07001076 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001077 *res = val;
1078 return 0;
1079}
1080
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001081#endif /* !USE_PROCFS */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001082
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001083void
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001084printcall(struct tcb *tcp)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001085{
Roland McGrath7a918832005-02-02 20:55:23 +00001086#define PRINTBADPC tprintf(sizeof(long) == 4 ? "[????????] " : \
1087 sizeof(long) == 8 ? "[????????????????] " : \
1088 NULL /* crash */)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001089
1090#ifdef LINUX
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001091# ifdef I386
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001092 long eip;
1093
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001094 if (upeek(tcp, 4*EIP, &eip) < 0) {
Roland McGrath7a918832005-02-02 20:55:23 +00001095 PRINTBADPC;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001096 return;
1097 }
1098 tprintf("[%08lx] ", eip);
Roland McGratheac26fc2005-02-02 02:48:53 +00001099
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001100# elif defined(S390) || defined(S390X)
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001101 long psw;
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001102 if (upeek(tcp, PT_PSWADDR, &psw) < 0) {
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001103 PRINTBADPC;
1104 return;
1105 }
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001106# ifdef S390
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001107 tprintf("[%08lx] ", psw);
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001108# elif S390X
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001109 tprintf("[%16lx] ", psw);
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001110# endif
Roland McGratheac26fc2005-02-02 02:48:53 +00001111
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001112# elif defined(X86_64)
Michal Ludvig0e035502002-09-23 15:41:01 +00001113 long rip;
1114
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001115 if (upeek(tcp, 8*RIP, &rip) < 0) {
Roland McGrath7a918832005-02-02 20:55:23 +00001116 PRINTBADPC;
Michal Ludvig0e035502002-09-23 15:41:01 +00001117 return;
1118 }
1119 tprintf("[%16lx] ", rip);
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001120# elif defined(IA64)
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00001121 long ip;
1122
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001123 if (upeek(tcp, PT_B0, &ip) < 0) {
Roland McGrath7a918832005-02-02 20:55:23 +00001124 PRINTBADPC;
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00001125 return;
1126 }
1127 tprintf("[%08lx] ", ip);
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001128# elif defined(POWERPC)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001129 long pc;
1130
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001131 if (upeek(tcp, sizeof(unsigned long)*PT_NIP, &pc) < 0) {
Andreas Schwabd69fa492010-07-12 21:39:57 +02001132 PRINTBADPC;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001133 return;
1134 }
Andreas Schwabd69fa492010-07-12 21:39:57 +02001135# ifdef POWERPC64
1136 tprintf("[%016lx] ", pc);
1137# else
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001138 tprintf("[%08lx] ", pc);
Andreas Schwabd69fa492010-07-12 21:39:57 +02001139# endif
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001140# elif defined(M68K)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001141 long pc;
1142
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001143 if (upeek(tcp, 4*PT_PC, &pc) < 0) {
Denys Vlasenko60fe8c12011-09-01 10:00:28 +02001144 tprints("[????????] ");
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001145 return;
1146 }
1147 tprintf("[%08lx] ", pc);
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001148# elif defined(ALPHA)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001149 long pc;
1150
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001151 if (upeek(tcp, REG_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(SPARC) || defined(SPARC64)
Mike Frysinger8566c502009-10-12 11:05:14 -04001157 struct pt_regs regs;
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001158 if (ptrace(PTRACE_GETREGS, tcp->pid, (char *)&regs, 0) < 0) {
Roland McGrath7a918832005-02-02 20:55:23 +00001159 PRINTBADPC;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001160 return;
1161 }
Mike Frysinger8566c502009-10-12 11:05:14 -04001162# if defined(SPARC64)
1163 tprintf("[%08lx] ", regs.tpc);
1164# else
1165 tprintf("[%08lx] ", regs.pc);
1166# endif
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001167# elif defined(HPPA)
Wichert Akkermanc1652e22001-03-27 12:17:16 +00001168 long pc;
1169
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001170 if (upeek(tcp, PT_IAOQ0, &pc) < 0) {
Denys Vlasenko60fe8c12011-09-01 10:00:28 +02001171 tprints("[????????] ");
Wichert Akkermanc1652e22001-03-27 12:17:16 +00001172 return;
1173 }
1174 tprintf("[%08lx] ", pc);
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001175# elif defined(MIPS)
Wichert Akkerman75c422b2001-04-10 10:22:50 +00001176 long pc;
1177
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001178 if (upeek(tcp, REG_EPC, &pc) < 0) {
Denys Vlasenko60fe8c12011-09-01 10:00:28 +02001179 tprints("[????????] ");
Wichert Akkerman75c422b2001-04-10 10:22:50 +00001180 return;
1181 }
1182 tprintf("[%08lx] ", pc);
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001183# elif defined(SH)
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001184 long pc;
Wichert Akkermanccef6372002-05-01 16:39:22 +00001185
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001186 if (upeek(tcp, 4*REG_PC, &pc) < 0) {
Denys Vlasenko60fe8c12011-09-01 10:00:28 +02001187 tprints("[????????] ");
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001188 return;
1189 }
1190 tprintf("[%08lx] ", pc);
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001191# elif defined(SH64)
Roland McGrathe1e584b2003-06-02 19:18:58 +00001192 long pc;
1193
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001194 if (upeek(tcp, REG_PC, &pc) < 0) {
Denys Vlasenko60fe8c12011-09-01 10:00:28 +02001195 tprints("[????????????????] ");
Roland McGrathe1e584b2003-06-02 19:18:58 +00001196 return;
1197 }
1198 tprintf("[%08lx] ", pc);
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001199# elif defined(ARM)
Roland McGrathef388682003-06-03 23:28:59 +00001200 long pc;
Roland McGrathe1e584b2003-06-02 19:18:58 +00001201
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001202 if (upeek(tcp, 4*15, &pc) < 0) {
Roland McGrath7a918832005-02-02 20:55:23 +00001203 PRINTBADPC;
Roland McGrathef388682003-06-03 23:28:59 +00001204 return;
1205 }
1206 tprintf("[%08lx] ", pc);
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00001207# elif defined(AVR32)
1208 long pc;
1209
1210 if (upeek(tcp, REG_PC, &pc) < 0) {
Denys Vlasenko60fe8c12011-09-01 10:00:28 +02001211 tprints("[????????] ");
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00001212 return;
1213 }
1214 tprintf("[%08lx] ", pc);
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001215# elif defined(BFIN)
Dmitry V. Levin87ea1f42008-11-10 22:21:41 +00001216 long pc;
1217
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001218 if (upeek(tcp, PT_PC, &pc) < 0) {
Dmitry V. Levin87ea1f42008-11-10 22:21:41 +00001219 PRINTBADPC;
1220 return;
1221 }
1222 tprintf("[%08lx] ", pc);
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001223#elif defined(CRISV10)
1224 long pc;
1225
Edgar E. Iglesiaseeb9ce32009-10-05 14:41:02 +00001226 if (upeek(tcp, 4*PT_IRP, &pc) < 0) {
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001227 PRINTBADPC;
1228 return;
1229 }
1230 tprintf("[%08lx] ", pc);
1231#elif defined(CRISV32)
1232 long pc;
1233
Edgar E. Iglesiaseeb9ce32009-10-05 14:41:02 +00001234 if (upeek(tcp, 4*PT_ERP, &pc) < 0) {
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001235 PRINTBADPC;
1236 return;
1237 }
1238 tprintf("[%08lx] ", pc);
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001239# endif /* architecture */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001240#endif /* LINUX */
1241
1242#ifdef SUNOS4
1243 struct regs regs;
1244
Roland McGratheb9e2e82009-06-02 16:49:22 -07001245 if (ptrace(PTRACE_GETREGS, tcp->pid, (char *) &regs, 0) < 0) {
1246 perror("printcall: ptrace(PTRACE_GETREGS, ...)");
Roland McGrath7a918832005-02-02 20:55:23 +00001247 PRINTBADPC;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001248 return;
1249 }
1250 tprintf("[%08x] ", regs.r_o7);
1251#endif /* SUNOS4 */
1252
1253#ifdef SVR4
1254 /* XXX */
Roland McGrath7a918832005-02-02 20:55:23 +00001255 PRINTBADPC;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001256#endif
1257
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001258#ifdef FREEBSD
1259 struct reg regs;
1260 pread(tcp->pfd_reg, &regs, sizeof(regs), 0);
1261 tprintf("[%08x] ", regs.r_eip);
1262#endif /* FREEBSD */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001263}
1264
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001265
1266/*
1267 * These #if's are huge, please indent them correctly.
1268 * It's easy to get confused otherwise.
1269 */
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001270#ifndef USE_PROCFS
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001271
Denys Vlasenkoe7c90242011-06-22 00:09:25 +02001272# ifdef LINUX
Roland McGrathd81f1d92003-01-09 06:53:34 +00001273
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001274# include "syscall.h"
Roland McGrath3291ef22008-05-20 00:34:34 +00001275
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001276# include <sys/syscall.h>
1277# ifndef CLONE_PTRACE
1278# define CLONE_PTRACE 0x00002000
1279# endif
1280# ifndef CLONE_VFORK
1281# define CLONE_VFORK 0x00004000
1282# endif
1283# ifndef CLONE_VM
1284# define CLONE_VM 0x00000100
1285# endif
1286# ifndef CLONE_STOPPED
1287# define CLONE_STOPPED 0x02000000
1288# endif
Roland McGrathd81f1d92003-01-09 06:53:34 +00001289
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001290# ifdef IA64
Roland McGrathd81f1d92003-01-09 06:53:34 +00001291
Roland McGrath08267b82004-02-20 22:56:43 +00001292/* We don't have fork()/vfork() syscalls on ia64 itself, but the ia32
1293 subsystem has them for x86... */
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001294# define SYS_fork 2
1295# define SYS_vfork 190
Roland McGrath08267b82004-02-20 22:56:43 +00001296
Roland McGrathd81f1d92003-01-09 06:53:34 +00001297typedef unsigned long *arg_setup_state;
1298
1299static int
1300arg_setup(struct tcb *tcp, arg_setup_state *state)
1301{
Jan Kratochvil1f942712008-08-06 21:38:52 +00001302 unsigned long cfm, sof, sol;
1303 long bsp;
Roland McGrathd81f1d92003-01-09 06:53:34 +00001304
Jan Kratochvil1f942712008-08-06 21:38:52 +00001305 if (ia32) {
1306 /* Satisfy a false GCC warning. */
1307 *state = NULL;
Roland McGrath08267b82004-02-20 22:56:43 +00001308 return 0;
Jan Kratochvil1f942712008-08-06 21:38:52 +00001309 }
Roland McGrath08267b82004-02-20 22:56:43 +00001310
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001311 if (upeek(tcp, PT_AR_BSP, &bsp) < 0)
Roland McGrathd81f1d92003-01-09 06:53:34 +00001312 return -1;
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001313 if (upeek(tcp, PT_CFM, (long *) &cfm) < 0)
Roland McGrathd81f1d92003-01-09 06:53:34 +00001314 return -1;
1315
1316 sof = (cfm >> 0) & 0x7f;
1317 sol = (cfm >> 7) & 0x7f;
Jan Kratochvil1f942712008-08-06 21:38:52 +00001318 bsp = (long) ia64_rse_skip_regs((unsigned long *) bsp, -sof + sol);
Roland McGrathd81f1d92003-01-09 06:53:34 +00001319
Jan Kratochvil1f942712008-08-06 21:38:52 +00001320 *state = (unsigned long *) bsp;
Roland McGrathd81f1d92003-01-09 06:53:34 +00001321 return 0;
1322}
1323
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001324# define arg_finish_change(tcp, state) 0
Roland McGrathd81f1d92003-01-09 06:53:34 +00001325
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001326# ifdef SYS_fork
Roland McGrathd81f1d92003-01-09 06:53:34 +00001327static int
Denys Vlasenko12014262011-05-30 14:00:14 +02001328get_arg0(struct tcb *tcp, arg_setup_state *state, long *valp)
Roland McGrathd81f1d92003-01-09 06:53:34 +00001329{
Roland McGrath08267b82004-02-20 22:56:43 +00001330 int ret;
1331
1332 if (ia32)
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001333 ret = upeek(tcp, PT_R11, valp);
Roland McGrath08267b82004-02-20 22:56:43 +00001334 else
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001335 ret = umoven(tcp,
Roland McGrath08267b82004-02-20 22:56:43 +00001336 (unsigned long) ia64_rse_skip_regs(*state, 0),
1337 sizeof(long), (void *) valp);
1338 return ret;
Roland McGrathd81f1d92003-01-09 06:53:34 +00001339}
1340
1341static int
Denys Vlasenko12014262011-05-30 14:00:14 +02001342get_arg1(struct tcb *tcp, arg_setup_state *state, long *valp)
Roland McGrathd81f1d92003-01-09 06:53:34 +00001343{
Roland McGrath08267b82004-02-20 22:56:43 +00001344 int ret;
1345
1346 if (ia32)
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001347 ret = upeek(tcp, PT_R9, valp);
Roland McGrath08267b82004-02-20 22:56:43 +00001348 else
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001349 ret = umoven(tcp,
Roland McGrath08267b82004-02-20 22:56:43 +00001350 (unsigned long) ia64_rse_skip_regs(*state, 1),
1351 sizeof(long), (void *) valp);
1352 return ret;
Roland McGrathd81f1d92003-01-09 06:53:34 +00001353}
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001354# endif
Roland McGrathd81f1d92003-01-09 06:53:34 +00001355
1356static int
Denys Vlasenko12014262011-05-30 14:00:14 +02001357set_arg0(struct tcb *tcp, arg_setup_state *state, long val)
Roland McGrathd81f1d92003-01-09 06:53:34 +00001358{
Roland McGrath08267b82004-02-20 22:56:43 +00001359 int req = PTRACE_POKEDATA;
1360 void *ap;
1361
1362 if (ia32) {
1363 ap = (void *) (intptr_t) PT_R11; /* r11 == EBX */
1364 req = PTRACE_POKEUSER;
1365 } else
1366 ap = ia64_rse_skip_regs(*state, 0);
Roland McGratheb9e2e82009-06-02 16:49:22 -07001367 errno = 0;
1368 ptrace(req, tcp->pid, ap, val);
1369 return errno ? -1 : 0;
Roland McGrathd81f1d92003-01-09 06:53:34 +00001370}
1371
1372static int
Denys Vlasenko12014262011-05-30 14:00:14 +02001373set_arg1(struct tcb *tcp, arg_setup_state *state, long val)
Roland McGrathd81f1d92003-01-09 06:53:34 +00001374{
Roland McGrath08267b82004-02-20 22:56:43 +00001375 int req = PTRACE_POKEDATA;
1376 void *ap;
1377
1378 if (ia32) {
1379 ap = (void *) (intptr_t) PT_R9; /* r9 == ECX */
1380 req = PTRACE_POKEUSER;
1381 } else
1382 ap = ia64_rse_skip_regs(*state, 1);
Roland McGratheb9e2e82009-06-02 16:49:22 -07001383 errno = 0;
1384 ptrace(req, tcp->pid, ap, val);
1385 return errno ? -1 : 0;
Roland McGrathd81f1d92003-01-09 06:53:34 +00001386}
1387
Roland McGrathb659f872008-07-18 01:19:36 +00001388/* ia64 does not return the input arguments from functions (and syscalls)
1389 according to ia64 RSE (Register Stack Engine) behavior. */
1390
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001391# define restore_arg0(tcp, state, val) ((void) (state), 0)
1392# define restore_arg1(tcp, state, val) ((void) (state), 0)
Roland McGrathb659f872008-07-18 01:19:36 +00001393
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001394# elif defined (SPARC) || defined (SPARC64)
Roland McGrathd81f1d92003-01-09 06:53:34 +00001395
Mike Frysinger8566c502009-10-12 11:05:14 -04001396typedef struct pt_regs arg_setup_state;
Roland McGrathd81f1d92003-01-09 06:53:34 +00001397
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001398# define arg_setup(tcp, state) \
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001399 (ptrace(PTRACE_GETREGS, tcp->pid, (char *) (state), 0))
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001400# define arg_finish_change(tcp, state) \
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001401 (ptrace(PTRACE_SETREGS, tcp->pid, (char *) (state), 0))
Roland McGrathd81f1d92003-01-09 06:53:34 +00001402
Mike Frysinger8566c502009-10-12 11:05:14 -04001403# define get_arg0(tcp, state, valp) (*(valp) = (state)->u_regs[U_REG_O0], 0)
1404# define get_arg1(tcp, state, valp) (*(valp) = (state)->u_regs[U_REG_O1], 0)
1405# define set_arg0(tcp, state, val) ((state)->u_regs[U_REG_O0] = (val), 0)
1406# define set_arg1(tcp, state, val) ((state)->u_regs[U_REG_O1] = (val), 0)
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001407# define restore_arg0(tcp, state, val) 0
Roland McGrathd81f1d92003-01-09 06:53:34 +00001408
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001409# else /* other architectures */
Roland McGrathd81f1d92003-01-09 06:53:34 +00001410
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001411# if defined S390 || defined S390X
Roland McGrath7b308222003-01-20 09:04:36 +00001412/* Note: this is only true for the `clone' system call, which handles
1413 arguments specially. We could as well say that its first two arguments
1414 are swapped relative to other architectures, but that would just be
1415 another #ifdef in the calls. */
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001416# define arg0_offset PT_GPR3
1417# define arg1_offset PT_ORIGGPR2
1418# define restore_arg0(tcp, state, val) ((void) (state), 0)
1419# define restore_arg1(tcp, state, val) ((void) (state), 0)
1420# define arg0_index 1
1421# define arg1_index 0
1422# elif defined (ALPHA) || defined (MIPS)
1423# define arg0_offset REG_A0
1424# define arg1_offset (REG_A0+1)
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00001425# elif defined (AVR32)
1426# define arg0_offset (REG_R12)
1427# define arg1_offset (REG_R11)
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001428# elif defined (POWERPC)
1429# define arg0_offset (sizeof(unsigned long)*PT_R3)
1430# define arg1_offset (sizeof(unsigned long)*PT_R4)
1431# define restore_arg0(tcp, state, val) ((void) (state), 0)
1432# elif defined (HPPA)
1433# define arg0_offset PT_GR26
1434# define arg1_offset (PT_GR26-4)
1435# elif defined (X86_64)
1436# define arg0_offset ((long)(8*(current_personality ? RBX : RDI)))
1437# define arg1_offset ((long)(8*(current_personality ? RCX : RSI)))
1438# elif defined (SH)
1439# define arg0_offset (4*(REG_REG0+4))
1440# define arg1_offset (4*(REG_REG0+5))
1441# elif defined (SH64)
1442 /* ABI defines arg0 & 1 in r2 & r3 */
1443# define arg0_offset (REG_OFFSET+16)
1444# define arg1_offset (REG_OFFSET+24)
1445# define restore_arg0(tcp, state, val) 0
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001446# elif defined CRISV10 || defined CRISV32
1447# define arg0_offset (4*PT_R11)
1448# define arg1_offset (4*PT_ORIG_R10)
1449# define restore_arg0(tcp, state, val) 0
1450# define restore_arg1(tcp, state, val) 0
1451# define arg0_index 1
1452# define arg1_index 0
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001453# else
1454# define arg0_offset 0
1455# define arg1_offset 4
1456# if defined ARM
1457# define restore_arg0(tcp, state, val) 0
1458# endif
1459# endif
Roland McGrathd81f1d92003-01-09 06:53:34 +00001460
1461typedef int arg_setup_state;
1462
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001463# define arg_setup(tcp, state) (0)
1464# define arg_finish_change(tcp, state) 0
1465# define get_arg0(tcp, cookie, valp) \
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001466 (upeek((tcp), arg0_offset, (valp)))
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001467# define get_arg1(tcp, cookie, valp) \
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001468 (upeek((tcp), arg1_offset, (valp)))
Roland McGrathd81f1d92003-01-09 06:53:34 +00001469
1470static int
Denys Vlasenko12014262011-05-30 14:00:14 +02001471set_arg0(struct tcb *tcp, void *cookie, long val)
Roland McGrathd81f1d92003-01-09 06:53:34 +00001472{
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001473 return ptrace(PTRACE_POKEUSER, tcp->pid, (char*)arg0_offset, val);
Roland McGrathd81f1d92003-01-09 06:53:34 +00001474}
1475
1476static int
Denys Vlasenko12014262011-05-30 14:00:14 +02001477set_arg1(struct tcb *tcp, void *cookie, long val)
Roland McGrathd81f1d92003-01-09 06:53:34 +00001478{
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001479 return ptrace(PTRACE_POKEUSER, tcp->pid, (char*)arg1_offset, val);
Roland McGrathd81f1d92003-01-09 06:53:34 +00001480}
1481
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001482# endif /* architectures */
Roland McGrathd81f1d92003-01-09 06:53:34 +00001483
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001484# ifndef restore_arg0
1485# define restore_arg0(tcp, state, val) set_arg0((tcp), (state), (val))
1486# endif
1487# ifndef restore_arg1
1488# define restore_arg1(tcp, state, val) set_arg1((tcp), (state), (val))
1489# endif
Roland McGrathd81f1d92003-01-09 06:53:34 +00001490
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001491# ifndef arg0_index
1492# define arg0_index 0
1493# define arg1_index 1
1494# endif
Roland McGrath90d0afd2004-03-01 21:05:16 +00001495
Roland McGrathd81f1d92003-01-09 06:53:34 +00001496int
Denys Vlasenko418d66a2009-01-17 01:52:54 +00001497setbpt(struct tcb *tcp)
Roland McGrathd81f1d92003-01-09 06:53:34 +00001498{
Roland McGrath3291ef22008-05-20 00:34:34 +00001499 static int clone_scno[SUPPORTED_PERSONALITIES] = { SYS_clone };
Roland McGrathd81f1d92003-01-09 06:53:34 +00001500 arg_setup_state state;
1501
1502 if (tcp->flags & TCB_BPTSET) {
1503 fprintf(stderr, "PANIC: TCB already set in pid %u\n", tcp->pid);
1504 return -1;
1505 }
1506
Roland McGrath3291ef22008-05-20 00:34:34 +00001507 /*
1508 * It's a silly kludge to initialize this with a search at runtime.
1509 * But it's better than maintaining another magic thing in the
1510 * godforsaken tables.
1511 */
1512 if (clone_scno[current_personality] == 0) {
1513 int i;
1514 for (i = 0; i < nsyscalls; ++i)
1515 if (sysent[i].sys_func == sys_clone) {
1516 clone_scno[current_personality] = i;
1517 break;
1518 }
1519 }
1520
Roland McGrath76989d72005-06-07 23:21:31 +00001521 switch (known_scno(tcp)) {
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001522# ifdef SYS_vfork
Roland McGrath9383c6c2003-01-18 00:19:31 +00001523 case SYS_vfork:
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001524# endif
1525# ifdef SYS_fork
Roland McGrathd81f1d92003-01-09 06:53:34 +00001526 case SYS_fork:
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001527# endif
1528# if defined SYS_fork || defined SYS_vfork
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001529 if (arg_setup(tcp, &state) < 0
1530 || get_arg0(tcp, &state, &tcp->inst[0]) < 0
1531 || get_arg1(tcp, &state, &tcp->inst[1]) < 0
Roland McGrath3291ef22008-05-20 00:34:34 +00001532 || change_syscall(tcp, clone_scno[current_personality]) < 0
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001533 || set_arg0(tcp, &state, CLONE_PTRACE|SIGCHLD) < 0
1534 || set_arg1(tcp, &state, 0) < 0
1535 || arg_finish_change(tcp, &state) < 0)
Roland McGrathd81f1d92003-01-09 06:53:34 +00001536 return -1;
Roland McGrathc9dc3c12004-03-01 20:57:09 +00001537 tcp->u_arg[arg0_index] = CLONE_PTRACE|SIGCHLD;
1538 tcp->u_arg[arg1_index] = 0;
Roland McGrathd81f1d92003-01-09 06:53:34 +00001539 tcp->flags |= TCB_BPTSET;
1540 return 0;
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001541# endif
Roland McGrathd81f1d92003-01-09 06:53:34 +00001542
Denys Vlasenkoc133bf02011-06-23 21:57:54 +02001543 case SYS_clone: ;
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001544# ifdef SYS_clone2
Denys Vlasenkoc133bf02011-06-23 21:57:54 +02001545 case SYS_clone2: ;
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001546# endif
Jan Kratochvil8fc95752008-08-06 21:43:35 +00001547 /* ia64 calls directly `clone (CLONE_VFORK | CLONE_VM)'
1548 contrary to x86 SYS_vfork above. Even on x86 we turn the
1549 vfork semantics into plain fork - each application must not
1550 depend on the vfork specifics according to POSIX. We would
1551 hang waiting for the parent resume otherwise. We need to
1552 clear also CLONE_VM but only in the CLONE_VFORK case as
1553 otherwise we would break pthread_create. */
1554
Denys Vlasenkoc133bf02011-06-23 21:57:54 +02001555 long new_arg0 = (tcp->u_arg[arg0_index] | CLONE_PTRACE);
1556 if (new_arg0 & CLONE_VFORK)
1557 new_arg0 &= ~(unsigned long)(CLONE_VFORK | CLONE_VM);
1558 if (arg_setup(tcp, &state) < 0
1559 || set_arg0(tcp, &state, new_arg0) < 0
1560 || arg_finish_change(tcp, &state) < 0)
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00001561 return -1;
Roland McGrathd81f1d92003-01-09 06:53:34 +00001562 tcp->flags |= TCB_BPTSET;
Roland McGrathc9dc3c12004-03-01 20:57:09 +00001563 tcp->inst[0] = tcp->u_arg[arg0_index];
1564 tcp->inst[1] = tcp->u_arg[arg1_index];
Roland McGrathd81f1d92003-01-09 06:53:34 +00001565 return 0;
1566
1567 default:
1568 fprintf(stderr, "PANIC: setbpt for syscall %ld on %u???\n",
1569 tcp->scno, tcp->pid);
1570 break;
1571 }
1572
1573 return -1;
1574}
1575
1576int
Denys Vlasenko12014262011-05-30 14:00:14 +02001577clearbpt(struct tcb *tcp)
Roland McGrathd81f1d92003-01-09 06:53:34 +00001578{
1579 arg_setup_state state;
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001580 if (arg_setup(tcp, &state) < 0
1581 || restore_arg0(tcp, &state, tcp->inst[0]) < 0
1582 || restore_arg1(tcp, &state, tcp->inst[1]) < 0
1583 || arg_finish_change(tcp, &state))
Denys Vlasenkoc133bf02011-06-23 21:57:54 +02001584 if (errno != ESRCH)
1585 return -1;
Roland McGrathd81f1d92003-01-09 06:53:34 +00001586 tcp->flags &= ~TCB_BPTSET;
1587 return 0;
1588}
1589
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001590# else /* !defined LINUX */
Roland McGrathd81f1d92003-01-09 06:53:34 +00001591
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001592int
Denys Vlasenko12014262011-05-30 14:00:14 +02001593setbpt(struct tcb *tcp)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001594{
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001595# ifdef SUNOS4
1596# ifdef SPARC /* This code is slightly sparc specific */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001597
Wichert Akkermane6f876c1999-06-22 15:28:30 +00001598 struct regs regs;
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001599# define BPT 0x91d02001 /* ta 1 */
1600# define LOOP 0x10800000 /* ba 0 */
1601# define LOOPA 0x30800000 /* ba,a 0 */
1602# define NOP 0x01000000
1603# if LOOPA
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001604 static int loopdeloop[1] = {LOOPA};
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001605# else
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001606 static int loopdeloop[2] = {LOOP, NOP};
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001607# endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001608
1609 if (tcp->flags & TCB_BPTSET) {
1610 fprintf(stderr, "PANIC: TCB already set in pid %u\n", tcp->pid);
1611 return -1;
1612 }
Roland McGratheb9e2e82009-06-02 16:49:22 -07001613 if (ptrace(PTRACE_GETREGS, tcp->pid, (char *)&regs, 0) < 0) {
1614 perror("setbpt: ptrace(PTRACE_GETREGS, ...)");
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001615 return -1;
1616 }
1617 tcp->baddr = regs.r_o7 + 8;
Roland McGratheb9e2e82009-06-02 16:49:22 -07001618 if (ptrace(PTRACE_READTEXT, tcp->pid, (char *)tcp->baddr,
1619 sizeof tcp->inst, (char *)tcp->inst) < 0) {
1620 perror("setbpt: ptrace(PTRACE_READTEXT, ...)");
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001621 return -1;
1622 }
1623
1624 /*
1625 * XXX - BRUTAL MODE ON
1626 * We cannot set a real BPT in the child, since it will not be
1627 * traced at the moment it will reach the trap and would probably
1628 * die with a core dump.
1629 * Thus, we are force our way in by taking out two instructions
1630 * and insert an eternal loop in stead, in expectance of the SIGSTOP
1631 * generated by out PTRACE_ATTACH.
1632 * Of cause, if we evaporate ourselves in the middle of all this...
1633 */
Roland McGratheb9e2e82009-06-02 16:49:22 -07001634 if (ptrace(PTRACE_WRITETEXT, tcp->pid, (char *) tcp->baddr,
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001635 sizeof loopdeloop, (char *) loopdeloop) < 0) {
Roland McGratheb9e2e82009-06-02 16:49:22 -07001636 perror("setbpt: ptrace(PTRACE_WRITETEXT, ...)");
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001637 return -1;
1638 }
1639 tcp->flags |= TCB_BPTSET;
1640
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001641# endif /* SPARC */
1642# endif /* SUNOS4 */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001643
1644 return 0;
1645}
1646
1647int
Denys Vlasenko12014262011-05-30 14:00:14 +02001648clearbpt(struct tcb *tcp)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001649{
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001650# ifdef SUNOS4
1651# ifdef SPARC
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001652
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001653# if !LOOPA
Wichert Akkermane6f876c1999-06-22 15:28:30 +00001654 struct regs regs;
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001655# endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001656
1657 if (!(tcp->flags & TCB_BPTSET)) {
1658 fprintf(stderr, "PANIC: TCB not set in pid %u\n", tcp->pid);
1659 return -1;
1660 }
Roland McGratheb9e2e82009-06-02 16:49:22 -07001661 if (ptrace(PTRACE_WRITETEXT, tcp->pid, (char *) tcp->baddr,
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001662 sizeof tcp->inst, (char *) tcp->inst) < 0) {
Roland McGratheb9e2e82009-06-02 16:49:22 -07001663 perror("clearbtp: ptrace(PTRACE_WRITETEXT, ...)");
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001664 return -1;
1665 }
1666 tcp->flags &= ~TCB_BPTSET;
1667
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001668# if !LOOPA
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001669 /*
1670 * Since we don't have a single instruction breakpoint, we may have
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001671 * to adjust the program counter after removing our `breakpoint'.
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001672 */
Roland McGratheb9e2e82009-06-02 16:49:22 -07001673 if (ptrace(PTRACE_GETREGS, tcp->pid, (char *)&regs, 0) < 0) {
1674 perror("clearbpt: ptrace(PTRACE_GETREGS, ...)");
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001675 return -1;
1676 }
Roland McGratheb9e2e82009-06-02 16:49:22 -07001677 if ((regs.r_pc < tcp->baddr) ||
1678 (regs.r_pc > tcp->baddr + 4)) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001679 /* The breakpoint has not been reached yet */
1680 if (debug)
1681 fprintf(stderr,
1682 "NOTE: PC not at bpt (pc %#x baddr %#x)\n",
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001683 regs.r_pc, tcp->baddr);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001684 return 0;
1685 }
1686 if (regs.r_pc != tcp->baddr)
1687 if (debug)
1688 fprintf(stderr, "NOTE: PC adjusted (%#x -> %#x\n",
1689 regs.r_pc, tcp->baddr);
1690
1691 regs.r_pc = tcp->baddr;
Roland McGratheb9e2e82009-06-02 16:49:22 -07001692 if (ptrace(PTRACE_SETREGS, tcp->pid, (char *)&regs, 0) < 0) {
1693 perror("clearbpt: ptrace(PTRACE_SETREGS, ...)");
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001694 return -1;
1695 }
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001696# endif /* LOOPA */
1697# endif /* SPARC */
1698# endif /* SUNOS4 */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001699
1700 return 0;
1701}
1702
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001703# endif /* !defined LINUX */
Roland McGrathd81f1d92003-01-09 06:53:34 +00001704
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001705#endif /* !USE_PROCFS */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001706
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001707
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001708#ifdef SUNOS4
1709
1710static int
Denys Vlasenko12014262011-05-30 14:00:14 +02001711getex(struct tcb *tcp, struct exec *hdr)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001712{
1713 int n;
1714
1715 for (n = 0; n < sizeof *hdr; n += 4) {
1716 long res;
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001717 if (upeek(tcp, uoff(u_exdata) + n, &res) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001718 return -1;
1719 memcpy(((char *) hdr) + n, &res, 4);
1720 }
1721 if (debug) {
1722 fprintf(stderr, "[struct exec: magic: %o version %u Mach %o\n",
1723 hdr->a_magic, hdr->a_toolversion, hdr->a_machtype);
1724 fprintf(stderr, "Text %lu Data %lu Bss %lu Syms %lu Entry %#lx]\n",
1725 hdr->a_text, hdr->a_data, hdr->a_bss, hdr->a_syms, hdr->a_entry);
1726 }
1727 return 0;
1728}
1729
1730int
Denys Vlasenko12014262011-05-30 14:00:14 +02001731fixvfork(struct tcb *tcp)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001732{
1733 int pid = tcp->pid;
1734 /*
1735 * Change `vfork' in a freshly exec'ed dynamically linked
1736 * executable's (internal) symbol table to plain old `fork'
1737 */
1738
1739 struct exec hdr;
1740 struct link_dynamic dyn;
1741 struct link_dynamic_2 ld;
1742 char *strtab, *cp;
1743
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001744 if (getex(tcp, &hdr) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001745 return -1;
1746 if (!hdr.a_dynamic)
1747 return -1;
1748
1749 if (umove(tcp, (int) N_DATADDR(hdr), &dyn) < 0) {
1750 fprintf(stderr, "Cannot read DYNAMIC\n");
1751 return -1;
1752 }
1753 if (umove(tcp, (int) dyn.ld_un.ld_2, &ld) < 0) {
1754 fprintf(stderr, "Cannot read link_dynamic_2\n");
1755 return -1;
1756 }
Denys Vlasenko5d645812011-08-20 12:48:18 +02001757 strtab = malloc((unsigned)ld.ld_symb_size);
Denys Vlasenko1d46ba52011-08-31 14:00:02 +02001758 if (!strtab)
1759 die_out_of_memory();
Roland McGratheb9e2e82009-06-02 16:49:22 -07001760 if (umoven(tcp, (int)ld.ld_symbols+(int)N_TXTADDR(hdr),
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001761 (int)ld.ld_symb_size, strtab) < 0)
1762 goto err;
1763
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001764 for (cp = strtab; cp < strtab + ld.ld_symb_size; ) {
1765 if (strcmp(cp, "_vfork") == 0) {
1766 if (debug)
1767 fprintf(stderr, "fixvfork: FOUND _vfork\n");
1768 strcpy(cp, "_fork");
1769 break;
1770 }
1771 cp += strlen(cp)+1;
1772 }
1773 if (cp < strtab + ld.ld_symb_size)
1774 /*
1775 * Write entire symbol table back to avoid
1776 * memory alignment bugs in ptrace
1777 */
Roland McGratheb9e2e82009-06-02 16:49:22 -07001778 if (tload(pid, (int)ld.ld_symbols+(int)N_TXTADDR(hdr),
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001779 (int)ld.ld_symb_size, strtab) < 0)
1780 goto err;
1781
1782 free(strtab);
1783 return 0;
1784
1785err:
1786 free(strtab);
1787 return -1;
1788}
1789
1790#endif /* SUNOS4 */