blob: 0283a9eea4a9b1898b992c42a911637148426868 [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
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000430static char path[MAXPATHLEN + 1];
431
Dmitry V. Levina501f142008-11-10 23:19:13 +0000432/*
433 * Quote string `instr' of length `size'
434 * Write up to (3 + `size' * 4) bytes to `outstr' buffer.
435 * If `len' < 0, treat `instr' as a NUL-terminated string
436 * and quote at most (`size' - 1) bytes.
437 */
Roland McGrath6d970322007-11-01 23:53:59 +0000438static int
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000439string_quote(const char *instr, char *outstr, int len, int size)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000440{
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000441 const unsigned char *ustr = (const unsigned char *) instr;
442 char *s = outstr;
Denys Vlasenko8778bff2011-08-31 12:22:56 +0200443 int usehex, c, i, eol;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000444
Denys Vlasenko8778bff2011-08-31 12:22:56 +0200445 eol = 0x100; /* this can never match a char */
446 if (len < 0) {
447 size--;
448 eol = '\0';
449 }
450
451 usehex = 0;
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000452 if (xflag > 1)
453 usehex = 1;
454 else if (xflag) {
Dmitry V. Levina501f142008-11-10 23:19:13 +0000455 /* Check for presence of symbol which require
456 to hex-quote the whole string. */
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000457 for (i = 0; i < size; ++i) {
458 c = ustr[i];
Dmitry V. Levina501f142008-11-10 23:19:13 +0000459 /* Check for NUL-terminated string. */
Denys Vlasenko8778bff2011-08-31 12:22:56 +0200460 if (c == eol)
461 break;
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000462 if (!isprint(c) && !isspace(c)) {
463 usehex = 1;
464 break;
465 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000466 }
467 }
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000468
469 *s++ = '\"';
470
471 if (usehex) {
Dmitry V. Levina501f142008-11-10 23:19:13 +0000472 /* Hex-quote the whole string. */
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000473 for (i = 0; i < size; ++i) {
474 c = ustr[i];
Dmitry V. Levina501f142008-11-10 23:19:13 +0000475 /* Check for NUL-terminated string. */
Denys Vlasenko8778bff2011-08-31 12:22:56 +0200476 if (c == eol)
477 goto asciz_ended;
478 *s++ = '\\';
479 *s++ = 'x';
480 *s++ = "0123456789abcdef"[c >> 4];
481 *s++ = "0123456789abcdef"[c & 0xf];
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000482 }
483 } else {
484 for (i = 0; i < size; ++i) {
485 c = ustr[i];
Dmitry V. Levina501f142008-11-10 23:19:13 +0000486 /* Check for NUL-terminated string. */
Denys Vlasenko8778bff2011-08-31 12:22:56 +0200487 if (c == eol)
488 goto asciz_ended;
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000489 switch (c) {
490 case '\"': case '\\':
491 *s++ = '\\';
492 *s++ = c;
493 break;
494 case '\f':
495 *s++ = '\\';
496 *s++ = 'f';
497 break;
498 case '\n':
499 *s++ = '\\';
500 *s++ = 'n';
501 break;
502 case '\r':
503 *s++ = '\\';
504 *s++ = 'r';
505 break;
506 case '\t':
507 *s++ = '\\';
508 *s++ = 't';
509 break;
510 case '\v':
511 *s++ = '\\';
512 *s++ = 'v';
513 break;
514 default:
515 if (isprint(c))
516 *s++ = c;
Denys Vlasenko8778bff2011-08-31 12:22:56 +0200517 else {
518 /* Print \octal */
519 *s++ = '\\';
520 if (i + 1 < size
521 && ustr[i + 1] >= '0'
522 && ustr[i + 1] <= '9'
523 ) {
524 /* Print \ooo */
525 *s++ = '0' + (c >> 6);
526 *s++ = '0' + ((c >> 3) & 0x7);
527 } else {
528 /* Print \[[o]o]o */
529 if ((c >> 3) != 0) {
530 if ((c >> 6) != 0)
531 *s++ = '0' + (c >> 6);
532 *s++ = '0' + ((c >> 3) & 0x7);
533 }
534 }
535 *s++ = '0' + (c & 0x7);
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000536 }
537 break;
538 }
539 }
540 }
541
542 *s++ = '\"';
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000543 *s = '\0';
Roland McGrath6d970322007-11-01 23:53:59 +0000544
Denys Vlasenko8778bff2011-08-31 12:22:56 +0200545 /* Return zero if we printed entire ASCIZ string (didn't truncate it) */
546 if (len < 0 && ustr[i] == '\0') {
547 /* We didn't see NUL yet (otherwise we'd jump to 'asciz_ended')
548 * but next char is NUL.
549 */
550 return 0;
551 }
552
553 return 1;
554
555 asciz_ended:
556 *s++ = '\"';
557 *s = '\0';
558 /* Return zero: we printed entire ASCIZ string (didn't truncate it) */
559 return 0;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000560}
561
Dmitry V. Levina501f142008-11-10 23:19:13 +0000562/*
563 * Print path string specified by address `addr' and length `n'.
564 * If path length exceeds `n', append `...' to the output.
565 */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000566void
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000567printpathn(struct tcb *tcp, long addr, int n)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000568{
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 {
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000584 static char outstr[4*(sizeof path - 1) + sizeof "\"...\""];
Denys Vlasenko52845572011-08-31 12:07:38 +0200585 const char *fmt;
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000586 int trunc = (path[n] != '\0');
587
588 if (trunc)
589 path[n] = '\0';
Denys Vlasenko52845572011-08-31 12:07:38 +0200590 string_quote(path, outstr, -1, n + 1);
591 fmt = "%s";
Dmitry V. Levina501f142008-11-10 23:19:13 +0000592 if (trunc)
Denys Vlasenko52845572011-08-31 12:07:38 +0200593 fmt = "%s...";
594 tprintf(fmt, outstr);
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{
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000601 printpathn(tcp, addr, sizeof path - 1);
602}
603
Dmitry V. Levina501f142008-11-10 23:19:13 +0000604/*
605 * Print string specified by address `addr' and length `len'.
606 * If `len' < 0, treat the string as a NUL-terminated string.
607 * If string length exceeds `max_strlen', append `...' to the output.
608 */
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000609void
610printstr(struct tcb *tcp, long addr, int len)
611{
612 static char *str = NULL;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000613 static char *outstr;
Roland McGrath6d970322007-11-01 23:53:59 +0000614 int size;
Denys Vlasenko52845572011-08-31 12:07:38 +0200615 const char *fmt;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000616
617 if (!addr) {
Denys Vlasenko60fe8c12011-09-01 10:00:28 +0200618 tprints("NULL");
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000619 return;
620 }
Dmitry V. Levina501f142008-11-10 23:19:13 +0000621 /* Allocate static buffers if they are not allocated yet. */
Denys Vlasenko1d46ba52011-08-31 14:00:02 +0200622 if (!str) {
Dmitry V. Levina501f142008-11-10 23:19:13 +0000623 str = malloc(max_strlen + 1);
Denys Vlasenko1d46ba52011-08-31 14:00:02 +0200624 if (!str)
625 die_out_of_memory();
626 }
627 if (!outstr) {
Dmitry V. Levina501f142008-11-10 23:19:13 +0000628 outstr = malloc(4 * max_strlen + sizeof "\"...\"");
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;
Dmitry V. Levina501f142008-11-10 23:19:13 +0000639 str[max_strlen] = '\0';
Denys Vlasenko52845572011-08-31 12:07:38 +0200640 /* FIXME! umovestr can overwrite the '\0' stored above??? */
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000641 if (umovestr(tcp, addr, size, str) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000642 tprintf("%#lx", addr);
643 return;
644 }
645 }
646 else {
Dmitry V. Levina501f142008-11-10 23:19:13 +0000647 size = MIN(len, max_strlen);
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000648 if (umoven(tcp, addr, size, str) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000649 tprintf("%#lx", addr);
650 return;
651 }
652 }
653
Denys Vlasenko52845572011-08-31 12:07:38 +0200654 fmt = "%s";
Dmitry V. Levina501f142008-11-10 23:19:13 +0000655 if (string_quote(str, outstr, len, size) &&
656 (len < 0 || len > max_strlen))
Denys Vlasenko52845572011-08-31 12:07:38 +0200657 fmt = "%s...";
Roland McGratha503dcf2007-08-02 02:06:26 +0000658
Denys Vlasenko52845572011-08-31 12:07:38 +0200659 tprintf(fmt, outstr);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000660}
661
John Hughes1d08dcf2001-07-10 13:48:44 +0000662#if HAVE_SYS_UIO_H
663void
Denys Vlasenko12014262011-05-30 14:00:14 +0200664dumpiov(struct tcb *tcp, int len, long addr)
John Hughes1d08dcf2001-07-10 13:48:44 +0000665{
Dmitry V. Levin4ebb4e32006-12-13 17:08:08 +0000666#if defined(LINUX) && SUPPORTED_PERSONALITIES > 1
667 union {
668 struct { u_int32_t base; u_int32_t len; } *iov32;
669 struct { u_int64_t base; u_int64_t len; } *iov64;
670 } iovu;
671#define iov iovu.iov64
672#define sizeof_iov \
673 (personality_wordsize[current_personality] == 4 \
674 ? sizeof(*iovu.iov32) : sizeof(*iovu.iov64))
675#define iov_iov_base(i) \
676 (personality_wordsize[current_personality] == 4 \
677 ? (u_int64_t) iovu.iov32[i].base : iovu.iov64[i].base)
678#define iov_iov_len(i) \
679 (personality_wordsize[current_personality] == 4 \
680 ? (u_int64_t) iovu.iov32[i].len : iovu.iov64[i].len)
681#else
John Hughes1d08dcf2001-07-10 13:48:44 +0000682 struct iovec *iov;
Dmitry V. Levin4ebb4e32006-12-13 17:08:08 +0000683#define sizeof_iov sizeof(*iov)
684#define iov_iov_base(i) iov[i].iov_base
685#define iov_iov_len(i) iov[i].iov_len
686#endif
John Hughes1d08dcf2001-07-10 13:48:44 +0000687 int i;
Denys Vlasenko79a79ea2011-09-01 16:35:44 +0200688 unsigned size;
John Hughes1d08dcf2001-07-10 13:48:44 +0000689
Denys Vlasenko79a79ea2011-09-01 16:35:44 +0200690 size = sizeof_iov * len;
691 /* Assuming no sane program has millions of iovs */
692 if ((unsigned)len > 1024*1024 /* insane or negative size? */
Dmitry V. Levin4ebb4e32006-12-13 17:08:08 +0000693 || (iov = malloc(size)) == NULL) {
Denys Vlasenko79a79ea2011-09-01 16:35:44 +0200694 fprintf(stderr, "Out of memory\n");
695 return;
John Hughes1d08dcf2001-07-10 13:48:44 +0000696 }
Roland McGrathaa524c82005-06-01 19:22:06 +0000697 if (umoven(tcp, addr, size, (char *) iov) >= 0) {
John Hughes1d08dcf2001-07-10 13:48:44 +0000698 for (i = 0; i < len; i++) {
Denys Vlasenkoadedb512008-12-30 18:47:55 +0000699 /* include the buffer number to make it easy to
700 * match up the trace with the source */
701 tprintf(" * %lu bytes in buffer %d\n",
702 (unsigned long)iov_iov_len(i), i);
703 dumpstr(tcp, (long) iov_iov_base(i),
704 iov_iov_len(i));
705 }
John Hughes1d08dcf2001-07-10 13:48:44 +0000706 }
Denys Vlasenko79a79ea2011-09-01 16:35:44 +0200707 free(iov);
Dmitry V. Levin4ebb4e32006-12-13 17:08:08 +0000708#undef sizeof_iov
709#undef iov_iov_base
710#undef iov_iov_len
711#undef iov
John Hughes1d08dcf2001-07-10 13:48:44 +0000712}
713#endif
714
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000715void
Denys Vlasenko12014262011-05-30 14:00:14 +0200716dumpstr(struct tcb *tcp, long addr, int len)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000717{
718 static int strsize = -1;
719 static unsigned char *str;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000720 char *s;
721 int i, j;
722
723 if (strsize < len) {
Denys Vlasenko5d645812011-08-20 12:48:18 +0200724 free(str);
725 str = malloc(len);
Denys Vlasenko79a79ea2011-09-01 16:35:44 +0200726 if (!str) {
727 strsize = -1;
728 fprintf(stderr, "Out of memory\n");
729 return;
730 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000731 strsize = len;
732 }
733
734 if (umoven(tcp, addr, len, (char *) str) < 0)
735 return;
736
737 for (i = 0; i < len; i += 16) {
Denys Vlasenko1d46ba52011-08-31 14:00:02 +0200738 char outstr[80];
739
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000740 s = outstr;
741 sprintf(s, " | %05x ", i);
742 s += 9;
743 for (j = 0; j < 16; j++) {
744 if (j == 8)
745 *s++ = ' ';
746 if (i + j < len) {
747 sprintf(s, " %02x", str[i + j]);
748 s += 3;
749 }
750 else {
751 *s++ = ' '; *s++ = ' '; *s++ = ' ';
752 }
753 }
754 *s++ = ' '; *s++ = ' ';
755 for (j = 0; j < 16; j++) {
756 if (j == 8)
757 *s++ = ' ';
758 if (i + j < len) {
759 if (isprint(str[i + j]))
760 *s++ = str[i + j];
761 else
762 *s++ = '.';
763 }
764 else
765 *s++ = ' ';
766 }
767 tprintf("%s |\n", outstr);
768 }
769}
770
771#define PAGMASK (~(PAGSIZ - 1))
772/*
773 * move `len' bytes of data from process `pid'
774 * at address `addr' to our space at `laddr'
775 */
776int
Denys Vlasenkoef2fbf82009-01-06 21:45:06 +0000777umoven(struct tcb *tcp, long addr, int len, char *laddr)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000778{
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000779#ifdef LINUX
Roland McGratheb9e2e82009-06-02 16:49:22 -0700780 int pid = tcp->pid;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000781 int n, m;
Wichert Akkerman5daa0281999-03-15 19:49:42 +0000782 int started = 0;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000783 union {
784 long val;
785 char x[sizeof(long)];
786 } u;
787
Dmitry V. Levin856c7ed2011-12-26 20:12:02 +0000788#if SUPPORTED_PERSONALITIES > 1
789 if (personality_wordsize[current_personality] < sizeof(addr))
790 addr &= (1ul << 8 * personality_wordsize[current_personality]) - 1;
791#endif
792
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000793 if (addr & (sizeof(long) - 1)) {
794 /* addr not a multiple of sizeof(long) */
795 n = addr - (addr & -sizeof(long)); /* residue */
796 addr &= -sizeof(long); /* residue */
Roland McGratheb9e2e82009-06-02 16:49:22 -0700797 errno = 0;
798 u.val = ptrace(PTRACE_PEEKDATA, pid, (char *) addr, 0);
799 if (errno) {
Roland McGratheb9e2e82009-06-02 16:49:22 -0700800 /* But if not started, we had a bogus address. */
801 if (addr != 0 && errno != EIO && errno != ESRCH)
802 perror("ptrace: umoven");
803 return -1;
804 }
Wichert Akkerman5daa0281999-03-15 19:49:42 +0000805 started = 1;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000806 memcpy(laddr, &u.x[n], m = MIN(sizeof(long) - n, len));
807 addr += sizeof(long), laddr += m, len -= m;
808 }
809 while (len) {
Roland McGratheb9e2e82009-06-02 16:49:22 -0700810 errno = 0;
811 u.val = ptrace(PTRACE_PEEKDATA, pid, (char *) addr, 0);
812 if (errno) {
813 if (started && (errno==EPERM || errno==EIO)) {
814 /* Ran into 'end of memory' - stupid "printpath" */
815 return 0;
816 }
817 if (addr != 0 && errno != EIO && errno != ESRCH)
818 perror("ptrace: umoven");
819 return -1;
820 }
Wichert Akkerman5daa0281999-03-15 19:49:42 +0000821 started = 1;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000822 memcpy(laddr, u.x, m = MIN(sizeof(long), len));
823 addr += sizeof(long), laddr += m, len -= m;
824 }
825#endif /* LINUX */
826
827#ifdef SUNOS4
828 int pid = tcp->pid;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000829 int n;
830
831 while (len) {
832 n = MIN(len, PAGSIZ);
833 n = MIN(n, ((addr + PAGSIZ) & PAGMASK) - addr);
Roland McGratheb9e2e82009-06-02 16:49:22 -0700834 if (ptrace(PTRACE_READDATA, pid,
835 (char *) addr, len, laddr) < 0) {
836 if (errno != ESRCH) {
837 perror("umoven: ptrace(PTRACE_READDATA, ...)");
838 abort();
839 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000840 return -1;
841 }
842 len -= n;
843 addr += n;
844 laddr += n;
845 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000846#endif /* SUNOS4 */
847
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000848#ifdef USE_PROCFS
Wichert Akkermanea78f0f1999-11-29 15:34:02 +0000849#ifdef HAVE_MP_PROCFS
John Hughesaa09c6b2001-05-15 14:53:43 +0000850 int fd = tcp->pfd_as;
Wichert Akkerman9ce1a631999-08-29 23:15:07 +0000851#else
John Hughesaa09c6b2001-05-15 14:53:43 +0000852 int fd = tcp->pfd;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000853#endif
John Hughesaa09c6b2001-05-15 14:53:43 +0000854 lseek(fd, addr, SEEK_SET);
855 if (read(fd, laddr, len) == -1)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000856 return -1;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000857#endif /* USE_PROCFS */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000858
859 return 0;
860}
861
862/*
863 * like `umove' but make the additional effort of looking
864 * for a terminating zero byte.
865 */
866int
Denys Vlasenkoef2fbf82009-01-06 21:45:06 +0000867umovestr(struct tcb *tcp, long addr, int len, char *laddr)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000868{
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000869#ifdef USE_PROCFS
John Hughesaa09c6b2001-05-15 14:53:43 +0000870#ifdef HAVE_MP_PROCFS
871 int fd = tcp->pfd_as;
872#else
873 int fd = tcp->pfd;
874#endif
875 /* Some systems (e.g. FreeBSD) can be upset if we read off the
876 end of valid memory, avoid this by trying to read up
877 to page boundaries. But we don't know what a page is (and
878 getpagesize(2) (if it exists) doesn't necessarily return
879 hardware page size). Assume all pages >= 1024 (a-historical
880 I know) */
881
Denys Vlasenkob63256e2011-06-07 12:13:24 +0200882 int page = 1024; /* How to find this? */
John Hughesaa09c6b2001-05-15 14:53:43 +0000883 int move = page - (addr & (page - 1));
884 int left = len;
885
886 lseek(fd, addr, SEEK_SET);
887
888 while (left) {
Denys Vlasenko5d645812011-08-20 12:48:18 +0200889 if (move > left)
890 move = left;
891 move = read(fd, laddr, move);
892 if (move <= 0)
John Hughesaa09c6b2001-05-15 14:53:43 +0000893 return left != len ? 0 : -1;
Denys Vlasenko5d645812011-08-20 12:48:18 +0200894 if (memchr(laddr, 0, move))
895 break;
John Hughesaa09c6b2001-05-15 14:53:43 +0000896 left -= move;
897 laddr += move;
898 addr += move;
899 move = page;
900 }
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000901#else /* !USE_PROCFS */
Wichert Akkerman5daa0281999-03-15 19:49:42 +0000902 int started = 0;
Roland McGratheb9e2e82009-06-02 16:49:22 -0700903 int pid = tcp->pid;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000904 int i, n, m;
905 union {
906 long val;
907 char x[sizeof(long)];
908 } u;
909
Dmitry V. Levin856c7ed2011-12-26 20:12:02 +0000910#if SUPPORTED_PERSONALITIES > 1
911 if (personality_wordsize[current_personality] < sizeof(addr))
912 addr &= (1ul << 8 * personality_wordsize[current_personality]) - 1;
913#endif
914
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000915 if (addr & (sizeof(long) - 1)) {
916 /* addr not a multiple of sizeof(long) */
917 n = addr - (addr & -sizeof(long)); /* residue */
918 addr &= -sizeof(long); /* residue */
Roland McGratheb9e2e82009-06-02 16:49:22 -0700919 errno = 0;
920 u.val = ptrace(PTRACE_PEEKDATA, pid, (char *)addr, 0);
921 if (errno) {
Roland McGratheb9e2e82009-06-02 16:49:22 -0700922 if (addr != 0 && errno != EIO && errno != ESRCH)
923 perror("umovestr");
924 return -1;
925 }
Wichert Akkerman5daa0281999-03-15 19:49:42 +0000926 started = 1;
Denys Vlasenkob63256e2011-06-07 12:13:24 +0200927 memcpy(laddr, &u.x[n], m = MIN(sizeof(long)-n, len));
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000928 while (n & (sizeof(long) - 1))
929 if (u.x[n++] == '\0')
930 return 0;
931 addr += sizeof(long), laddr += m, len -= m;
932 }
933 while (len) {
Roland McGratheb9e2e82009-06-02 16:49:22 -0700934 errno = 0;
935 u.val = ptrace(PTRACE_PEEKDATA, pid, (char *)addr, 0);
936 if (errno) {
937 if (started && (errno==EPERM || errno==EIO)) {
938 /* Ran into 'end of memory' - stupid "printpath" */
939 return 0;
940 }
941 if (addr != 0 && errno != EIO && errno != ESRCH)
942 perror("umovestr");
943 return -1;
944 }
Wichert Akkerman5daa0281999-03-15 19:49:42 +0000945 started = 1;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000946 memcpy(laddr, u.x, m = MIN(sizeof(long), len));
947 for (i = 0; i < sizeof(long); i++)
948 if (u.x[i] == '\0')
949 return 0;
950
951 addr += sizeof(long), laddr += m, len -= m;
952 }
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000953#endif /* !USE_PROCFS */
John Hughesaa09c6b2001-05-15 14:53:43 +0000954 return 0;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000955}
956
957#ifdef LINUX
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +0000958# if !defined (SPARC) && !defined(SPARC64)
959# define PTRACE_WRITETEXT 101
960# define PTRACE_WRITEDATA 102
961# endif /* !SPARC && !SPARC64 */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000962#endif /* LINUX */
963
964#ifdef SUNOS4
965
966static int
Denys Vlasenko12014262011-05-30 14:00:14 +0200967uload(int cmd, int pid, long addr, int len, char *laddr)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000968{
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000969 int peek, poke;
970 int n, m;
971 union {
972 long val;
973 char x[sizeof(long)];
974 } u;
975
976 if (cmd == PTRACE_WRITETEXT) {
977 peek = PTRACE_PEEKTEXT;
978 poke = PTRACE_POKETEXT;
979 }
980 else {
981 peek = PTRACE_PEEKDATA;
982 poke = PTRACE_POKEDATA;
983 }
984 if (addr & (sizeof(long) - 1)) {
985 /* addr not a multiple of sizeof(long) */
986 n = addr - (addr & -sizeof(long)); /* residue */
987 addr &= -sizeof(long);
Roland McGratheb9e2e82009-06-02 16:49:22 -0700988 errno = 0;
989 u.val = ptrace(peek, pid, (char *) addr, 0);
990 if (errno) {
991 perror("uload: POKE");
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000992 return -1;
993 }
Roland McGratheb9e2e82009-06-02 16:49:22 -0700994 memcpy(&u.x[n], laddr, m = MIN(sizeof(long) - n, len));
995 if (ptrace(poke, pid, (char *)addr, u.val) < 0) {
996 perror("uload: POKE");
997 return -1;
998 }
999 addr += sizeof(long), laddr += m, len -= m;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001000 }
1001 while (len) {
1002 if (len < sizeof(long))
Roland McGratheb9e2e82009-06-02 16:49:22 -07001003 u.val = ptrace(peek, pid, (char *) addr, 0);
1004 memcpy(u.x, laddr, m = MIN(sizeof(long), len));
1005 if (ptrace(poke, pid, (char *) addr, u.val) < 0) {
1006 perror("uload: POKE");
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001007 return -1;
1008 }
Roland McGratheb9e2e82009-06-02 16:49:22 -07001009 addr += sizeof(long), laddr += m, len -= m;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001010 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001011 return 0;
1012}
1013
Roland McGratheb9e2e82009-06-02 16:49:22 -07001014int
Denys Vlasenko12014262011-05-30 14:00:14 +02001015tload(int pid, int addr, int len, char *laddr)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001016{
Roland McGratheb9e2e82009-06-02 16:49:22 -07001017 return uload(PTRACE_WRITETEXT, pid, addr, len, laddr);
1018}
1019
1020int
Denys Vlasenko12014262011-05-30 14:00:14 +02001021dload(int pid, int addr, int len, char *laddr)
Roland McGratheb9e2e82009-06-02 16:49:22 -07001022{
1023 return uload(PTRACE_WRITEDATA, pid, addr, len, laddr);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001024}
1025
1026#endif /* SUNOS4 */
1027
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001028#ifndef USE_PROCFS
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001029
1030int
Denys Vlasenko12014262011-05-30 14:00:14 +02001031upeek(struct tcb *tcp, long off, long *res)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001032{
1033 long val;
1034
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001035# ifdef SUNOS4_KERNEL_ARCH_KLUDGE
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001036 {
1037 static int is_sun4m = -1;
1038 struct utsname name;
1039
1040 /* Round up the usual suspects. */
1041 if (is_sun4m == -1) {
1042 if (uname(&name) < 0) {
1043 perror("upeek: uname?");
1044 exit(1);
1045 }
1046 is_sun4m = strcmp(name.machine, "sun4m") == 0;
1047 if (is_sun4m) {
Roland McGrathd9f816f2004-09-04 03:39:20 +00001048 const struct xlat *x;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001049
1050 for (x = struct_user_offsets; x->str; x++)
1051 x->val += 1024;
1052 }
1053 }
1054 if (is_sun4m)
1055 off += 1024;
1056 }
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001057# endif /* SUNOS4_KERNEL_ARCH_KLUDGE */
Roland McGratheb9e2e82009-06-02 16:49:22 -07001058 errno = 0;
Denys Vlasenko732d1bf2008-12-17 19:21:59 +00001059 val = do_ptrace(PTRACE_PEEKUSER, tcp, (char *) off, 0);
Roland McGratheb9e2e82009-06-02 16:49:22 -07001060 if (val == -1 && errno) {
1061 if (errno != ESRCH) {
1062 char buf[60];
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001063 sprintf(buf, "upeek: ptrace(PTRACE_PEEKUSER,%d,%lu,0)", tcp->pid, off);
Roland McGratheb9e2e82009-06-02 16:49:22 -07001064 perror(buf);
1065 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001066 return -1;
Roland McGratheb9e2e82009-06-02 16:49:22 -07001067 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001068 *res = val;
1069 return 0;
1070}
1071
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001072#endif /* !USE_PROCFS */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001073
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001074void
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001075printcall(struct tcb *tcp)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001076{
Roland McGrath7a918832005-02-02 20:55:23 +00001077#define PRINTBADPC tprintf(sizeof(long) == 4 ? "[????????] " : \
1078 sizeof(long) == 8 ? "[????????????????] " : \
1079 NULL /* crash */)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001080
1081#ifdef LINUX
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001082# ifdef I386
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001083 long eip;
1084
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001085 if (upeek(tcp, 4*EIP, &eip) < 0) {
Roland McGrath7a918832005-02-02 20:55:23 +00001086 PRINTBADPC;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001087 return;
1088 }
1089 tprintf("[%08lx] ", eip);
Roland McGratheac26fc2005-02-02 02:48:53 +00001090
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001091# elif defined(S390) || defined(S390X)
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001092 long psw;
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001093 if (upeek(tcp, PT_PSWADDR, &psw) < 0) {
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001094 PRINTBADPC;
1095 return;
1096 }
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001097# ifdef S390
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001098 tprintf("[%08lx] ", psw);
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001099# elif S390X
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001100 tprintf("[%16lx] ", psw);
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001101# endif
Roland McGratheac26fc2005-02-02 02:48:53 +00001102
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001103# elif defined(X86_64)
Michal Ludvig0e035502002-09-23 15:41:01 +00001104 long rip;
1105
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001106 if (upeek(tcp, 8*RIP, &rip) < 0) {
Roland McGrath7a918832005-02-02 20:55:23 +00001107 PRINTBADPC;
Michal Ludvig0e035502002-09-23 15:41:01 +00001108 return;
1109 }
1110 tprintf("[%16lx] ", rip);
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001111# elif defined(IA64)
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00001112 long ip;
1113
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001114 if (upeek(tcp, PT_B0, &ip) < 0) {
Roland McGrath7a918832005-02-02 20:55:23 +00001115 PRINTBADPC;
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00001116 return;
1117 }
1118 tprintf("[%08lx] ", ip);
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001119# elif defined(POWERPC)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001120 long pc;
1121
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001122 if (upeek(tcp, sizeof(unsigned long)*PT_NIP, &pc) < 0) {
Andreas Schwabd69fa492010-07-12 21:39:57 +02001123 PRINTBADPC;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001124 return;
1125 }
Andreas Schwabd69fa492010-07-12 21:39:57 +02001126# ifdef POWERPC64
1127 tprintf("[%016lx] ", pc);
1128# else
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001129 tprintf("[%08lx] ", pc);
Andreas Schwabd69fa492010-07-12 21:39:57 +02001130# endif
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001131# elif defined(M68K)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001132 long pc;
1133
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001134 if (upeek(tcp, 4*PT_PC, &pc) < 0) {
Denys Vlasenko60fe8c12011-09-01 10:00:28 +02001135 tprints("[????????] ");
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001136 return;
1137 }
1138 tprintf("[%08lx] ", pc);
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001139# elif defined(ALPHA)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001140 long pc;
1141
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001142 if (upeek(tcp, REG_PC, &pc) < 0) {
Denys Vlasenko60fe8c12011-09-01 10:00:28 +02001143 tprints("[????????????????] ");
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001144 return;
1145 }
1146 tprintf("[%08lx] ", pc);
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001147# elif defined(SPARC) || defined(SPARC64)
Mike Frysinger8566c502009-10-12 11:05:14 -04001148 struct pt_regs regs;
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001149 if (ptrace(PTRACE_GETREGS, tcp->pid, (char *)&regs, 0) < 0) {
Roland McGrath7a918832005-02-02 20:55:23 +00001150 PRINTBADPC;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001151 return;
1152 }
Mike Frysinger8566c502009-10-12 11:05:14 -04001153# if defined(SPARC64)
1154 tprintf("[%08lx] ", regs.tpc);
1155# else
1156 tprintf("[%08lx] ", regs.pc);
1157# endif
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001158# elif defined(HPPA)
Wichert Akkermanc1652e22001-03-27 12:17:16 +00001159 long pc;
1160
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001161 if (upeek(tcp, PT_IAOQ0, &pc) < 0) {
Denys Vlasenko60fe8c12011-09-01 10:00:28 +02001162 tprints("[????????] ");
Wichert Akkermanc1652e22001-03-27 12:17:16 +00001163 return;
1164 }
1165 tprintf("[%08lx] ", pc);
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001166# elif defined(MIPS)
Wichert Akkerman75c422b2001-04-10 10:22:50 +00001167 long pc;
1168
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001169 if (upeek(tcp, REG_EPC, &pc) < 0) {
Denys Vlasenko60fe8c12011-09-01 10:00:28 +02001170 tprints("[????????] ");
Wichert Akkerman75c422b2001-04-10 10:22:50 +00001171 return;
1172 }
1173 tprintf("[%08lx] ", pc);
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001174# elif defined(SH)
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001175 long pc;
Wichert Akkermanccef6372002-05-01 16:39:22 +00001176
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001177 if (upeek(tcp, 4*REG_PC, &pc) < 0) {
Denys Vlasenko60fe8c12011-09-01 10:00:28 +02001178 tprints("[????????] ");
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001179 return;
1180 }
1181 tprintf("[%08lx] ", pc);
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001182# elif defined(SH64)
Roland McGrathe1e584b2003-06-02 19:18:58 +00001183 long pc;
1184
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001185 if (upeek(tcp, REG_PC, &pc) < 0) {
Denys Vlasenko60fe8c12011-09-01 10:00:28 +02001186 tprints("[????????????????] ");
Roland McGrathe1e584b2003-06-02 19:18:58 +00001187 return;
1188 }
1189 tprintf("[%08lx] ", pc);
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001190# elif defined(ARM)
Roland McGrathef388682003-06-03 23:28:59 +00001191 long pc;
Roland McGrathe1e584b2003-06-02 19:18:58 +00001192
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001193 if (upeek(tcp, 4*15, &pc) < 0) {
Roland McGrath7a918832005-02-02 20:55:23 +00001194 PRINTBADPC;
Roland McGrathef388682003-06-03 23:28:59 +00001195 return;
1196 }
1197 tprintf("[%08lx] ", pc);
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00001198# elif defined(AVR32)
1199 long pc;
1200
1201 if (upeek(tcp, REG_PC, &pc) < 0) {
Denys Vlasenko60fe8c12011-09-01 10:00:28 +02001202 tprints("[????????] ");
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00001203 return;
1204 }
1205 tprintf("[%08lx] ", pc);
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001206# elif defined(BFIN)
Dmitry V. Levin87ea1f42008-11-10 22:21:41 +00001207 long pc;
1208
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001209 if (upeek(tcp, PT_PC, &pc) < 0) {
Dmitry V. Levin87ea1f42008-11-10 22:21:41 +00001210 PRINTBADPC;
1211 return;
1212 }
1213 tprintf("[%08lx] ", pc);
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001214#elif defined(CRISV10)
1215 long pc;
1216
Edgar E. Iglesiaseeb9ce32009-10-05 14:41:02 +00001217 if (upeek(tcp, 4*PT_IRP, &pc) < 0) {
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001218 PRINTBADPC;
1219 return;
1220 }
1221 tprintf("[%08lx] ", pc);
1222#elif defined(CRISV32)
1223 long pc;
1224
Edgar E. Iglesiaseeb9ce32009-10-05 14:41:02 +00001225 if (upeek(tcp, 4*PT_ERP, &pc) < 0) {
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001226 PRINTBADPC;
1227 return;
1228 }
1229 tprintf("[%08lx] ", pc);
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001230# endif /* architecture */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001231#endif /* LINUX */
1232
1233#ifdef SUNOS4
1234 struct regs regs;
1235
Roland McGratheb9e2e82009-06-02 16:49:22 -07001236 if (ptrace(PTRACE_GETREGS, tcp->pid, (char *) &regs, 0) < 0) {
1237 perror("printcall: ptrace(PTRACE_GETREGS, ...)");
Roland McGrath7a918832005-02-02 20:55:23 +00001238 PRINTBADPC;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001239 return;
1240 }
1241 tprintf("[%08x] ", regs.r_o7);
1242#endif /* SUNOS4 */
1243
1244#ifdef SVR4
1245 /* XXX */
Roland McGrath7a918832005-02-02 20:55:23 +00001246 PRINTBADPC;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001247#endif
1248
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001249#ifdef FREEBSD
1250 struct reg regs;
1251 pread(tcp->pfd_reg, &regs, sizeof(regs), 0);
1252 tprintf("[%08x] ", regs.r_eip);
1253#endif /* FREEBSD */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001254}
1255
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001256
1257/*
1258 * These #if's are huge, please indent them correctly.
1259 * It's easy to get confused otherwise.
1260 */
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001261#ifndef USE_PROCFS
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001262
Denys Vlasenkoe7c90242011-06-22 00:09:25 +02001263# ifdef LINUX
Roland McGrathd81f1d92003-01-09 06:53:34 +00001264
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001265# include "syscall.h"
Roland McGrath3291ef22008-05-20 00:34:34 +00001266
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001267# include <sys/syscall.h>
1268# ifndef CLONE_PTRACE
1269# define CLONE_PTRACE 0x00002000
1270# endif
1271# ifndef CLONE_VFORK
1272# define CLONE_VFORK 0x00004000
1273# endif
1274# ifndef CLONE_VM
1275# define CLONE_VM 0x00000100
1276# endif
1277# ifndef CLONE_STOPPED
1278# define CLONE_STOPPED 0x02000000
1279# endif
Roland McGrathd81f1d92003-01-09 06:53:34 +00001280
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001281# ifdef IA64
Roland McGrathd81f1d92003-01-09 06:53:34 +00001282
Roland McGrath08267b82004-02-20 22:56:43 +00001283/* We don't have fork()/vfork() syscalls on ia64 itself, but the ia32
1284 subsystem has them for x86... */
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001285# define SYS_fork 2
1286# define SYS_vfork 190
Roland McGrath08267b82004-02-20 22:56:43 +00001287
Roland McGrathd81f1d92003-01-09 06:53:34 +00001288typedef unsigned long *arg_setup_state;
1289
1290static int
1291arg_setup(struct tcb *tcp, arg_setup_state *state)
1292{
Jan Kratochvil1f942712008-08-06 21:38:52 +00001293 unsigned long cfm, sof, sol;
1294 long bsp;
Roland McGrathd81f1d92003-01-09 06:53:34 +00001295
Jan Kratochvil1f942712008-08-06 21:38:52 +00001296 if (ia32) {
1297 /* Satisfy a false GCC warning. */
1298 *state = NULL;
Roland McGrath08267b82004-02-20 22:56:43 +00001299 return 0;
Jan Kratochvil1f942712008-08-06 21:38:52 +00001300 }
Roland McGrath08267b82004-02-20 22:56:43 +00001301
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001302 if (upeek(tcp, PT_AR_BSP, &bsp) < 0)
Roland McGrathd81f1d92003-01-09 06:53:34 +00001303 return -1;
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001304 if (upeek(tcp, PT_CFM, (long *) &cfm) < 0)
Roland McGrathd81f1d92003-01-09 06:53:34 +00001305 return -1;
1306
1307 sof = (cfm >> 0) & 0x7f;
1308 sol = (cfm >> 7) & 0x7f;
Jan Kratochvil1f942712008-08-06 21:38:52 +00001309 bsp = (long) ia64_rse_skip_regs((unsigned long *) bsp, -sof + sol);
Roland McGrathd81f1d92003-01-09 06:53:34 +00001310
Jan Kratochvil1f942712008-08-06 21:38:52 +00001311 *state = (unsigned long *) bsp;
Roland McGrathd81f1d92003-01-09 06:53:34 +00001312 return 0;
1313}
1314
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001315# define arg_finish_change(tcp, state) 0
Roland McGrathd81f1d92003-01-09 06:53:34 +00001316
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001317# ifdef SYS_fork
Roland McGrathd81f1d92003-01-09 06:53:34 +00001318static int
Denys Vlasenko12014262011-05-30 14:00:14 +02001319get_arg0(struct tcb *tcp, arg_setup_state *state, long *valp)
Roland McGrathd81f1d92003-01-09 06:53:34 +00001320{
Roland McGrath08267b82004-02-20 22:56:43 +00001321 int ret;
1322
1323 if (ia32)
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001324 ret = upeek(tcp, PT_R11, valp);
Roland McGrath08267b82004-02-20 22:56:43 +00001325 else
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001326 ret = umoven(tcp,
Roland McGrath08267b82004-02-20 22:56:43 +00001327 (unsigned long) ia64_rse_skip_regs(*state, 0),
1328 sizeof(long), (void *) valp);
1329 return ret;
Roland McGrathd81f1d92003-01-09 06:53:34 +00001330}
1331
1332static int
Denys Vlasenko12014262011-05-30 14:00:14 +02001333get_arg1(struct tcb *tcp, arg_setup_state *state, long *valp)
Roland McGrathd81f1d92003-01-09 06:53:34 +00001334{
Roland McGrath08267b82004-02-20 22:56:43 +00001335 int ret;
1336
1337 if (ia32)
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001338 ret = upeek(tcp, PT_R9, valp);
Roland McGrath08267b82004-02-20 22:56:43 +00001339 else
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001340 ret = umoven(tcp,
Roland McGrath08267b82004-02-20 22:56:43 +00001341 (unsigned long) ia64_rse_skip_regs(*state, 1),
1342 sizeof(long), (void *) valp);
1343 return ret;
Roland McGrathd81f1d92003-01-09 06:53:34 +00001344}
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001345# endif
Roland McGrathd81f1d92003-01-09 06:53:34 +00001346
1347static int
Denys Vlasenko12014262011-05-30 14:00:14 +02001348set_arg0(struct tcb *tcp, arg_setup_state *state, long val)
Roland McGrathd81f1d92003-01-09 06:53:34 +00001349{
Roland McGrath08267b82004-02-20 22:56:43 +00001350 int req = PTRACE_POKEDATA;
1351 void *ap;
1352
1353 if (ia32) {
1354 ap = (void *) (intptr_t) PT_R11; /* r11 == EBX */
1355 req = PTRACE_POKEUSER;
1356 } else
1357 ap = ia64_rse_skip_regs(*state, 0);
Roland McGratheb9e2e82009-06-02 16:49:22 -07001358 errno = 0;
1359 ptrace(req, tcp->pid, ap, val);
1360 return errno ? -1 : 0;
Roland McGrathd81f1d92003-01-09 06:53:34 +00001361}
1362
1363static int
Denys Vlasenko12014262011-05-30 14:00:14 +02001364set_arg1(struct tcb *tcp, arg_setup_state *state, long val)
Roland McGrathd81f1d92003-01-09 06:53:34 +00001365{
Roland McGrath08267b82004-02-20 22:56:43 +00001366 int req = PTRACE_POKEDATA;
1367 void *ap;
1368
1369 if (ia32) {
1370 ap = (void *) (intptr_t) PT_R9; /* r9 == ECX */
1371 req = PTRACE_POKEUSER;
1372 } else
1373 ap = ia64_rse_skip_regs(*state, 1);
Roland McGratheb9e2e82009-06-02 16:49:22 -07001374 errno = 0;
1375 ptrace(req, tcp->pid, ap, val);
1376 return errno ? -1 : 0;
Roland McGrathd81f1d92003-01-09 06:53:34 +00001377}
1378
Roland McGrathb659f872008-07-18 01:19:36 +00001379/* ia64 does not return the input arguments from functions (and syscalls)
1380 according to ia64 RSE (Register Stack Engine) behavior. */
1381
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001382# define restore_arg0(tcp, state, val) ((void) (state), 0)
1383# define restore_arg1(tcp, state, val) ((void) (state), 0)
Roland McGrathb659f872008-07-18 01:19:36 +00001384
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001385# elif defined (SPARC) || defined (SPARC64)
Roland McGrathd81f1d92003-01-09 06:53:34 +00001386
Mike Frysinger8566c502009-10-12 11:05:14 -04001387typedef struct pt_regs arg_setup_state;
Roland McGrathd81f1d92003-01-09 06:53:34 +00001388
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001389# define arg_setup(tcp, state) \
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001390 (ptrace(PTRACE_GETREGS, tcp->pid, (char *) (state), 0))
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001391# define arg_finish_change(tcp, state) \
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001392 (ptrace(PTRACE_SETREGS, tcp->pid, (char *) (state), 0))
Roland McGrathd81f1d92003-01-09 06:53:34 +00001393
Mike Frysinger8566c502009-10-12 11:05:14 -04001394# define get_arg0(tcp, state, valp) (*(valp) = (state)->u_regs[U_REG_O0], 0)
1395# define get_arg1(tcp, state, valp) (*(valp) = (state)->u_regs[U_REG_O1], 0)
1396# define set_arg0(tcp, state, val) ((state)->u_regs[U_REG_O0] = (val), 0)
1397# define set_arg1(tcp, state, val) ((state)->u_regs[U_REG_O1] = (val), 0)
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001398# define restore_arg0(tcp, state, val) 0
Roland McGrathd81f1d92003-01-09 06:53:34 +00001399
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001400# else /* other architectures */
Roland McGrathd81f1d92003-01-09 06:53:34 +00001401
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001402# if defined S390 || defined S390X
Roland McGrath7b308222003-01-20 09:04:36 +00001403/* Note: this is only true for the `clone' system call, which handles
1404 arguments specially. We could as well say that its first two arguments
1405 are swapped relative to other architectures, but that would just be
1406 another #ifdef in the calls. */
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001407# define arg0_offset PT_GPR3
1408# define arg1_offset PT_ORIGGPR2
1409# define restore_arg0(tcp, state, val) ((void) (state), 0)
1410# define restore_arg1(tcp, state, val) ((void) (state), 0)
1411# define arg0_index 1
1412# define arg1_index 0
1413# elif defined (ALPHA) || defined (MIPS)
1414# define arg0_offset REG_A0
1415# define arg1_offset (REG_A0+1)
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00001416# elif defined (AVR32)
1417# define arg0_offset (REG_R12)
1418# define arg1_offset (REG_R11)
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001419# elif defined (POWERPC)
1420# define arg0_offset (sizeof(unsigned long)*PT_R3)
1421# define arg1_offset (sizeof(unsigned long)*PT_R4)
1422# define restore_arg0(tcp, state, val) ((void) (state), 0)
1423# elif defined (HPPA)
1424# define arg0_offset PT_GR26
1425# define arg1_offset (PT_GR26-4)
1426# elif defined (X86_64)
1427# define arg0_offset ((long)(8*(current_personality ? RBX : RDI)))
1428# define arg1_offset ((long)(8*(current_personality ? RCX : RSI)))
1429# elif defined (SH)
1430# define arg0_offset (4*(REG_REG0+4))
1431# define arg1_offset (4*(REG_REG0+5))
1432# elif defined (SH64)
1433 /* ABI defines arg0 & 1 in r2 & r3 */
1434# define arg0_offset (REG_OFFSET+16)
1435# define arg1_offset (REG_OFFSET+24)
1436# define restore_arg0(tcp, state, val) 0
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001437# elif defined CRISV10 || defined CRISV32
1438# define arg0_offset (4*PT_R11)
1439# define arg1_offset (4*PT_ORIG_R10)
1440# define restore_arg0(tcp, state, val) 0
1441# define restore_arg1(tcp, state, val) 0
1442# define arg0_index 1
1443# define arg1_index 0
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001444# else
1445# define arg0_offset 0
1446# define arg1_offset 4
1447# if defined ARM
1448# define restore_arg0(tcp, state, val) 0
1449# endif
1450# endif
Roland McGrathd81f1d92003-01-09 06:53:34 +00001451
1452typedef int arg_setup_state;
1453
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001454# define arg_setup(tcp, state) (0)
1455# define arg_finish_change(tcp, state) 0
1456# define get_arg0(tcp, cookie, valp) \
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001457 (upeek((tcp), arg0_offset, (valp)))
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001458# define get_arg1(tcp, cookie, valp) \
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001459 (upeek((tcp), arg1_offset, (valp)))
Roland McGrathd81f1d92003-01-09 06:53:34 +00001460
1461static int
Denys Vlasenko12014262011-05-30 14:00:14 +02001462set_arg0(struct tcb *tcp, void *cookie, long val)
Roland McGrathd81f1d92003-01-09 06:53:34 +00001463{
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001464 return ptrace(PTRACE_POKEUSER, tcp->pid, (char*)arg0_offset, val);
Roland McGrathd81f1d92003-01-09 06:53:34 +00001465}
1466
1467static int
Denys Vlasenko12014262011-05-30 14:00:14 +02001468set_arg1(struct tcb *tcp, void *cookie, long val)
Roland McGrathd81f1d92003-01-09 06:53:34 +00001469{
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001470 return ptrace(PTRACE_POKEUSER, tcp->pid, (char*)arg1_offset, val);
Roland McGrathd81f1d92003-01-09 06:53:34 +00001471}
1472
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001473# endif /* architectures */
Roland McGrathd81f1d92003-01-09 06:53:34 +00001474
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001475# ifndef restore_arg0
1476# define restore_arg0(tcp, state, val) set_arg0((tcp), (state), (val))
1477# endif
1478# ifndef restore_arg1
1479# define restore_arg1(tcp, state, val) set_arg1((tcp), (state), (val))
1480# endif
Roland McGrathd81f1d92003-01-09 06:53:34 +00001481
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001482# ifndef arg0_index
1483# define arg0_index 0
1484# define arg1_index 1
1485# endif
Roland McGrath90d0afd2004-03-01 21:05:16 +00001486
Roland McGrathd81f1d92003-01-09 06:53:34 +00001487int
Denys Vlasenko418d66a2009-01-17 01:52:54 +00001488setbpt(struct tcb *tcp)
Roland McGrathd81f1d92003-01-09 06:53:34 +00001489{
Roland McGrath3291ef22008-05-20 00:34:34 +00001490 static int clone_scno[SUPPORTED_PERSONALITIES] = { SYS_clone };
Roland McGrathd81f1d92003-01-09 06:53:34 +00001491 arg_setup_state state;
1492
1493 if (tcp->flags & TCB_BPTSET) {
1494 fprintf(stderr, "PANIC: TCB already set in pid %u\n", tcp->pid);
1495 return -1;
1496 }
1497
Roland McGrath3291ef22008-05-20 00:34:34 +00001498 /*
1499 * It's a silly kludge to initialize this with a search at runtime.
1500 * But it's better than maintaining another magic thing in the
1501 * godforsaken tables.
1502 */
1503 if (clone_scno[current_personality] == 0) {
1504 int i;
1505 for (i = 0; i < nsyscalls; ++i)
1506 if (sysent[i].sys_func == sys_clone) {
1507 clone_scno[current_personality] = i;
1508 break;
1509 }
1510 }
1511
Roland McGrath76989d72005-06-07 23:21:31 +00001512 switch (known_scno(tcp)) {
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001513# ifdef SYS_vfork
Roland McGrath9383c6c2003-01-18 00:19:31 +00001514 case SYS_vfork:
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001515# endif
1516# ifdef SYS_fork
Roland McGrathd81f1d92003-01-09 06:53:34 +00001517 case SYS_fork:
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001518# endif
1519# if defined SYS_fork || defined SYS_vfork
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001520 if (arg_setup(tcp, &state) < 0
1521 || get_arg0(tcp, &state, &tcp->inst[0]) < 0
1522 || get_arg1(tcp, &state, &tcp->inst[1]) < 0
Roland McGrath3291ef22008-05-20 00:34:34 +00001523 || change_syscall(tcp, clone_scno[current_personality]) < 0
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001524 || set_arg0(tcp, &state, CLONE_PTRACE|SIGCHLD) < 0
1525 || set_arg1(tcp, &state, 0) < 0
1526 || arg_finish_change(tcp, &state) < 0)
Roland McGrathd81f1d92003-01-09 06:53:34 +00001527 return -1;
Roland McGrathc9dc3c12004-03-01 20:57:09 +00001528 tcp->u_arg[arg0_index] = CLONE_PTRACE|SIGCHLD;
1529 tcp->u_arg[arg1_index] = 0;
Roland McGrathd81f1d92003-01-09 06:53:34 +00001530 tcp->flags |= TCB_BPTSET;
1531 return 0;
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001532# endif
Roland McGrathd81f1d92003-01-09 06:53:34 +00001533
Denys Vlasenkoc133bf02011-06-23 21:57:54 +02001534 case SYS_clone: ;
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001535# ifdef SYS_clone2
Denys Vlasenkoc133bf02011-06-23 21:57:54 +02001536 case SYS_clone2: ;
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001537# endif
Jan Kratochvil8fc95752008-08-06 21:43:35 +00001538 /* ia64 calls directly `clone (CLONE_VFORK | CLONE_VM)'
1539 contrary to x86 SYS_vfork above. Even on x86 we turn the
1540 vfork semantics into plain fork - each application must not
1541 depend on the vfork specifics according to POSIX. We would
1542 hang waiting for the parent resume otherwise. We need to
1543 clear also CLONE_VM but only in the CLONE_VFORK case as
1544 otherwise we would break pthread_create. */
1545
Denys Vlasenkoc133bf02011-06-23 21:57:54 +02001546 long new_arg0 = (tcp->u_arg[arg0_index] | CLONE_PTRACE);
1547 if (new_arg0 & CLONE_VFORK)
1548 new_arg0 &= ~(unsigned long)(CLONE_VFORK | CLONE_VM);
1549 if (arg_setup(tcp, &state) < 0
1550 || set_arg0(tcp, &state, new_arg0) < 0
1551 || arg_finish_change(tcp, &state) < 0)
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00001552 return -1;
Roland McGrathd81f1d92003-01-09 06:53:34 +00001553 tcp->flags |= TCB_BPTSET;
Roland McGrathc9dc3c12004-03-01 20:57:09 +00001554 tcp->inst[0] = tcp->u_arg[arg0_index];
1555 tcp->inst[1] = tcp->u_arg[arg1_index];
Roland McGrathd81f1d92003-01-09 06:53:34 +00001556 return 0;
1557
1558 default:
1559 fprintf(stderr, "PANIC: setbpt for syscall %ld on %u???\n",
1560 tcp->scno, tcp->pid);
1561 break;
1562 }
1563
1564 return -1;
1565}
1566
1567int
Denys Vlasenko12014262011-05-30 14:00:14 +02001568clearbpt(struct tcb *tcp)
Roland McGrathd81f1d92003-01-09 06:53:34 +00001569{
1570 arg_setup_state state;
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001571 if (arg_setup(tcp, &state) < 0
1572 || restore_arg0(tcp, &state, tcp->inst[0]) < 0
1573 || restore_arg1(tcp, &state, tcp->inst[1]) < 0
1574 || arg_finish_change(tcp, &state))
Denys Vlasenkoc133bf02011-06-23 21:57:54 +02001575 if (errno != ESRCH)
1576 return -1;
Roland McGrathd81f1d92003-01-09 06:53:34 +00001577 tcp->flags &= ~TCB_BPTSET;
1578 return 0;
1579}
1580
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001581# else /* !defined LINUX */
Roland McGrathd81f1d92003-01-09 06:53:34 +00001582
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001583int
Denys Vlasenko12014262011-05-30 14:00:14 +02001584setbpt(struct tcb *tcp)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001585{
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001586# ifdef SUNOS4
1587# ifdef SPARC /* This code is slightly sparc specific */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001588
Wichert Akkermane6f876c1999-06-22 15:28:30 +00001589 struct regs regs;
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001590# define BPT 0x91d02001 /* ta 1 */
1591# define LOOP 0x10800000 /* ba 0 */
1592# define LOOPA 0x30800000 /* ba,a 0 */
1593# define NOP 0x01000000
1594# if LOOPA
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001595 static int loopdeloop[1] = {LOOPA};
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001596# else
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001597 static int loopdeloop[2] = {LOOP, NOP};
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001598# endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001599
1600 if (tcp->flags & TCB_BPTSET) {
1601 fprintf(stderr, "PANIC: TCB already set in pid %u\n", tcp->pid);
1602 return -1;
1603 }
Roland McGratheb9e2e82009-06-02 16:49:22 -07001604 if (ptrace(PTRACE_GETREGS, tcp->pid, (char *)&regs, 0) < 0) {
1605 perror("setbpt: ptrace(PTRACE_GETREGS, ...)");
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001606 return -1;
1607 }
1608 tcp->baddr = regs.r_o7 + 8;
Roland McGratheb9e2e82009-06-02 16:49:22 -07001609 if (ptrace(PTRACE_READTEXT, tcp->pid, (char *)tcp->baddr,
1610 sizeof tcp->inst, (char *)tcp->inst) < 0) {
1611 perror("setbpt: ptrace(PTRACE_READTEXT, ...)");
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001612 return -1;
1613 }
1614
1615 /*
1616 * XXX - BRUTAL MODE ON
1617 * We cannot set a real BPT in the child, since it will not be
1618 * traced at the moment it will reach the trap and would probably
1619 * die with a core dump.
1620 * Thus, we are force our way in by taking out two instructions
1621 * and insert an eternal loop in stead, in expectance of the SIGSTOP
1622 * generated by out PTRACE_ATTACH.
1623 * Of cause, if we evaporate ourselves in the middle of all this...
1624 */
Roland McGratheb9e2e82009-06-02 16:49:22 -07001625 if (ptrace(PTRACE_WRITETEXT, tcp->pid, (char *) tcp->baddr,
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001626 sizeof loopdeloop, (char *) loopdeloop) < 0) {
Roland McGratheb9e2e82009-06-02 16:49:22 -07001627 perror("setbpt: ptrace(PTRACE_WRITETEXT, ...)");
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001628 return -1;
1629 }
1630 tcp->flags |= TCB_BPTSET;
1631
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001632# endif /* SPARC */
1633# endif /* SUNOS4 */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001634
1635 return 0;
1636}
1637
1638int
Denys Vlasenko12014262011-05-30 14:00:14 +02001639clearbpt(struct tcb *tcp)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001640{
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001641# ifdef SUNOS4
1642# ifdef SPARC
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001643
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001644# if !LOOPA
Wichert Akkermane6f876c1999-06-22 15:28:30 +00001645 struct regs regs;
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001646# endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001647
1648 if (!(tcp->flags & TCB_BPTSET)) {
1649 fprintf(stderr, "PANIC: TCB not set in pid %u\n", tcp->pid);
1650 return -1;
1651 }
Roland McGratheb9e2e82009-06-02 16:49:22 -07001652 if (ptrace(PTRACE_WRITETEXT, tcp->pid, (char *) tcp->baddr,
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001653 sizeof tcp->inst, (char *) tcp->inst) < 0) {
Roland McGratheb9e2e82009-06-02 16:49:22 -07001654 perror("clearbtp: ptrace(PTRACE_WRITETEXT, ...)");
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001655 return -1;
1656 }
1657 tcp->flags &= ~TCB_BPTSET;
1658
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001659# if !LOOPA
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001660 /*
1661 * Since we don't have a single instruction breakpoint, we may have
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001662 * to adjust the program counter after removing our `breakpoint'.
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001663 */
Roland McGratheb9e2e82009-06-02 16:49:22 -07001664 if (ptrace(PTRACE_GETREGS, tcp->pid, (char *)&regs, 0) < 0) {
1665 perror("clearbpt: ptrace(PTRACE_GETREGS, ...)");
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001666 return -1;
1667 }
Roland McGratheb9e2e82009-06-02 16:49:22 -07001668 if ((regs.r_pc < tcp->baddr) ||
1669 (regs.r_pc > tcp->baddr + 4)) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001670 /* The breakpoint has not been reached yet */
1671 if (debug)
1672 fprintf(stderr,
1673 "NOTE: PC not at bpt (pc %#x baddr %#x)\n",
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001674 regs.r_pc, tcp->baddr);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001675 return 0;
1676 }
1677 if (regs.r_pc != tcp->baddr)
1678 if (debug)
1679 fprintf(stderr, "NOTE: PC adjusted (%#x -> %#x\n",
1680 regs.r_pc, tcp->baddr);
1681
1682 regs.r_pc = tcp->baddr;
Roland McGratheb9e2e82009-06-02 16:49:22 -07001683 if (ptrace(PTRACE_SETREGS, tcp->pid, (char *)&regs, 0) < 0) {
1684 perror("clearbpt: ptrace(PTRACE_SETREGS, ...)");
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001685 return -1;
1686 }
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001687# endif /* LOOPA */
1688# endif /* SPARC */
1689# endif /* SUNOS4 */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001690
1691 return 0;
1692}
1693
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001694# endif /* !defined LINUX */
Roland McGrathd81f1d92003-01-09 06:53:34 +00001695
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001696#endif /* !USE_PROCFS */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001697
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001698
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001699#ifdef SUNOS4
1700
1701static int
Denys Vlasenko12014262011-05-30 14:00:14 +02001702getex(struct tcb *tcp, struct exec *hdr)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001703{
1704 int n;
1705
1706 for (n = 0; n < sizeof *hdr; n += 4) {
1707 long res;
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001708 if (upeek(tcp, uoff(u_exdata) + n, &res) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001709 return -1;
1710 memcpy(((char *) hdr) + n, &res, 4);
1711 }
1712 if (debug) {
1713 fprintf(stderr, "[struct exec: magic: %o version %u Mach %o\n",
1714 hdr->a_magic, hdr->a_toolversion, hdr->a_machtype);
1715 fprintf(stderr, "Text %lu Data %lu Bss %lu Syms %lu Entry %#lx]\n",
1716 hdr->a_text, hdr->a_data, hdr->a_bss, hdr->a_syms, hdr->a_entry);
1717 }
1718 return 0;
1719}
1720
1721int
Denys Vlasenko12014262011-05-30 14:00:14 +02001722fixvfork(struct tcb *tcp)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001723{
1724 int pid = tcp->pid;
1725 /*
1726 * Change `vfork' in a freshly exec'ed dynamically linked
1727 * executable's (internal) symbol table to plain old `fork'
1728 */
1729
1730 struct exec hdr;
1731 struct link_dynamic dyn;
1732 struct link_dynamic_2 ld;
1733 char *strtab, *cp;
1734
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001735 if (getex(tcp, &hdr) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001736 return -1;
1737 if (!hdr.a_dynamic)
1738 return -1;
1739
1740 if (umove(tcp, (int) N_DATADDR(hdr), &dyn) < 0) {
1741 fprintf(stderr, "Cannot read DYNAMIC\n");
1742 return -1;
1743 }
1744 if (umove(tcp, (int) dyn.ld_un.ld_2, &ld) < 0) {
1745 fprintf(stderr, "Cannot read link_dynamic_2\n");
1746 return -1;
1747 }
Denys Vlasenko5d645812011-08-20 12:48:18 +02001748 strtab = malloc((unsigned)ld.ld_symb_size);
Denys Vlasenko1d46ba52011-08-31 14:00:02 +02001749 if (!strtab)
1750 die_out_of_memory();
Roland McGratheb9e2e82009-06-02 16:49:22 -07001751 if (umoven(tcp, (int)ld.ld_symbols+(int)N_TXTADDR(hdr),
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001752 (int)ld.ld_symb_size, strtab) < 0)
1753 goto err;
1754
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001755 for (cp = strtab; cp < strtab + ld.ld_symb_size; ) {
1756 if (strcmp(cp, "_vfork") == 0) {
1757 if (debug)
1758 fprintf(stderr, "fixvfork: FOUND _vfork\n");
1759 strcpy(cp, "_fork");
1760 break;
1761 }
1762 cp += strlen(cp)+1;
1763 }
1764 if (cp < strtab + ld.ld_symb_size)
1765 /*
1766 * Write entire symbol table back to avoid
1767 * memory alignment bugs in ptrace
1768 */
Roland McGratheb9e2e82009-06-02 16:49:22 -07001769 if (tload(pid, (int)ld.ld_symbols+(int)N_TXTADDR(hdr),
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001770 (int)ld.ld_symb_size, strtab) < 0)
1771 goto err;
1772
1773 free(strtab);
1774 return 0;
1775
1776err:
1777 free(strtab);
1778 return -1;
1779}
1780
1781#endif /* SUNOS4 */