blob: 2c21b4939a6ec61d61241e62df5da776096c13e6 [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.
435 */
Roland McGrath6d970322007-11-01 23:53:59 +0000436static int
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000437string_quote(const char *instr, char *outstr, int len, int size)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000438{
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000439 const unsigned char *ustr = (const unsigned char *) instr;
440 char *s = outstr;
Denys Vlasenko8778bff2011-08-31 12:22:56 +0200441 int usehex, c, i, eol;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000442
Denys Vlasenko8778bff2011-08-31 12:22:56 +0200443 eol = 0x100; /* this can never match a char */
444 if (len < 0) {
445 size--;
446 eol = '\0';
447 }
448
449 usehex = 0;
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000450 if (xflag > 1)
451 usehex = 1;
452 else if (xflag) {
Dmitry V. Levina501f142008-11-10 23:19:13 +0000453 /* Check for presence of symbol which require
454 to hex-quote the whole string. */
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000455 for (i = 0; i < size; ++i) {
456 c = ustr[i];
Dmitry V. Levina501f142008-11-10 23:19:13 +0000457 /* Check for NUL-terminated string. */
Denys Vlasenko8778bff2011-08-31 12:22:56 +0200458 if (c == eol)
459 break;
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000460 if (!isprint(c) && !isspace(c)) {
461 usehex = 1;
462 break;
463 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000464 }
465 }
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000466
467 *s++ = '\"';
468
469 if (usehex) {
Dmitry V. Levina501f142008-11-10 23:19:13 +0000470 /* Hex-quote the whole string. */
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000471 for (i = 0; i < size; ++i) {
472 c = ustr[i];
Dmitry V. Levina501f142008-11-10 23:19:13 +0000473 /* Check for NUL-terminated string. */
Denys Vlasenko8778bff2011-08-31 12:22:56 +0200474 if (c == eol)
475 goto asciz_ended;
476 *s++ = '\\';
477 *s++ = 'x';
478 *s++ = "0123456789abcdef"[c >> 4];
479 *s++ = "0123456789abcdef"[c & 0xf];
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000480 }
481 } else {
482 for (i = 0; i < size; ++i) {
483 c = ustr[i];
Dmitry V. Levina501f142008-11-10 23:19:13 +0000484 /* Check for NUL-terminated string. */
Denys Vlasenko8778bff2011-08-31 12:22:56 +0200485 if (c == eol)
486 goto asciz_ended;
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000487 switch (c) {
488 case '\"': case '\\':
489 *s++ = '\\';
490 *s++ = c;
491 break;
492 case '\f':
493 *s++ = '\\';
494 *s++ = 'f';
495 break;
496 case '\n':
497 *s++ = '\\';
498 *s++ = 'n';
499 break;
500 case '\r':
501 *s++ = '\\';
502 *s++ = 'r';
503 break;
504 case '\t':
505 *s++ = '\\';
506 *s++ = 't';
507 break;
508 case '\v':
509 *s++ = '\\';
510 *s++ = 'v';
511 break;
512 default:
513 if (isprint(c))
514 *s++ = c;
Denys Vlasenko8778bff2011-08-31 12:22:56 +0200515 else {
516 /* Print \octal */
517 *s++ = '\\';
518 if (i + 1 < size
519 && ustr[i + 1] >= '0'
520 && ustr[i + 1] <= '9'
521 ) {
522 /* Print \ooo */
523 *s++ = '0' + (c >> 6);
524 *s++ = '0' + ((c >> 3) & 0x7);
525 } else {
526 /* Print \[[o]o]o */
527 if ((c >> 3) != 0) {
528 if ((c >> 6) != 0)
529 *s++ = '0' + (c >> 6);
530 *s++ = '0' + ((c >> 3) & 0x7);
531 }
532 }
533 *s++ = '0' + (c & 0x7);
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000534 }
535 break;
536 }
537 }
538 }
539
540 *s++ = '\"';
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000541 *s = '\0';
Roland McGrath6d970322007-11-01 23:53:59 +0000542
Denys Vlasenko8778bff2011-08-31 12:22:56 +0200543 /* Return zero if we printed entire ASCIZ string (didn't truncate it) */
544 if (len < 0 && ustr[i] == '\0') {
545 /* We didn't see NUL yet (otherwise we'd jump to 'asciz_ended')
546 * but next char is NUL.
547 */
548 return 0;
549 }
550
551 return 1;
552
553 asciz_ended:
554 *s++ = '\"';
555 *s = '\0';
556 /* Return zero: we printed entire ASCIZ string (didn't truncate it) */
557 return 0;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000558}
559
Dmitry V. Levina501f142008-11-10 23:19:13 +0000560/*
561 * Print path string specified by address `addr' and length `n'.
562 * If path length exceeds `n', append `...' to the output.
563 */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000564void
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000565printpathn(struct tcb *tcp, long addr, int n)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000566{
Denys Vlasenkob3c52cf2012-01-19 17:20:23 +0100567 char path[MAXPATHLEN + 1];
568
Dmitry V. Levina501f142008-11-10 23:19:13 +0000569 if (!addr) {
Denys Vlasenko60fe8c12011-09-01 10:00:28 +0200570 tprints("NULL");
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000571 return;
572 }
573
Dmitry V. Levina501f142008-11-10 23:19:13 +0000574 /* Cap path length to the path buffer size,
575 and NUL-terminate the buffer. */
576 if (n > sizeof path - 1)
577 n = sizeof path - 1;
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000578 path[n] = '\0';
Dmitry V. Levina501f142008-11-10 23:19:13 +0000579
580 /* Fetch one byte more to find out whether path length > n. */
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000581 if (umovestr(tcp, addr, n + 1, path) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000582 tprintf("%#lx", addr);
583 else {
Denys Vlasenkob3c52cf2012-01-19 17:20:23 +0100584 char *outstr;
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000585 int trunc = (path[n] != '\0');
586
587 if (trunc)
588 path[n] = '\0';
Denys Vlasenkob3c52cf2012-01-19 17:20:23 +0100589 n++;
590 outstr = alloca(4 * n); /* 4*(n-1) + 2 for quotes */
591 string_quote(path, outstr, -1, n);
592 tprints(outstr);
Dmitry V. Levina501f142008-11-10 23:19:13 +0000593 if (trunc)
Denys Vlasenkob3c52cf2012-01-19 17:20:23 +0100594 tprints("...");
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000595 }
596}
597
598void
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000599printpath(struct tcb *tcp, long addr)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000600{
Denys Vlasenkob3c52cf2012-01-19 17:20:23 +0100601 /* Size must correspond to char path[] size in printpathn */
602 printpathn(tcp, addr, MAXPATHLEN);
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000603}
604
Dmitry V. Levina501f142008-11-10 23:19:13 +0000605/*
606 * Print string specified by address `addr' and length `len'.
607 * If `len' < 0, treat the string as a NUL-terminated string.
608 * If string length exceeds `max_strlen', append `...' to the output.
609 */
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000610void
611printstr(struct tcb *tcp, long addr, int len)
612{
613 static char *str = NULL;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000614 static char *outstr;
Roland McGrath6d970322007-11-01 23:53:59 +0000615 int size;
Denys Vlasenkob3c52cf2012-01-19 17:20:23 +0100616 int ellipsis;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000617
618 if (!addr) {
Denys Vlasenko60fe8c12011-09-01 10:00:28 +0200619 tprints("NULL");
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000620 return;
621 }
Dmitry V. Levina501f142008-11-10 23:19:13 +0000622 /* Allocate static buffers if they are not allocated yet. */
Denys Vlasenko1d46ba52011-08-31 14:00:02 +0200623 if (!str) {
Dmitry V. Levina501f142008-11-10 23:19:13 +0000624 str = malloc(max_strlen + 1);
Denys Vlasenko1d46ba52011-08-31 14:00:02 +0200625 if (!str)
626 die_out_of_memory();
Denys Vlasenkob3c52cf2012-01-19 17:20:23 +0100627 outstr = malloc(4 * max_strlen + /*for quotes:*/ 2);
Denys Vlasenko1d46ba52011-08-31 14:00:02 +0200628 if (!outstr)
629 die_out_of_memory();
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000630 }
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000631
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000632 if (len < 0) {
Dmitry V. Levina501f142008-11-10 23:19:13 +0000633 /*
634 * Treat as a NUL-terminated string: fetch one byte more
635 * because string_quote() quotes one byte less.
636 */
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000637 size = max_strlen + 1;
Dmitry V. Levina501f142008-11-10 23:19:13 +0000638 str[max_strlen] = '\0';
Denys Vlasenko52845572011-08-31 12:07:38 +0200639 /* FIXME! umovestr can overwrite the '\0' stored above??? */
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000640 if (umovestr(tcp, addr, size, str) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000641 tprintf("%#lx", addr);
642 return;
643 }
644 }
645 else {
Dmitry V. Levina501f142008-11-10 23:19:13 +0000646 size = MIN(len, max_strlen);
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000647 if (umoven(tcp, addr, size, str) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000648 tprintf("%#lx", addr);
649 return;
650 }
651 }
652
Denys Vlasenkob3c52cf2012-01-19 17:20:23 +0100653 ellipsis = (string_quote(str, outstr, len, size) &&
654 (len < 0 || len > max_strlen));
Roland McGratha503dcf2007-08-02 02:06:26 +0000655
Denys Vlasenkob3c52cf2012-01-19 17:20:23 +0100656 tprints(outstr);
657 if (ellipsis)
658 tprints("...");
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000659}
660
John Hughes1d08dcf2001-07-10 13:48:44 +0000661#if HAVE_SYS_UIO_H
662void
Denys Vlasenko12014262011-05-30 14:00:14 +0200663dumpiov(struct tcb *tcp, int len, long addr)
John Hughes1d08dcf2001-07-10 13:48:44 +0000664{
Dmitry V. Levin4ebb4e32006-12-13 17:08:08 +0000665#if defined(LINUX) && SUPPORTED_PERSONALITIES > 1
666 union {
667 struct { u_int32_t base; u_int32_t len; } *iov32;
668 struct { u_int64_t base; u_int64_t len; } *iov64;
669 } iovu;
670#define iov iovu.iov64
671#define sizeof_iov \
672 (personality_wordsize[current_personality] == 4 \
673 ? sizeof(*iovu.iov32) : sizeof(*iovu.iov64))
674#define iov_iov_base(i) \
675 (personality_wordsize[current_personality] == 4 \
676 ? (u_int64_t) iovu.iov32[i].base : iovu.iov64[i].base)
677#define iov_iov_len(i) \
678 (personality_wordsize[current_personality] == 4 \
679 ? (u_int64_t) iovu.iov32[i].len : iovu.iov64[i].len)
680#else
John Hughes1d08dcf2001-07-10 13:48:44 +0000681 struct iovec *iov;
Dmitry V. Levin4ebb4e32006-12-13 17:08:08 +0000682#define sizeof_iov sizeof(*iov)
683#define iov_iov_base(i) iov[i].iov_base
684#define iov_iov_len(i) iov[i].iov_len
685#endif
John Hughes1d08dcf2001-07-10 13:48:44 +0000686 int i;
Denys Vlasenko79a79ea2011-09-01 16:35:44 +0200687 unsigned size;
John Hughes1d08dcf2001-07-10 13:48:44 +0000688
Denys Vlasenko79a79ea2011-09-01 16:35:44 +0200689 size = sizeof_iov * len;
690 /* Assuming no sane program has millions of iovs */
691 if ((unsigned)len > 1024*1024 /* insane or negative size? */
Dmitry V. Levin4ebb4e32006-12-13 17:08:08 +0000692 || (iov = malloc(size)) == NULL) {
Denys Vlasenko79a79ea2011-09-01 16:35:44 +0200693 fprintf(stderr, "Out of memory\n");
694 return;
John Hughes1d08dcf2001-07-10 13:48:44 +0000695 }
Roland McGrathaa524c82005-06-01 19:22:06 +0000696 if (umoven(tcp, addr, size, (char *) iov) >= 0) {
John Hughes1d08dcf2001-07-10 13:48:44 +0000697 for (i = 0; i < len; i++) {
Denys Vlasenkoadedb512008-12-30 18:47:55 +0000698 /* include the buffer number to make it easy to
699 * match up the trace with the source */
700 tprintf(" * %lu bytes in buffer %d\n",
701 (unsigned long)iov_iov_len(i), i);
702 dumpstr(tcp, (long) iov_iov_base(i),
703 iov_iov_len(i));
704 }
John Hughes1d08dcf2001-07-10 13:48:44 +0000705 }
Denys Vlasenko79a79ea2011-09-01 16:35:44 +0200706 free(iov);
Dmitry V. Levin4ebb4e32006-12-13 17:08:08 +0000707#undef sizeof_iov
708#undef iov_iov_base
709#undef iov_iov_len
710#undef iov
John Hughes1d08dcf2001-07-10 13:48:44 +0000711}
712#endif
713
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000714void
Denys Vlasenko12014262011-05-30 14:00:14 +0200715dumpstr(struct tcb *tcp, long addr, int len)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000716{
717 static int strsize = -1;
718 static unsigned char *str;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000719 char *s;
720 int i, j;
721
722 if (strsize < len) {
Denys Vlasenko5d645812011-08-20 12:48:18 +0200723 free(str);
724 str = malloc(len);
Denys Vlasenko79a79ea2011-09-01 16:35:44 +0200725 if (!str) {
726 strsize = -1;
727 fprintf(stderr, "Out of memory\n");
728 return;
729 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000730 strsize = len;
731 }
732
733 if (umoven(tcp, addr, len, (char *) str) < 0)
734 return;
735
736 for (i = 0; i < len; i += 16) {
Denys Vlasenko1d46ba52011-08-31 14:00:02 +0200737 char outstr[80];
738
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000739 s = outstr;
740 sprintf(s, " | %05x ", i);
741 s += 9;
742 for (j = 0; j < 16; j++) {
743 if (j == 8)
744 *s++ = ' ';
745 if (i + j < len) {
746 sprintf(s, " %02x", str[i + j]);
747 s += 3;
748 }
749 else {
750 *s++ = ' '; *s++ = ' '; *s++ = ' ';
751 }
752 }
753 *s++ = ' '; *s++ = ' ';
754 for (j = 0; j < 16; j++) {
755 if (j == 8)
756 *s++ = ' ';
757 if (i + j < len) {
758 if (isprint(str[i + j]))
759 *s++ = str[i + j];
760 else
761 *s++ = '.';
762 }
763 else
764 *s++ = ' ';
765 }
766 tprintf("%s |\n", outstr);
767 }
768}
769
770#define PAGMASK (~(PAGSIZ - 1))
771/*
772 * move `len' bytes of data from process `pid'
773 * at address `addr' to our space at `laddr'
774 */
775int
Denys Vlasenkoef2fbf82009-01-06 21:45:06 +0000776umoven(struct tcb *tcp, long addr, int len, char *laddr)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000777{
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000778#ifdef LINUX
Roland McGratheb9e2e82009-06-02 16:49:22 -0700779 int pid = tcp->pid;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000780 int n, m;
Wichert Akkerman5daa0281999-03-15 19:49:42 +0000781 int started = 0;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000782 union {
783 long val;
784 char x[sizeof(long)];
785 } u;
786
Dmitry V. Levin856c7ed2011-12-26 20:12:02 +0000787#if SUPPORTED_PERSONALITIES > 1
788 if (personality_wordsize[current_personality] < sizeof(addr))
789 addr &= (1ul << 8 * personality_wordsize[current_personality]) - 1;
790#endif
791
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000792 if (addr & (sizeof(long) - 1)) {
793 /* addr not a multiple of sizeof(long) */
794 n = addr - (addr & -sizeof(long)); /* residue */
795 addr &= -sizeof(long); /* residue */
Roland McGratheb9e2e82009-06-02 16:49:22 -0700796 errno = 0;
797 u.val = ptrace(PTRACE_PEEKDATA, pid, (char *) addr, 0);
798 if (errno) {
Roland McGratheb9e2e82009-06-02 16:49:22 -0700799 /* But if not started, we had a bogus address. */
800 if (addr != 0 && errno != EIO && errno != ESRCH)
801 perror("ptrace: umoven");
802 return -1;
803 }
Wichert Akkerman5daa0281999-03-15 19:49:42 +0000804 started = 1;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000805 memcpy(laddr, &u.x[n], m = MIN(sizeof(long) - n, len));
806 addr += sizeof(long), laddr += m, len -= m;
807 }
808 while (len) {
Roland McGratheb9e2e82009-06-02 16:49:22 -0700809 errno = 0;
810 u.val = ptrace(PTRACE_PEEKDATA, pid, (char *) addr, 0);
811 if (errno) {
812 if (started && (errno==EPERM || errno==EIO)) {
813 /* Ran into 'end of memory' - stupid "printpath" */
814 return 0;
815 }
816 if (addr != 0 && errno != EIO && errno != ESRCH)
817 perror("ptrace: umoven");
818 return -1;
819 }
Wichert Akkerman5daa0281999-03-15 19:49:42 +0000820 started = 1;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000821 memcpy(laddr, u.x, m = MIN(sizeof(long), len));
822 addr += sizeof(long), laddr += m, len -= m;
823 }
824#endif /* LINUX */
825
826#ifdef SUNOS4
827 int pid = tcp->pid;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000828 int n;
829
830 while (len) {
831 n = MIN(len, PAGSIZ);
832 n = MIN(n, ((addr + PAGSIZ) & PAGMASK) - addr);
Roland McGratheb9e2e82009-06-02 16:49:22 -0700833 if (ptrace(PTRACE_READDATA, pid,
834 (char *) addr, len, laddr) < 0) {
835 if (errno != ESRCH) {
836 perror("umoven: ptrace(PTRACE_READDATA, ...)");
837 abort();
838 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000839 return -1;
840 }
841 len -= n;
842 addr += n;
843 laddr += n;
844 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000845#endif /* SUNOS4 */
846
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000847#ifdef USE_PROCFS
Wichert Akkermanea78f0f1999-11-29 15:34:02 +0000848#ifdef HAVE_MP_PROCFS
John Hughesaa09c6b2001-05-15 14:53:43 +0000849 int fd = tcp->pfd_as;
Wichert Akkerman9ce1a631999-08-29 23:15:07 +0000850#else
John Hughesaa09c6b2001-05-15 14:53:43 +0000851 int fd = tcp->pfd;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000852#endif
John Hughesaa09c6b2001-05-15 14:53:43 +0000853 lseek(fd, addr, SEEK_SET);
854 if (read(fd, laddr, len) == -1)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000855 return -1;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000856#endif /* USE_PROCFS */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000857
858 return 0;
859}
860
861/*
862 * like `umove' but make the additional effort of looking
863 * for a terminating zero byte.
864 */
865int
Denys Vlasenkoef2fbf82009-01-06 21:45:06 +0000866umovestr(struct tcb *tcp, long addr, int len, char *laddr)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000867{
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000868#ifdef USE_PROCFS
John Hughesaa09c6b2001-05-15 14:53:43 +0000869#ifdef HAVE_MP_PROCFS
870 int fd = tcp->pfd_as;
871#else
872 int fd = tcp->pfd;
873#endif
874 /* Some systems (e.g. FreeBSD) can be upset if we read off the
875 end of valid memory, avoid this by trying to read up
876 to page boundaries. But we don't know what a page is (and
877 getpagesize(2) (if it exists) doesn't necessarily return
878 hardware page size). Assume all pages >= 1024 (a-historical
879 I know) */
880
Denys Vlasenkob63256e2011-06-07 12:13:24 +0200881 int page = 1024; /* How to find this? */
John Hughesaa09c6b2001-05-15 14:53:43 +0000882 int move = page - (addr & (page - 1));
883 int left = len;
884
885 lseek(fd, addr, SEEK_SET);
886
887 while (left) {
Denys Vlasenko5d645812011-08-20 12:48:18 +0200888 if (move > left)
889 move = left;
890 move = read(fd, laddr, move);
891 if (move <= 0)
John Hughesaa09c6b2001-05-15 14:53:43 +0000892 return left != len ? 0 : -1;
Denys Vlasenko5d645812011-08-20 12:48:18 +0200893 if (memchr(laddr, 0, move))
894 break;
John Hughesaa09c6b2001-05-15 14:53:43 +0000895 left -= move;
896 laddr += move;
897 addr += move;
898 move = page;
899 }
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000900#else /* !USE_PROCFS */
Wichert Akkerman5daa0281999-03-15 19:49:42 +0000901 int started = 0;
Roland McGratheb9e2e82009-06-02 16:49:22 -0700902 int pid = tcp->pid;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000903 int i, n, m;
904 union {
905 long val;
906 char x[sizeof(long)];
907 } u;
908
Dmitry V. Levin856c7ed2011-12-26 20:12:02 +0000909#if SUPPORTED_PERSONALITIES > 1
910 if (personality_wordsize[current_personality] < sizeof(addr))
911 addr &= (1ul << 8 * personality_wordsize[current_personality]) - 1;
912#endif
913
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000914 if (addr & (sizeof(long) - 1)) {
915 /* addr not a multiple of sizeof(long) */
916 n = addr - (addr & -sizeof(long)); /* residue */
917 addr &= -sizeof(long); /* residue */
Roland McGratheb9e2e82009-06-02 16:49:22 -0700918 errno = 0;
919 u.val = ptrace(PTRACE_PEEKDATA, pid, (char *)addr, 0);
920 if (errno) {
Roland McGratheb9e2e82009-06-02 16:49:22 -0700921 if (addr != 0 && errno != EIO && errno != ESRCH)
922 perror("umovestr");
923 return -1;
924 }
Wichert Akkerman5daa0281999-03-15 19:49:42 +0000925 started = 1;
Denys Vlasenkob63256e2011-06-07 12:13:24 +0200926 memcpy(laddr, &u.x[n], m = MIN(sizeof(long)-n, len));
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000927 while (n & (sizeof(long) - 1))
928 if (u.x[n++] == '\0')
929 return 0;
930 addr += sizeof(long), laddr += m, len -= m;
931 }
932 while (len) {
Roland McGratheb9e2e82009-06-02 16:49:22 -0700933 errno = 0;
934 u.val = ptrace(PTRACE_PEEKDATA, pid, (char *)addr, 0);
935 if (errno) {
936 if (started && (errno==EPERM || errno==EIO)) {
937 /* Ran into 'end of memory' - stupid "printpath" */
938 return 0;
939 }
940 if (addr != 0 && errno != EIO && errno != ESRCH)
941 perror("umovestr");
942 return -1;
943 }
Wichert Akkerman5daa0281999-03-15 19:49:42 +0000944 started = 1;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000945 memcpy(laddr, u.x, m = MIN(sizeof(long), len));
946 for (i = 0; i < sizeof(long); i++)
947 if (u.x[i] == '\0')
948 return 0;
949
950 addr += sizeof(long), laddr += m, len -= m;
951 }
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000952#endif /* !USE_PROCFS */
John Hughesaa09c6b2001-05-15 14:53:43 +0000953 return 0;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000954}
955
956#ifdef LINUX
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +0000957# if !defined (SPARC) && !defined(SPARC64)
958# define PTRACE_WRITETEXT 101
959# define PTRACE_WRITEDATA 102
960# endif /* !SPARC && !SPARC64 */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000961#endif /* LINUX */
962
963#ifdef SUNOS4
964
965static int
Denys Vlasenko12014262011-05-30 14:00:14 +0200966uload(int cmd, int pid, long addr, int len, char *laddr)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000967{
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000968 int peek, poke;
969 int n, m;
970 union {
971 long val;
972 char x[sizeof(long)];
973 } u;
974
975 if (cmd == PTRACE_WRITETEXT) {
976 peek = PTRACE_PEEKTEXT;
977 poke = PTRACE_POKETEXT;
978 }
979 else {
980 peek = PTRACE_PEEKDATA;
981 poke = PTRACE_POKEDATA;
982 }
983 if (addr & (sizeof(long) - 1)) {
984 /* addr not a multiple of sizeof(long) */
985 n = addr - (addr & -sizeof(long)); /* residue */
986 addr &= -sizeof(long);
Roland McGratheb9e2e82009-06-02 16:49:22 -0700987 errno = 0;
988 u.val = ptrace(peek, pid, (char *) addr, 0);
989 if (errno) {
990 perror("uload: POKE");
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000991 return -1;
992 }
Roland McGratheb9e2e82009-06-02 16:49:22 -0700993 memcpy(&u.x[n], laddr, m = MIN(sizeof(long) - n, len));
994 if (ptrace(poke, pid, (char *)addr, u.val) < 0) {
995 perror("uload: POKE");
996 return -1;
997 }
998 addr += sizeof(long), laddr += m, len -= m;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000999 }
1000 while (len) {
1001 if (len < sizeof(long))
Roland McGratheb9e2e82009-06-02 16:49:22 -07001002 u.val = ptrace(peek, pid, (char *) addr, 0);
1003 memcpy(u.x, laddr, m = MIN(sizeof(long), len));
1004 if (ptrace(poke, pid, (char *) addr, u.val) < 0) {
1005 perror("uload: POKE");
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001006 return -1;
1007 }
Roland McGratheb9e2e82009-06-02 16:49:22 -07001008 addr += sizeof(long), laddr += m, len -= m;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001009 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001010 return 0;
1011}
1012
Roland McGratheb9e2e82009-06-02 16:49:22 -07001013int
Denys Vlasenko12014262011-05-30 14:00:14 +02001014tload(int pid, int addr, int len, char *laddr)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001015{
Roland McGratheb9e2e82009-06-02 16:49:22 -07001016 return uload(PTRACE_WRITETEXT, pid, addr, len, laddr);
1017}
1018
1019int
Denys Vlasenko12014262011-05-30 14:00:14 +02001020dload(int pid, int addr, int len, char *laddr)
Roland McGratheb9e2e82009-06-02 16:49:22 -07001021{
1022 return uload(PTRACE_WRITEDATA, pid, addr, len, laddr);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001023}
1024
1025#endif /* SUNOS4 */
1026
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001027#ifndef USE_PROCFS
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001028
1029int
Denys Vlasenko12014262011-05-30 14:00:14 +02001030upeek(struct tcb *tcp, long off, long *res)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001031{
1032 long val;
1033
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001034# ifdef SUNOS4_KERNEL_ARCH_KLUDGE
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001035 {
1036 static int is_sun4m = -1;
1037 struct utsname name;
1038
1039 /* Round up the usual suspects. */
1040 if (is_sun4m == -1) {
1041 if (uname(&name) < 0) {
1042 perror("upeek: uname?");
1043 exit(1);
1044 }
1045 is_sun4m = strcmp(name.machine, "sun4m") == 0;
1046 if (is_sun4m) {
Roland McGrathd9f816f2004-09-04 03:39:20 +00001047 const struct xlat *x;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001048
1049 for (x = struct_user_offsets; x->str; x++)
1050 x->val += 1024;
1051 }
1052 }
1053 if (is_sun4m)
1054 off += 1024;
1055 }
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001056# endif /* SUNOS4_KERNEL_ARCH_KLUDGE */
Roland McGratheb9e2e82009-06-02 16:49:22 -07001057 errno = 0;
Denys Vlasenko732d1bf2008-12-17 19:21:59 +00001058 val = do_ptrace(PTRACE_PEEKUSER, tcp, (char *) off, 0);
Roland McGratheb9e2e82009-06-02 16:49:22 -07001059 if (val == -1 && errno) {
1060 if (errno != ESRCH) {
1061 char buf[60];
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001062 sprintf(buf, "upeek: ptrace(PTRACE_PEEKUSER,%d,%lu,0)", tcp->pid, off);
Roland McGratheb9e2e82009-06-02 16:49:22 -07001063 perror(buf);
1064 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001065 return -1;
Roland McGratheb9e2e82009-06-02 16:49:22 -07001066 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001067 *res = val;
1068 return 0;
1069}
1070
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001071#endif /* !USE_PROCFS */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001072
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001073void
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001074printcall(struct tcb *tcp)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001075{
Roland McGrath7a918832005-02-02 20:55:23 +00001076#define PRINTBADPC tprintf(sizeof(long) == 4 ? "[????????] " : \
1077 sizeof(long) == 8 ? "[????????????????] " : \
1078 NULL /* crash */)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001079
1080#ifdef LINUX
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001081# ifdef I386
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001082 long eip;
1083
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001084 if (upeek(tcp, 4*EIP, &eip) < 0) {
Roland McGrath7a918832005-02-02 20:55:23 +00001085 PRINTBADPC;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001086 return;
1087 }
1088 tprintf("[%08lx] ", eip);
Roland McGratheac26fc2005-02-02 02:48:53 +00001089
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001090# elif defined(S390) || defined(S390X)
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001091 long psw;
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001092 if (upeek(tcp, PT_PSWADDR, &psw) < 0) {
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001093 PRINTBADPC;
1094 return;
1095 }
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001096# ifdef S390
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001097 tprintf("[%08lx] ", psw);
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001098# elif S390X
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001099 tprintf("[%16lx] ", psw);
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001100# endif
Roland McGratheac26fc2005-02-02 02:48:53 +00001101
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001102# elif defined(X86_64)
Michal Ludvig0e035502002-09-23 15:41:01 +00001103 long rip;
1104
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001105 if (upeek(tcp, 8*RIP, &rip) < 0) {
Roland McGrath7a918832005-02-02 20:55:23 +00001106 PRINTBADPC;
Michal Ludvig0e035502002-09-23 15:41:01 +00001107 return;
1108 }
1109 tprintf("[%16lx] ", rip);
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001110# elif defined(IA64)
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00001111 long ip;
1112
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001113 if (upeek(tcp, PT_B0, &ip) < 0) {
Roland McGrath7a918832005-02-02 20:55:23 +00001114 PRINTBADPC;
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00001115 return;
1116 }
1117 tprintf("[%08lx] ", ip);
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001118# elif defined(POWERPC)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001119 long pc;
1120
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001121 if (upeek(tcp, sizeof(unsigned long)*PT_NIP, &pc) < 0) {
Andreas Schwabd69fa492010-07-12 21:39:57 +02001122 PRINTBADPC;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001123 return;
1124 }
Andreas Schwabd69fa492010-07-12 21:39:57 +02001125# ifdef POWERPC64
1126 tprintf("[%016lx] ", pc);
1127# else
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001128 tprintf("[%08lx] ", pc);
Andreas Schwabd69fa492010-07-12 21:39:57 +02001129# endif
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001130# elif defined(M68K)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001131 long pc;
1132
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001133 if (upeek(tcp, 4*PT_PC, &pc) < 0) {
Denys Vlasenko60fe8c12011-09-01 10:00:28 +02001134 tprints("[????????] ");
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001135 return;
1136 }
1137 tprintf("[%08lx] ", pc);
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001138# elif defined(ALPHA)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001139 long pc;
1140
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001141 if (upeek(tcp, REG_PC, &pc) < 0) {
Denys Vlasenko60fe8c12011-09-01 10:00:28 +02001142 tprints("[????????????????] ");
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001143 return;
1144 }
1145 tprintf("[%08lx] ", pc);
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001146# elif defined(SPARC) || defined(SPARC64)
Mike Frysinger8566c502009-10-12 11:05:14 -04001147 struct pt_regs regs;
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001148 if (ptrace(PTRACE_GETREGS, tcp->pid, (char *)&regs, 0) < 0) {
Roland McGrath7a918832005-02-02 20:55:23 +00001149 PRINTBADPC;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001150 return;
1151 }
Mike Frysinger8566c502009-10-12 11:05:14 -04001152# if defined(SPARC64)
1153 tprintf("[%08lx] ", regs.tpc);
1154# else
1155 tprintf("[%08lx] ", regs.pc);
1156# endif
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001157# elif defined(HPPA)
Wichert Akkermanc1652e22001-03-27 12:17:16 +00001158 long pc;
1159
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001160 if (upeek(tcp, PT_IAOQ0, &pc) < 0) {
Denys Vlasenko60fe8c12011-09-01 10:00:28 +02001161 tprints("[????????] ");
Wichert Akkermanc1652e22001-03-27 12:17:16 +00001162 return;
1163 }
1164 tprintf("[%08lx] ", pc);
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001165# elif defined(MIPS)
Wichert Akkerman75c422b2001-04-10 10:22:50 +00001166 long pc;
1167
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001168 if (upeek(tcp, REG_EPC, &pc) < 0) {
Denys Vlasenko60fe8c12011-09-01 10:00:28 +02001169 tprints("[????????] ");
Wichert Akkerman75c422b2001-04-10 10:22:50 +00001170 return;
1171 }
1172 tprintf("[%08lx] ", pc);
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001173# elif defined(SH)
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001174 long pc;
Wichert Akkermanccef6372002-05-01 16:39:22 +00001175
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001176 if (upeek(tcp, 4*REG_PC, &pc) < 0) {
Denys Vlasenko60fe8c12011-09-01 10:00:28 +02001177 tprints("[????????] ");
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001178 return;
1179 }
1180 tprintf("[%08lx] ", pc);
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001181# elif defined(SH64)
Roland McGrathe1e584b2003-06-02 19:18:58 +00001182 long pc;
1183
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001184 if (upeek(tcp, REG_PC, &pc) < 0) {
Denys Vlasenko60fe8c12011-09-01 10:00:28 +02001185 tprints("[????????????????] ");
Roland McGrathe1e584b2003-06-02 19:18:58 +00001186 return;
1187 }
1188 tprintf("[%08lx] ", pc);
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001189# elif defined(ARM)
Roland McGrathef388682003-06-03 23:28:59 +00001190 long pc;
Roland McGrathe1e584b2003-06-02 19:18:58 +00001191
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001192 if (upeek(tcp, 4*15, &pc) < 0) {
Roland McGrath7a918832005-02-02 20:55:23 +00001193 PRINTBADPC;
Roland McGrathef388682003-06-03 23:28:59 +00001194 return;
1195 }
1196 tprintf("[%08lx] ", pc);
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00001197# elif defined(AVR32)
1198 long pc;
1199
1200 if (upeek(tcp, REG_PC, &pc) < 0) {
Denys Vlasenko60fe8c12011-09-01 10:00:28 +02001201 tprints("[????????] ");
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00001202 return;
1203 }
1204 tprintf("[%08lx] ", pc);
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001205# elif defined(BFIN)
Dmitry V. Levin87ea1f42008-11-10 22:21:41 +00001206 long pc;
1207
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001208 if (upeek(tcp, PT_PC, &pc) < 0) {
Dmitry V. Levin87ea1f42008-11-10 22:21:41 +00001209 PRINTBADPC;
1210 return;
1211 }
1212 tprintf("[%08lx] ", pc);
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001213#elif defined(CRISV10)
1214 long pc;
1215
Edgar E. Iglesiaseeb9ce32009-10-05 14:41:02 +00001216 if (upeek(tcp, 4*PT_IRP, &pc) < 0) {
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001217 PRINTBADPC;
1218 return;
1219 }
1220 tprintf("[%08lx] ", pc);
1221#elif defined(CRISV32)
1222 long pc;
1223
Edgar E. Iglesiaseeb9ce32009-10-05 14:41:02 +00001224 if (upeek(tcp, 4*PT_ERP, &pc) < 0) {
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001225 PRINTBADPC;
1226 return;
1227 }
1228 tprintf("[%08lx] ", pc);
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001229# endif /* architecture */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001230#endif /* LINUX */
1231
1232#ifdef SUNOS4
1233 struct regs regs;
1234
Roland McGratheb9e2e82009-06-02 16:49:22 -07001235 if (ptrace(PTRACE_GETREGS, tcp->pid, (char *) &regs, 0) < 0) {
1236 perror("printcall: ptrace(PTRACE_GETREGS, ...)");
Roland McGrath7a918832005-02-02 20:55:23 +00001237 PRINTBADPC;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001238 return;
1239 }
1240 tprintf("[%08x] ", regs.r_o7);
1241#endif /* SUNOS4 */
1242
1243#ifdef SVR4
1244 /* XXX */
Roland McGrath7a918832005-02-02 20:55:23 +00001245 PRINTBADPC;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001246#endif
1247
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001248#ifdef FREEBSD
1249 struct reg regs;
1250 pread(tcp->pfd_reg, &regs, sizeof(regs), 0);
1251 tprintf("[%08x] ", regs.r_eip);
1252#endif /* FREEBSD */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001253}
1254
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001255
1256/*
1257 * These #if's are huge, please indent them correctly.
1258 * It's easy to get confused otherwise.
1259 */
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001260#ifndef USE_PROCFS
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001261
Denys Vlasenkoe7c90242011-06-22 00:09:25 +02001262# ifdef LINUX
Roland McGrathd81f1d92003-01-09 06:53:34 +00001263
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001264# include "syscall.h"
Roland McGrath3291ef22008-05-20 00:34:34 +00001265
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001266# include <sys/syscall.h>
1267# ifndef CLONE_PTRACE
1268# define CLONE_PTRACE 0x00002000
1269# endif
1270# ifndef CLONE_VFORK
1271# define CLONE_VFORK 0x00004000
1272# endif
1273# ifndef CLONE_VM
1274# define CLONE_VM 0x00000100
1275# endif
1276# ifndef CLONE_STOPPED
1277# define CLONE_STOPPED 0x02000000
1278# endif
Roland McGrathd81f1d92003-01-09 06:53:34 +00001279
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001280# ifdef IA64
Roland McGrathd81f1d92003-01-09 06:53:34 +00001281
Roland McGrath08267b82004-02-20 22:56:43 +00001282/* We don't have fork()/vfork() syscalls on ia64 itself, but the ia32
1283 subsystem has them for x86... */
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001284# define SYS_fork 2
1285# define SYS_vfork 190
Roland McGrath08267b82004-02-20 22:56:43 +00001286
Roland McGrathd81f1d92003-01-09 06:53:34 +00001287typedef unsigned long *arg_setup_state;
1288
1289static int
1290arg_setup(struct tcb *tcp, arg_setup_state *state)
1291{
Jan Kratochvil1f942712008-08-06 21:38:52 +00001292 unsigned long cfm, sof, sol;
1293 long bsp;
Roland McGrathd81f1d92003-01-09 06:53:34 +00001294
Jan Kratochvil1f942712008-08-06 21:38:52 +00001295 if (ia32) {
1296 /* Satisfy a false GCC warning. */
1297 *state = NULL;
Roland McGrath08267b82004-02-20 22:56:43 +00001298 return 0;
Jan Kratochvil1f942712008-08-06 21:38:52 +00001299 }
Roland McGrath08267b82004-02-20 22:56:43 +00001300
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001301 if (upeek(tcp, PT_AR_BSP, &bsp) < 0)
Roland McGrathd81f1d92003-01-09 06:53:34 +00001302 return -1;
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001303 if (upeek(tcp, PT_CFM, (long *) &cfm) < 0)
Roland McGrathd81f1d92003-01-09 06:53:34 +00001304 return -1;
1305
1306 sof = (cfm >> 0) & 0x7f;
1307 sol = (cfm >> 7) & 0x7f;
Jan Kratochvil1f942712008-08-06 21:38:52 +00001308 bsp = (long) ia64_rse_skip_regs((unsigned long *) bsp, -sof + sol);
Roland McGrathd81f1d92003-01-09 06:53:34 +00001309
Jan Kratochvil1f942712008-08-06 21:38:52 +00001310 *state = (unsigned long *) bsp;
Roland McGrathd81f1d92003-01-09 06:53:34 +00001311 return 0;
1312}
1313
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001314# define arg_finish_change(tcp, state) 0
Roland McGrathd81f1d92003-01-09 06:53:34 +00001315
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001316# ifdef SYS_fork
Roland McGrathd81f1d92003-01-09 06:53:34 +00001317static int
Denys Vlasenko12014262011-05-30 14:00:14 +02001318get_arg0(struct tcb *tcp, arg_setup_state *state, long *valp)
Roland McGrathd81f1d92003-01-09 06:53:34 +00001319{
Roland McGrath08267b82004-02-20 22:56:43 +00001320 int ret;
1321
1322 if (ia32)
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001323 ret = upeek(tcp, PT_R11, valp);
Roland McGrath08267b82004-02-20 22:56:43 +00001324 else
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001325 ret = umoven(tcp,
Roland McGrath08267b82004-02-20 22:56:43 +00001326 (unsigned long) ia64_rse_skip_regs(*state, 0),
1327 sizeof(long), (void *) valp);
1328 return ret;
Roland McGrathd81f1d92003-01-09 06:53:34 +00001329}
1330
1331static int
Denys Vlasenko12014262011-05-30 14:00:14 +02001332get_arg1(struct tcb *tcp, arg_setup_state *state, long *valp)
Roland McGrathd81f1d92003-01-09 06:53:34 +00001333{
Roland McGrath08267b82004-02-20 22:56:43 +00001334 int ret;
1335
1336 if (ia32)
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001337 ret = upeek(tcp, PT_R9, valp);
Roland McGrath08267b82004-02-20 22:56:43 +00001338 else
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001339 ret = umoven(tcp,
Roland McGrath08267b82004-02-20 22:56:43 +00001340 (unsigned long) ia64_rse_skip_regs(*state, 1),
1341 sizeof(long), (void *) valp);
1342 return ret;
Roland McGrathd81f1d92003-01-09 06:53:34 +00001343}
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001344# endif
Roland McGrathd81f1d92003-01-09 06:53:34 +00001345
1346static int
Denys Vlasenko12014262011-05-30 14:00:14 +02001347set_arg0(struct tcb *tcp, arg_setup_state *state, long val)
Roland McGrathd81f1d92003-01-09 06:53:34 +00001348{
Roland McGrath08267b82004-02-20 22:56:43 +00001349 int req = PTRACE_POKEDATA;
1350 void *ap;
1351
1352 if (ia32) {
1353 ap = (void *) (intptr_t) PT_R11; /* r11 == EBX */
1354 req = PTRACE_POKEUSER;
1355 } else
1356 ap = ia64_rse_skip_regs(*state, 0);
Roland McGratheb9e2e82009-06-02 16:49:22 -07001357 errno = 0;
1358 ptrace(req, tcp->pid, ap, val);
1359 return errno ? -1 : 0;
Roland McGrathd81f1d92003-01-09 06:53:34 +00001360}
1361
1362static int
Denys Vlasenko12014262011-05-30 14:00:14 +02001363set_arg1(struct tcb *tcp, arg_setup_state *state, long val)
Roland McGrathd81f1d92003-01-09 06:53:34 +00001364{
Roland McGrath08267b82004-02-20 22:56:43 +00001365 int req = PTRACE_POKEDATA;
1366 void *ap;
1367
1368 if (ia32) {
1369 ap = (void *) (intptr_t) PT_R9; /* r9 == ECX */
1370 req = PTRACE_POKEUSER;
1371 } else
1372 ap = ia64_rse_skip_regs(*state, 1);
Roland McGratheb9e2e82009-06-02 16:49:22 -07001373 errno = 0;
1374 ptrace(req, tcp->pid, ap, val);
1375 return errno ? -1 : 0;
Roland McGrathd81f1d92003-01-09 06:53:34 +00001376}
1377
Roland McGrathb659f872008-07-18 01:19:36 +00001378/* ia64 does not return the input arguments from functions (and syscalls)
1379 according to ia64 RSE (Register Stack Engine) behavior. */
1380
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001381# define restore_arg0(tcp, state, val) ((void) (state), 0)
1382# define restore_arg1(tcp, state, val) ((void) (state), 0)
Roland McGrathb659f872008-07-18 01:19:36 +00001383
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001384# elif defined (SPARC) || defined (SPARC64)
Roland McGrathd81f1d92003-01-09 06:53:34 +00001385
Mike Frysinger8566c502009-10-12 11:05:14 -04001386typedef struct pt_regs arg_setup_state;
Roland McGrathd81f1d92003-01-09 06:53:34 +00001387
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001388# define arg_setup(tcp, state) \
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001389 (ptrace(PTRACE_GETREGS, tcp->pid, (char *) (state), 0))
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001390# define arg_finish_change(tcp, state) \
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001391 (ptrace(PTRACE_SETREGS, tcp->pid, (char *) (state), 0))
Roland McGrathd81f1d92003-01-09 06:53:34 +00001392
Mike Frysinger8566c502009-10-12 11:05:14 -04001393# define get_arg0(tcp, state, valp) (*(valp) = (state)->u_regs[U_REG_O0], 0)
1394# define get_arg1(tcp, state, valp) (*(valp) = (state)->u_regs[U_REG_O1], 0)
1395# define set_arg0(tcp, state, val) ((state)->u_regs[U_REG_O0] = (val), 0)
1396# define set_arg1(tcp, state, val) ((state)->u_regs[U_REG_O1] = (val), 0)
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001397# define restore_arg0(tcp, state, val) 0
Roland McGrathd81f1d92003-01-09 06:53:34 +00001398
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001399# else /* other architectures */
Roland McGrathd81f1d92003-01-09 06:53:34 +00001400
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001401# if defined S390 || defined S390X
Roland McGrath7b308222003-01-20 09:04:36 +00001402/* Note: this is only true for the `clone' system call, which handles
1403 arguments specially. We could as well say that its first two arguments
1404 are swapped relative to other architectures, but that would just be
1405 another #ifdef in the calls. */
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001406# define arg0_offset PT_GPR3
1407# define arg1_offset PT_ORIGGPR2
1408# define restore_arg0(tcp, state, val) ((void) (state), 0)
1409# define restore_arg1(tcp, state, val) ((void) (state), 0)
1410# define arg0_index 1
1411# define arg1_index 0
1412# elif defined (ALPHA) || defined (MIPS)
1413# define arg0_offset REG_A0
1414# define arg1_offset (REG_A0+1)
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00001415# elif defined (AVR32)
1416# define arg0_offset (REG_R12)
1417# define arg1_offset (REG_R11)
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001418# elif defined (POWERPC)
1419# define arg0_offset (sizeof(unsigned long)*PT_R3)
1420# define arg1_offset (sizeof(unsigned long)*PT_R4)
1421# define restore_arg0(tcp, state, val) ((void) (state), 0)
1422# elif defined (HPPA)
1423# define arg0_offset PT_GR26
1424# define arg1_offset (PT_GR26-4)
1425# elif defined (X86_64)
1426# define arg0_offset ((long)(8*(current_personality ? RBX : RDI)))
1427# define arg1_offset ((long)(8*(current_personality ? RCX : RSI)))
1428# elif defined (SH)
1429# define arg0_offset (4*(REG_REG0+4))
1430# define arg1_offset (4*(REG_REG0+5))
1431# elif defined (SH64)
1432 /* ABI defines arg0 & 1 in r2 & r3 */
1433# define arg0_offset (REG_OFFSET+16)
1434# define arg1_offset (REG_OFFSET+24)
1435# define restore_arg0(tcp, state, val) 0
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001436# elif defined CRISV10 || defined CRISV32
1437# define arg0_offset (4*PT_R11)
1438# define arg1_offset (4*PT_ORIG_R10)
1439# define restore_arg0(tcp, state, val) 0
1440# define restore_arg1(tcp, state, val) 0
1441# define arg0_index 1
1442# define arg1_index 0
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001443# else
1444# define arg0_offset 0
1445# define arg1_offset 4
1446# if defined ARM
1447# define restore_arg0(tcp, state, val) 0
1448# endif
1449# endif
Roland McGrathd81f1d92003-01-09 06:53:34 +00001450
1451typedef int arg_setup_state;
1452
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001453# define arg_setup(tcp, state) (0)
1454# define arg_finish_change(tcp, state) 0
1455# define get_arg0(tcp, cookie, valp) \
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001456 (upeek((tcp), arg0_offset, (valp)))
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001457# define get_arg1(tcp, cookie, valp) \
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001458 (upeek((tcp), arg1_offset, (valp)))
Roland McGrathd81f1d92003-01-09 06:53:34 +00001459
1460static int
Denys Vlasenko12014262011-05-30 14:00:14 +02001461set_arg0(struct tcb *tcp, void *cookie, long val)
Roland McGrathd81f1d92003-01-09 06:53:34 +00001462{
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001463 return ptrace(PTRACE_POKEUSER, tcp->pid, (char*)arg0_offset, val);
Roland McGrathd81f1d92003-01-09 06:53:34 +00001464}
1465
1466static int
Denys Vlasenko12014262011-05-30 14:00:14 +02001467set_arg1(struct tcb *tcp, void *cookie, long val)
Roland McGrathd81f1d92003-01-09 06:53:34 +00001468{
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001469 return ptrace(PTRACE_POKEUSER, tcp->pid, (char*)arg1_offset, val);
Roland McGrathd81f1d92003-01-09 06:53:34 +00001470}
1471
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001472# endif /* architectures */
Roland McGrathd81f1d92003-01-09 06:53:34 +00001473
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001474# ifndef restore_arg0
1475# define restore_arg0(tcp, state, val) set_arg0((tcp), (state), (val))
1476# endif
1477# ifndef restore_arg1
1478# define restore_arg1(tcp, state, val) set_arg1((tcp), (state), (val))
1479# endif
Roland McGrathd81f1d92003-01-09 06:53:34 +00001480
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001481# ifndef arg0_index
1482# define arg0_index 0
1483# define arg1_index 1
1484# endif
Roland McGrath90d0afd2004-03-01 21:05:16 +00001485
Roland McGrathd81f1d92003-01-09 06:53:34 +00001486int
Denys Vlasenko418d66a2009-01-17 01:52:54 +00001487setbpt(struct tcb *tcp)
Roland McGrathd81f1d92003-01-09 06:53:34 +00001488{
Roland McGrath3291ef22008-05-20 00:34:34 +00001489 static int clone_scno[SUPPORTED_PERSONALITIES] = { SYS_clone };
Roland McGrathd81f1d92003-01-09 06:53:34 +00001490 arg_setup_state state;
1491
1492 if (tcp->flags & TCB_BPTSET) {
1493 fprintf(stderr, "PANIC: TCB already set in pid %u\n", tcp->pid);
1494 return -1;
1495 }
1496
Roland McGrath3291ef22008-05-20 00:34:34 +00001497 /*
1498 * It's a silly kludge to initialize this with a search at runtime.
1499 * But it's better than maintaining another magic thing in the
1500 * godforsaken tables.
1501 */
1502 if (clone_scno[current_personality] == 0) {
1503 int i;
1504 for (i = 0; i < nsyscalls; ++i)
1505 if (sysent[i].sys_func == sys_clone) {
1506 clone_scno[current_personality] = i;
1507 break;
1508 }
1509 }
1510
Roland McGrath76989d72005-06-07 23:21:31 +00001511 switch (known_scno(tcp)) {
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001512# ifdef SYS_vfork
Roland McGrath9383c6c2003-01-18 00:19:31 +00001513 case SYS_vfork:
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001514# endif
1515# ifdef SYS_fork
Roland McGrathd81f1d92003-01-09 06:53:34 +00001516 case SYS_fork:
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001517# endif
1518# if defined SYS_fork || defined SYS_vfork
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001519 if (arg_setup(tcp, &state) < 0
1520 || get_arg0(tcp, &state, &tcp->inst[0]) < 0
1521 || get_arg1(tcp, &state, &tcp->inst[1]) < 0
Roland McGrath3291ef22008-05-20 00:34:34 +00001522 || change_syscall(tcp, clone_scno[current_personality]) < 0
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001523 || set_arg0(tcp, &state, CLONE_PTRACE|SIGCHLD) < 0
1524 || set_arg1(tcp, &state, 0) < 0
1525 || arg_finish_change(tcp, &state) < 0)
Roland McGrathd81f1d92003-01-09 06:53:34 +00001526 return -1;
Roland McGrathc9dc3c12004-03-01 20:57:09 +00001527 tcp->u_arg[arg0_index] = CLONE_PTRACE|SIGCHLD;
1528 tcp->u_arg[arg1_index] = 0;
Roland McGrathd81f1d92003-01-09 06:53:34 +00001529 tcp->flags |= TCB_BPTSET;
1530 return 0;
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001531# endif
Roland McGrathd81f1d92003-01-09 06:53:34 +00001532
Denys Vlasenkoc133bf02011-06-23 21:57:54 +02001533 case SYS_clone: ;
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001534# ifdef SYS_clone2
Denys Vlasenkoc133bf02011-06-23 21:57:54 +02001535 case SYS_clone2: ;
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001536# endif
Jan Kratochvil8fc95752008-08-06 21:43:35 +00001537 /* ia64 calls directly `clone (CLONE_VFORK | CLONE_VM)'
1538 contrary to x86 SYS_vfork above. Even on x86 we turn the
1539 vfork semantics into plain fork - each application must not
1540 depend on the vfork specifics according to POSIX. We would
1541 hang waiting for the parent resume otherwise. We need to
1542 clear also CLONE_VM but only in the CLONE_VFORK case as
1543 otherwise we would break pthread_create. */
1544
Denys Vlasenkoc133bf02011-06-23 21:57:54 +02001545 long new_arg0 = (tcp->u_arg[arg0_index] | CLONE_PTRACE);
1546 if (new_arg0 & CLONE_VFORK)
1547 new_arg0 &= ~(unsigned long)(CLONE_VFORK | CLONE_VM);
1548 if (arg_setup(tcp, &state) < 0
1549 || set_arg0(tcp, &state, new_arg0) < 0
1550 || arg_finish_change(tcp, &state) < 0)
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00001551 return -1;
Roland McGrathd81f1d92003-01-09 06:53:34 +00001552 tcp->flags |= TCB_BPTSET;
Roland McGrathc9dc3c12004-03-01 20:57:09 +00001553 tcp->inst[0] = tcp->u_arg[arg0_index];
1554 tcp->inst[1] = tcp->u_arg[arg1_index];
Roland McGrathd81f1d92003-01-09 06:53:34 +00001555 return 0;
1556
1557 default:
1558 fprintf(stderr, "PANIC: setbpt for syscall %ld on %u???\n",
1559 tcp->scno, tcp->pid);
1560 break;
1561 }
1562
1563 return -1;
1564}
1565
1566int
Denys Vlasenko12014262011-05-30 14:00:14 +02001567clearbpt(struct tcb *tcp)
Roland McGrathd81f1d92003-01-09 06:53:34 +00001568{
1569 arg_setup_state state;
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001570 if (arg_setup(tcp, &state) < 0
1571 || restore_arg0(tcp, &state, tcp->inst[0]) < 0
1572 || restore_arg1(tcp, &state, tcp->inst[1]) < 0
1573 || arg_finish_change(tcp, &state))
Denys Vlasenkoc133bf02011-06-23 21:57:54 +02001574 if (errno != ESRCH)
1575 return -1;
Roland McGrathd81f1d92003-01-09 06:53:34 +00001576 tcp->flags &= ~TCB_BPTSET;
1577 return 0;
1578}
1579
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001580# else /* !defined LINUX */
Roland McGrathd81f1d92003-01-09 06:53:34 +00001581
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001582int
Denys Vlasenko12014262011-05-30 14:00:14 +02001583setbpt(struct tcb *tcp)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001584{
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001585# ifdef SUNOS4
1586# ifdef SPARC /* This code is slightly sparc specific */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001587
Wichert Akkermane6f876c1999-06-22 15:28:30 +00001588 struct regs regs;
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001589# define BPT 0x91d02001 /* ta 1 */
1590# define LOOP 0x10800000 /* ba 0 */
1591# define LOOPA 0x30800000 /* ba,a 0 */
1592# define NOP 0x01000000
1593# if LOOPA
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001594 static int loopdeloop[1] = {LOOPA};
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001595# else
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001596 static int loopdeloop[2] = {LOOP, NOP};
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001597# endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001598
1599 if (tcp->flags & TCB_BPTSET) {
1600 fprintf(stderr, "PANIC: TCB already set in pid %u\n", tcp->pid);
1601 return -1;
1602 }
Roland McGratheb9e2e82009-06-02 16:49:22 -07001603 if (ptrace(PTRACE_GETREGS, tcp->pid, (char *)&regs, 0) < 0) {
1604 perror("setbpt: ptrace(PTRACE_GETREGS, ...)");
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001605 return -1;
1606 }
1607 tcp->baddr = regs.r_o7 + 8;
Roland McGratheb9e2e82009-06-02 16:49:22 -07001608 if (ptrace(PTRACE_READTEXT, tcp->pid, (char *)tcp->baddr,
1609 sizeof tcp->inst, (char *)tcp->inst) < 0) {
1610 perror("setbpt: ptrace(PTRACE_READTEXT, ...)");
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001611 return -1;
1612 }
1613
1614 /*
1615 * XXX - BRUTAL MODE ON
1616 * We cannot set a real BPT in the child, since it will not be
1617 * traced at the moment it will reach the trap and would probably
1618 * die with a core dump.
1619 * Thus, we are force our way in by taking out two instructions
1620 * and insert an eternal loop in stead, in expectance of the SIGSTOP
1621 * generated by out PTRACE_ATTACH.
1622 * Of cause, if we evaporate ourselves in the middle of all this...
1623 */
Roland McGratheb9e2e82009-06-02 16:49:22 -07001624 if (ptrace(PTRACE_WRITETEXT, tcp->pid, (char *) tcp->baddr,
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001625 sizeof loopdeloop, (char *) loopdeloop) < 0) {
Roland McGratheb9e2e82009-06-02 16:49:22 -07001626 perror("setbpt: ptrace(PTRACE_WRITETEXT, ...)");
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001627 return -1;
1628 }
1629 tcp->flags |= TCB_BPTSET;
1630
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001631# endif /* SPARC */
1632# endif /* SUNOS4 */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001633
1634 return 0;
1635}
1636
1637int
Denys Vlasenko12014262011-05-30 14:00:14 +02001638clearbpt(struct tcb *tcp)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001639{
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001640# ifdef SUNOS4
1641# ifdef SPARC
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001642
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001643# if !LOOPA
Wichert Akkermane6f876c1999-06-22 15:28:30 +00001644 struct regs regs;
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001645# endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001646
1647 if (!(tcp->flags & TCB_BPTSET)) {
1648 fprintf(stderr, "PANIC: TCB not set in pid %u\n", tcp->pid);
1649 return -1;
1650 }
Roland McGratheb9e2e82009-06-02 16:49:22 -07001651 if (ptrace(PTRACE_WRITETEXT, tcp->pid, (char *) tcp->baddr,
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001652 sizeof tcp->inst, (char *) tcp->inst) < 0) {
Roland McGratheb9e2e82009-06-02 16:49:22 -07001653 perror("clearbtp: ptrace(PTRACE_WRITETEXT, ...)");
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001654 return -1;
1655 }
1656 tcp->flags &= ~TCB_BPTSET;
1657
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001658# if !LOOPA
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001659 /*
1660 * Since we don't have a single instruction breakpoint, we may have
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001661 * to adjust the program counter after removing our `breakpoint'.
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001662 */
Roland McGratheb9e2e82009-06-02 16:49:22 -07001663 if (ptrace(PTRACE_GETREGS, tcp->pid, (char *)&regs, 0) < 0) {
1664 perror("clearbpt: ptrace(PTRACE_GETREGS, ...)");
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001665 return -1;
1666 }
Roland McGratheb9e2e82009-06-02 16:49:22 -07001667 if ((regs.r_pc < tcp->baddr) ||
1668 (regs.r_pc > tcp->baddr + 4)) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001669 /* The breakpoint has not been reached yet */
1670 if (debug)
1671 fprintf(stderr,
1672 "NOTE: PC not at bpt (pc %#x baddr %#x)\n",
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001673 regs.r_pc, tcp->baddr);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001674 return 0;
1675 }
1676 if (regs.r_pc != tcp->baddr)
1677 if (debug)
1678 fprintf(stderr, "NOTE: PC adjusted (%#x -> %#x\n",
1679 regs.r_pc, tcp->baddr);
1680
1681 regs.r_pc = tcp->baddr;
Roland McGratheb9e2e82009-06-02 16:49:22 -07001682 if (ptrace(PTRACE_SETREGS, tcp->pid, (char *)&regs, 0) < 0) {
1683 perror("clearbpt: ptrace(PTRACE_SETREGS, ...)");
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001684 return -1;
1685 }
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001686# endif /* LOOPA */
1687# endif /* SPARC */
1688# endif /* SUNOS4 */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001689
1690 return 0;
1691}
1692
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001693# endif /* !defined LINUX */
Roland McGrathd81f1d92003-01-09 06:53:34 +00001694
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001695#endif /* !USE_PROCFS */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001696
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001697
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001698#ifdef SUNOS4
1699
1700static int
Denys Vlasenko12014262011-05-30 14:00:14 +02001701getex(struct tcb *tcp, struct exec *hdr)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001702{
1703 int n;
1704
1705 for (n = 0; n < sizeof *hdr; n += 4) {
1706 long res;
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001707 if (upeek(tcp, uoff(u_exdata) + n, &res) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001708 return -1;
1709 memcpy(((char *) hdr) + n, &res, 4);
1710 }
1711 if (debug) {
1712 fprintf(stderr, "[struct exec: magic: %o version %u Mach %o\n",
1713 hdr->a_magic, hdr->a_toolversion, hdr->a_machtype);
1714 fprintf(stderr, "Text %lu Data %lu Bss %lu Syms %lu Entry %#lx]\n",
1715 hdr->a_text, hdr->a_data, hdr->a_bss, hdr->a_syms, hdr->a_entry);
1716 }
1717 return 0;
1718}
1719
1720int
Denys Vlasenko12014262011-05-30 14:00:14 +02001721fixvfork(struct tcb *tcp)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001722{
1723 int pid = tcp->pid;
1724 /*
1725 * Change `vfork' in a freshly exec'ed dynamically linked
1726 * executable's (internal) symbol table to plain old `fork'
1727 */
1728
1729 struct exec hdr;
1730 struct link_dynamic dyn;
1731 struct link_dynamic_2 ld;
1732 char *strtab, *cp;
1733
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001734 if (getex(tcp, &hdr) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001735 return -1;
1736 if (!hdr.a_dynamic)
1737 return -1;
1738
1739 if (umove(tcp, (int) N_DATADDR(hdr), &dyn) < 0) {
1740 fprintf(stderr, "Cannot read DYNAMIC\n");
1741 return -1;
1742 }
1743 if (umove(tcp, (int) dyn.ld_un.ld_2, &ld) < 0) {
1744 fprintf(stderr, "Cannot read link_dynamic_2\n");
1745 return -1;
1746 }
Denys Vlasenko5d645812011-08-20 12:48:18 +02001747 strtab = malloc((unsigned)ld.ld_symb_size);
Denys Vlasenko1d46ba52011-08-31 14:00:02 +02001748 if (!strtab)
1749 die_out_of_memory();
Roland McGratheb9e2e82009-06-02 16:49:22 -07001750 if (umoven(tcp, (int)ld.ld_symbols+(int)N_TXTADDR(hdr),
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001751 (int)ld.ld_symb_size, strtab) < 0)
1752 goto err;
1753
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001754 for (cp = strtab; cp < strtab + ld.ld_symb_size; ) {
1755 if (strcmp(cp, "_vfork") == 0) {
1756 if (debug)
1757 fprintf(stderr, "fixvfork: FOUND _vfork\n");
1758 strcpy(cp, "_fork");
1759 break;
1760 }
1761 cp += strlen(cp)+1;
1762 }
1763 if (cp < strtab + ld.ld_symb_size)
1764 /*
1765 * Write entire symbol table back to avoid
1766 * memory alignment bugs in ptrace
1767 */
Roland McGratheb9e2e82009-06-02 16:49:22 -07001768 if (tload(pid, (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
1772 free(strtab);
1773 return 0;
1774
1775err:
1776 free(strtab);
1777 return -1;
1778}
1779
1780#endif /* SUNOS4 */