blob: 0277deb8bdc5c7bc5902ec73e570112f12318a1c [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 Vlasenko52845572011-08-31 12:07:38 +0200167char *
168stpcpy(char *dst, const char *src)
169{
170 while ((*dst = *src++) != '\0')
171 dst++;
172 return dst;
173}
174
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000175/*
Roland McGratheb9e2e82009-06-02 16:49:22 -0700176 * Generic ptrace wrapper which tracks ESRCH errors
177 * by setting tcp->ptrace_errno to ESRCH.
Denys Vlasenko732d1bf2008-12-17 19:21:59 +0000178 *
179 * We assume that ESRCH indicates likely process death (SIGKILL?),
180 * modulo bugs where process somehow ended up not stopped.
181 * Unfortunately kernel uses ESRCH for that case too. Oh well.
Roland McGratheb9e2e82009-06-02 16:49:22 -0700182 *
183 * Currently used by upeek() only.
184 * TODO: use this in all other ptrace() calls while decoding.
Denys Vlasenko732d1bf2008-12-17 19:21:59 +0000185 */
Denys Vlasenko4dedd562009-02-24 15:17:53 +0000186long
Roland McGratheb9e2e82009-06-02 16:49:22 -0700187do_ptrace(int request, struct tcb *tcp, void *addr, void *data)
Denys Vlasenko4dedd562009-02-24 15:17:53 +0000188{
Denys Vlasenko732d1bf2008-12-17 19:21:59 +0000189 long l;
190
191 errno = 0;
Mike Frysinger09a13c22009-10-07 01:13:39 -0400192 l = ptrace(request, tcp->pid, addr, (long) data);
Roland McGratheb9e2e82009-06-02 16:49:22 -0700193 /* Non-ESRCH errors might be our invalid reg/mem accesses,
194 * we do not record them. */
195 if (errno == ESRCH)
196 tcp->ptrace_errno = ESRCH;
Denys Vlasenko732d1bf2008-12-17 19:21:59 +0000197 return l;
198}
199
200/*
201 * Used when we want to unblock stopped traced process.
202 * Should be only used with PTRACE_CONT, PTRACE_DETACH and PTRACE_SYSCALL.
203 * Returns 0 on success or if error was ESRCH
204 * (presumably process was killed while we talk to it).
205 * Otherwise prints error message and returns -1.
206 */
207int
Roland McGratheb9e2e82009-06-02 16:49:22 -0700208ptrace_restart(int op, struct tcb *tcp, int sig)
Denys Vlasenko732d1bf2008-12-17 19:21:59 +0000209{
210 int err;
Roland McGratheb9e2e82009-06-02 16:49:22 -0700211 const char *msg;
Denys Vlasenko732d1bf2008-12-17 19:21:59 +0000212
213 errno = 0;
Mike Frysinger09a13c22009-10-07 01:13:39 -0400214 ptrace(op, tcp->pid, (void *) 1, (long) sig);
Denys Vlasenko732d1bf2008-12-17 19:21:59 +0000215 err = errno;
216 if (!err || err == ESRCH)
217 return 0;
218
219 tcp->ptrace_errno = err;
Roland McGratheb9e2e82009-06-02 16:49:22 -0700220 msg = "SYSCALL";
221 if (op == PTRACE_CONT)
222 msg = "CONT";
223 if (op == PTRACE_DETACH)
224 msg = "DETACH";
225 fprintf(stderr, "strace: ptrace(PTRACE_%s,1,%d): %s\n",
226 msg, sig, strerror(err));
Denys Vlasenko732d1bf2008-12-17 19:21:59 +0000227 return -1;
228}
229
230/*
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000231 * Print entry in struct xlat table, if there.
232 */
233void
Dmitry V. Levinab9008b2007-01-11 22:05:04 +0000234printxval(const struct xlat *xlat, int val, const char *dflt)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000235{
Dmitry V. Levinab9008b2007-01-11 22:05:04 +0000236 const char *str = xlookup(xlat, val);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000237
238 if (str)
Denys Vlasenko5940e652011-09-01 09:55:05 +0200239 tprints(str);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000240 else
241 tprintf("%#x /* %s */", val, dflt);
242}
243
Andreas Schwabb5600fc2009-11-04 17:08:34 +0100244#if HAVE_LONG_LONG
245/*
246 * Print 64bit argument at position llarg and return the index of the next
247 * argument.
248 */
249int
250printllval(struct tcb *tcp, const char *format, int llarg)
251{
252# if defined(FREEBSD) \
Andreas Schwabd69fa492010-07-12 21:39:57 +0200253 || (defined(LINUX) && defined(POWERPC) && !defined(POWERPC64)) \
Dmitry V. Levin7a5b08f2011-05-28 20:47:43 +0000254 || defined(LINUX_MIPSO32) \
255 || defined(__ARM_EABI__)
Andreas Schwabb5600fc2009-11-04 17:08:34 +0100256 /* Align 64bit argument to 64bit boundary. */
Denys Vlasenko4b08df42011-08-19 15:58:24 +0200257 llarg = (llarg + 1) & 0x1e;
Andreas Schwabb5600fc2009-11-04 17:08:34 +0100258# endif
Andreas Schwabd69fa492010-07-12 21:39:57 +0200259# if defined LINUX && (defined X86_64 || defined POWERPC64)
Andreas Schwabb5600fc2009-11-04 17:08:34 +0100260 if (current_personality == 0) {
261 tprintf(format, tcp->u_arg[llarg]);
262 llarg++;
263 } else {
Andreas Schwabd69fa492010-07-12 21:39:57 +0200264# ifdef POWERPC64
265 /* Align 64bit argument to 64bit boundary. */
Denys Vlasenko4b08df42011-08-19 15:58:24 +0200266 llarg = (llarg + 1) & 0x1e;
Andreas Schwabd69fa492010-07-12 21:39:57 +0200267# endif
Andreas Schwabb5600fc2009-11-04 17:08:34 +0100268 tprintf(format, LONG_LONG(tcp->u_arg[llarg], tcp->u_arg[llarg + 1]));
269 llarg += 2;
270 }
Andreas Schwabd69fa492010-07-12 21:39:57 +0200271# elif defined IA64 || defined ALPHA
Andreas Schwabb5600fc2009-11-04 17:08:34 +0100272 tprintf(format, tcp->u_arg[llarg]);
273 llarg++;
274# elif defined LINUX_MIPSN32
275 tprintf(format, tcp->ext_arg[llarg]);
276 llarg++;
277# else
278 tprintf(format, LONG_LONG(tcp->u_arg[llarg], tcp->u_arg[llarg + 1]));
279 llarg += 2;
280# endif
281 return llarg;
282}
283#endif
284
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000285/*
286 * Interpret `xlat' as an array of flags
287 * print the entries whose bits are on in `flags'
288 * return # of flags printed.
289 */
Denys Vlasenko4924dbd2011-08-19 18:06:46 +0200290void
Denys Vlasenko12014262011-05-30 14:00:14 +0200291addflags(const struct xlat *xlat, int flags)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000292{
Denys Vlasenko4924dbd2011-08-19 18:06:46 +0200293 for (; xlat->str; xlat++) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000294 if (xlat->val && (flags & xlat->val) == xlat->val) {
295 tprintf("|%s", xlat->str);
296 flags &= ~xlat->val;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000297 }
298 }
299 if (flags) {
300 tprintf("|%#x", flags);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000301 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000302}
303
Roland McGratha6c0d8c2007-11-01 21:46:22 +0000304/*
Denys Vlasenko4924dbd2011-08-19 18:06:46 +0200305 * Interpret `xlat' as an array of flags.
Roland McGratha6c0d8c2007-11-01 21:46:22 +0000306 * Print to static string the entries whose bits are on in `flags'
307 * Return static string.
308 */
309const char *
310sprintflags(const char *prefix, const struct xlat *xlat, int flags)
311{
312 static char outstr[1024];
Denys Vlasenko52845572011-08-31 12:07:38 +0200313 char *outptr;
Roland McGratha6c0d8c2007-11-01 21:46:22 +0000314 int found = 0;
315
Denys Vlasenko52845572011-08-31 12:07:38 +0200316 outptr = stpcpy(outstr, prefix);
Roland McGratha6c0d8c2007-11-01 21:46:22 +0000317
318 for (; xlat->str; xlat++) {
319 if ((flags & xlat->val) == xlat->val) {
320 if (found)
Denys Vlasenko52845572011-08-31 12:07:38 +0200321 *outptr++ = '|';
322 outptr = stpcpy(outptr, xlat->str);
Roland McGratha6c0d8c2007-11-01 21:46:22 +0000323 flags &= ~xlat->val;
324 found = 1;
325 }
326 }
327 if (flags) {
328 if (found)
Denys Vlasenko52845572011-08-31 12:07:38 +0200329 *outptr++ = '|';
330 outptr += sprintf(outptr, "%#x", flags);
Roland McGratha6c0d8c2007-11-01 21:46:22 +0000331 }
332
333 return outstr;
334}
335
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000336int
Dmitry V. Levin30145dd2010-09-06 22:08:24 +0000337printflags(const struct xlat *xlat, int flags, const char *dflt)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000338{
339 int n;
Dmitry V. Levin30145dd2010-09-06 22:08:24 +0000340 const char *sep;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000341
342 if (flags == 0 && xlat->val == 0) {
Denys Vlasenko5940e652011-09-01 09:55:05 +0200343 tprints(xlat->str);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000344 return 1;
345 }
346
347 sep = "";
348 for (n = 0; xlat->str; xlat++) {
349 if (xlat->val && (flags & xlat->val) == xlat->val) {
350 tprintf("%s%s", sep, xlat->str);
351 flags &= ~xlat->val;
352 sep = "|";
353 n++;
354 }
355 }
Roland McGrathb2dee132005-06-01 19:02:36 +0000356
357 if (n) {
358 if (flags) {
359 tprintf("%s%#x", sep, flags);
360 n++;
361 }
362 } else {
363 if (flags) {
364 tprintf("%#x", flags);
365 if (dflt)
366 tprintf(" /* %s */", dflt);
367 } else {
368 if (dflt)
Denys Vlasenko60fe8c12011-09-01 10:00:28 +0200369 tprints("0");
Roland McGrathb2dee132005-06-01 19:02:36 +0000370 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000371 }
Roland McGrathb2dee132005-06-01 19:02:36 +0000372
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000373 return n;
374}
375
376void
Dmitry V. Levin30145dd2010-09-06 22:08:24 +0000377printnum(struct tcb *tcp, long addr, const char *fmt)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000378{
Roland McGratheb285352003-01-14 09:59:00 +0000379 long num;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000380
381 if (!addr) {
Denys Vlasenko60fe8c12011-09-01 10:00:28 +0200382 tprints("NULL");
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000383 return;
384 }
385 if (umove(tcp, addr, &num) < 0) {
386 tprintf("%#lx", addr);
387 return;
388 }
Denys Vlasenko60fe8c12011-09-01 10:00:28 +0200389 tprints("[");
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000390 tprintf(fmt, num);
Denys Vlasenko60fe8c12011-09-01 10:00:28 +0200391 tprints("]");
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000392}
393
Roland McGrath6bc12202003-11-13 22:32:27 +0000394void
Dmitry V. Levin30145dd2010-09-06 22:08:24 +0000395printnum_int(struct tcb *tcp, long addr, const char *fmt)
Roland McGrath9814a942005-07-04 23:28:10 +0000396{
397 int num;
398
399 if (!addr) {
Denys Vlasenko60fe8c12011-09-01 10:00:28 +0200400 tprints("NULL");
Roland McGrath9814a942005-07-04 23:28:10 +0000401 return;
402 }
403 if (umove(tcp, addr, &num) < 0) {
404 tprintf("%#lx", addr);
405 return;
406 }
Denys Vlasenko60fe8c12011-09-01 10:00:28 +0200407 tprints("[");
Roland McGrath9814a942005-07-04 23:28:10 +0000408 tprintf(fmt, num);
Denys Vlasenko60fe8c12011-09-01 10:00:28 +0200409 tprints("]");
Roland McGrath9814a942005-07-04 23:28:10 +0000410}
411
412void
Dmitry V. Levin31382132011-03-04 05:08:02 +0300413printfd(struct tcb *tcp, int fd)
414{
Grant Edwards8a082772011-04-07 20:25:40 +0000415 const char *p;
416
417 if (show_fd_path && (p = getfdpath(tcp, fd)))
418 tprintf("%d<%s>", fd, p);
419 else
420 tprintf("%d", fd);
Dmitry V. Levin31382132011-03-04 05:08:02 +0300421}
422
423void
Denys Vlasenko12014262011-05-30 14:00:14 +0200424printuid(const char *text, unsigned long uid)
Roland McGrath6bc12202003-11-13 22:32:27 +0000425{
Denys Vlasenko5940e652011-09-01 09:55:05 +0200426 tprintf((uid == -1) ? "%s%ld" : "%s%lu", text, uid);
Roland McGrath6bc12202003-11-13 22:32:27 +0000427}
428
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000429static char path[MAXPATHLEN + 1];
430
Dmitry V. Levina501f142008-11-10 23:19:13 +0000431/*
432 * Quote string `instr' of length `size'
433 * Write up to (3 + `size' * 4) bytes to `outstr' buffer.
434 * If `len' < 0, treat `instr' as a NUL-terminated string
435 * and quote at most (`size' - 1) bytes.
436 */
Roland McGrath6d970322007-11-01 23:53:59 +0000437static int
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000438string_quote(const char *instr, char *outstr, int len, int size)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000439{
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000440 const unsigned char *ustr = (const unsigned char *) instr;
441 char *s = outstr;
Denys Vlasenko8778bff2011-08-31 12:22:56 +0200442 int usehex, c, i, eol;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000443
Denys Vlasenko8778bff2011-08-31 12:22:56 +0200444 eol = 0x100; /* this can never match a char */
445 if (len < 0) {
446 size--;
447 eol = '\0';
448 }
449
450 usehex = 0;
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000451 if (xflag > 1)
452 usehex = 1;
453 else if (xflag) {
Dmitry V. Levina501f142008-11-10 23:19:13 +0000454 /* Check for presence of symbol which require
455 to hex-quote the whole string. */
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000456 for (i = 0; i < size; ++i) {
457 c = ustr[i];
Dmitry V. Levina501f142008-11-10 23:19:13 +0000458 /* Check for NUL-terminated string. */
Denys Vlasenko8778bff2011-08-31 12:22:56 +0200459 if (c == eol)
460 break;
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000461 if (!isprint(c) && !isspace(c)) {
462 usehex = 1;
463 break;
464 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000465 }
466 }
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000467
468 *s++ = '\"';
469
470 if (usehex) {
Dmitry V. Levina501f142008-11-10 23:19:13 +0000471 /* Hex-quote the whole string. */
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000472 for (i = 0; i < size; ++i) {
473 c = ustr[i];
Dmitry V. Levina501f142008-11-10 23:19:13 +0000474 /* Check for NUL-terminated string. */
Denys Vlasenko8778bff2011-08-31 12:22:56 +0200475 if (c == eol)
476 goto asciz_ended;
477 *s++ = '\\';
478 *s++ = 'x';
479 *s++ = "0123456789abcdef"[c >> 4];
480 *s++ = "0123456789abcdef"[c & 0xf];
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000481 }
482 } else {
483 for (i = 0; i < size; ++i) {
484 c = ustr[i];
Dmitry V. Levina501f142008-11-10 23:19:13 +0000485 /* Check for NUL-terminated string. */
Denys Vlasenko8778bff2011-08-31 12:22:56 +0200486 if (c == eol)
487 goto asciz_ended;
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000488 switch (c) {
489 case '\"': case '\\':
490 *s++ = '\\';
491 *s++ = c;
492 break;
493 case '\f':
494 *s++ = '\\';
495 *s++ = 'f';
496 break;
497 case '\n':
498 *s++ = '\\';
499 *s++ = 'n';
500 break;
501 case '\r':
502 *s++ = '\\';
503 *s++ = 'r';
504 break;
505 case '\t':
506 *s++ = '\\';
507 *s++ = 't';
508 break;
509 case '\v':
510 *s++ = '\\';
511 *s++ = 'v';
512 break;
513 default:
514 if (isprint(c))
515 *s++ = c;
Denys Vlasenko8778bff2011-08-31 12:22:56 +0200516 else {
517 /* Print \octal */
518 *s++ = '\\';
519 if (i + 1 < size
520 && ustr[i + 1] >= '0'
521 && ustr[i + 1] <= '9'
522 ) {
523 /* Print \ooo */
524 *s++ = '0' + (c >> 6);
525 *s++ = '0' + ((c >> 3) & 0x7);
526 } else {
527 /* Print \[[o]o]o */
528 if ((c >> 3) != 0) {
529 if ((c >> 6) != 0)
530 *s++ = '0' + (c >> 6);
531 *s++ = '0' + ((c >> 3) & 0x7);
532 }
533 }
534 *s++ = '0' + (c & 0x7);
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000535 }
536 break;
537 }
538 }
539 }
540
541 *s++ = '\"';
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000542 *s = '\0';
Roland McGrath6d970322007-11-01 23:53:59 +0000543
Denys Vlasenko8778bff2011-08-31 12:22:56 +0200544 /* Return zero if we printed entire ASCIZ string (didn't truncate it) */
545 if (len < 0 && ustr[i] == '\0') {
546 /* We didn't see NUL yet (otherwise we'd jump to 'asciz_ended')
547 * but next char is NUL.
548 */
549 return 0;
550 }
551
552 return 1;
553
554 asciz_ended:
555 *s++ = '\"';
556 *s = '\0';
557 /* Return zero: we printed entire ASCIZ string (didn't truncate it) */
558 return 0;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000559}
560
Dmitry V. Levina501f142008-11-10 23:19:13 +0000561/*
562 * Print path string specified by address `addr' and length `n'.
563 * If path length exceeds `n', append `...' to the output.
564 */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000565void
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000566printpathn(struct tcb *tcp, long addr, int n)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000567{
Dmitry V. Levina501f142008-11-10 23:19:13 +0000568 if (!addr) {
Denys Vlasenko60fe8c12011-09-01 10:00:28 +0200569 tprints("NULL");
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000570 return;
571 }
572
Dmitry V. Levina501f142008-11-10 23:19:13 +0000573 /* Cap path length to the path buffer size,
574 and NUL-terminate the buffer. */
575 if (n > sizeof path - 1)
576 n = sizeof path - 1;
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000577 path[n] = '\0';
Dmitry V. Levina501f142008-11-10 23:19:13 +0000578
579 /* Fetch one byte more to find out whether path length > n. */
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000580 if (umovestr(tcp, addr, n + 1, path) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000581 tprintf("%#lx", addr);
582 else {
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000583 static char outstr[4*(sizeof path - 1) + sizeof "\"...\""];
Denys Vlasenko52845572011-08-31 12:07:38 +0200584 const char *fmt;
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000585 int trunc = (path[n] != '\0');
586
587 if (trunc)
588 path[n] = '\0';
Denys Vlasenko52845572011-08-31 12:07:38 +0200589 string_quote(path, outstr, -1, n + 1);
590 fmt = "%s";
Dmitry V. Levina501f142008-11-10 23:19:13 +0000591 if (trunc)
Denys Vlasenko52845572011-08-31 12:07:38 +0200592 fmt = "%s...";
593 tprintf(fmt, outstr);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000594 }
595}
596
597void
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000598printpath(struct tcb *tcp, long addr)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000599{
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000600 printpathn(tcp, addr, sizeof path - 1);
601}
602
Dmitry V. Levina501f142008-11-10 23:19:13 +0000603/*
604 * Print string specified by address `addr' and length `len'.
605 * If `len' < 0, treat the string as a NUL-terminated string.
606 * If string length exceeds `max_strlen', append `...' to the output.
607 */
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000608void
609printstr(struct tcb *tcp, long addr, int len)
610{
611 static char *str = NULL;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000612 static char *outstr;
Roland McGrath6d970322007-11-01 23:53:59 +0000613 int size;
Denys Vlasenko52845572011-08-31 12:07:38 +0200614 const char *fmt;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000615
616 if (!addr) {
Denys Vlasenko60fe8c12011-09-01 10:00:28 +0200617 tprints("NULL");
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000618 return;
619 }
Dmitry V. Levina501f142008-11-10 23:19:13 +0000620 /* Allocate static buffers if they are not allocated yet. */
Denys Vlasenko1d46ba52011-08-31 14:00:02 +0200621 if (!str) {
Dmitry V. Levina501f142008-11-10 23:19:13 +0000622 str = malloc(max_strlen + 1);
Denys Vlasenko1d46ba52011-08-31 14:00:02 +0200623 if (!str)
624 die_out_of_memory();
625 }
626 if (!outstr) {
Dmitry V. Levina501f142008-11-10 23:19:13 +0000627 outstr = malloc(4 * max_strlen + sizeof "\"...\"");
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 Vlasenko52845572011-08-31 12:07:38 +0200653 fmt = "%s";
Dmitry V. Levina501f142008-11-10 23:19:13 +0000654 if (string_quote(str, outstr, len, size) &&
655 (len < 0 || len > max_strlen))
Denys Vlasenko52845572011-08-31 12:07:38 +0200656 fmt = "%s...";
Roland McGratha503dcf2007-08-02 02:06:26 +0000657
Denys Vlasenko52845572011-08-31 12:07:38 +0200658 tprintf(fmt, outstr);
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;
Roland McGrathaa524c82005-06-01 19:22:06 +0000687 unsigned long size;
John Hughes1d08dcf2001-07-10 13:48:44 +0000688
Dmitry V. Levin4ebb4e32006-12-13 17:08:08 +0000689 size = sizeof_iov * (unsigned long) len;
Denys Vlasenko1d46ba52011-08-31 14:00:02 +0200690 if (size / sizeof_iov != len /* overflow? */
Dmitry V. Levin4ebb4e32006-12-13 17:08:08 +0000691 || (iov = malloc(size)) == NULL) {
Denys Vlasenko1d46ba52011-08-31 14:00:02 +0200692 die_out_of_memory();
John Hughes1d08dcf2001-07-10 13:48:44 +0000693 }
Roland McGrathaa524c82005-06-01 19:22:06 +0000694 if (umoven(tcp, addr, size, (char *) iov) >= 0) {
John Hughes1d08dcf2001-07-10 13:48:44 +0000695 for (i = 0; i < len; i++) {
Denys Vlasenkoadedb512008-12-30 18:47:55 +0000696 /* include the buffer number to make it easy to
697 * match up the trace with the source */
698 tprintf(" * %lu bytes in buffer %d\n",
699 (unsigned long)iov_iov_len(i), i);
700 dumpstr(tcp, (long) iov_iov_base(i),
701 iov_iov_len(i));
702 }
John Hughes1d08dcf2001-07-10 13:48:44 +0000703 }
704 free((char *) iov);
Dmitry V. Levin4ebb4e32006-12-13 17:08:08 +0000705#undef sizeof_iov
706#undef iov_iov_base
707#undef iov_iov_len
708#undef iov
John Hughes1d08dcf2001-07-10 13:48:44 +0000709}
710#endif
711
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000712void
Denys Vlasenko12014262011-05-30 14:00:14 +0200713dumpstr(struct tcb *tcp, long addr, int len)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000714{
715 static int strsize = -1;
716 static unsigned char *str;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000717 char *s;
718 int i, j;
719
720 if (strsize < len) {
Denys Vlasenko5d645812011-08-20 12:48:18 +0200721 free(str);
722 str = malloc(len);
Denys Vlasenko1d46ba52011-08-31 14:00:02 +0200723 if (!str)
724 die_out_of_memory();
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000725 strsize = len;
726 }
727
728 if (umoven(tcp, addr, len, (char *) str) < 0)
729 return;
730
731 for (i = 0; i < len; i += 16) {
Denys Vlasenko1d46ba52011-08-31 14:00:02 +0200732 char outstr[80];
733
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000734 s = outstr;
735 sprintf(s, " | %05x ", i);
736 s += 9;
737 for (j = 0; j < 16; j++) {
738 if (j == 8)
739 *s++ = ' ';
740 if (i + j < len) {
741 sprintf(s, " %02x", str[i + j]);
742 s += 3;
743 }
744 else {
745 *s++ = ' '; *s++ = ' '; *s++ = ' ';
746 }
747 }
748 *s++ = ' '; *s++ = ' ';
749 for (j = 0; j < 16; j++) {
750 if (j == 8)
751 *s++ = ' ';
752 if (i + j < len) {
753 if (isprint(str[i + j]))
754 *s++ = str[i + j];
755 else
756 *s++ = '.';
757 }
758 else
759 *s++ = ' ';
760 }
761 tprintf("%s |\n", outstr);
762 }
763}
764
765#define PAGMASK (~(PAGSIZ - 1))
766/*
767 * move `len' bytes of data from process `pid'
768 * at address `addr' to our space at `laddr'
769 */
770int
Denys Vlasenkoef2fbf82009-01-06 21:45:06 +0000771umoven(struct tcb *tcp, long addr, int len, char *laddr)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000772{
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000773#ifdef LINUX
Roland McGratheb9e2e82009-06-02 16:49:22 -0700774 int pid = tcp->pid;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000775 int n, m;
Wichert Akkerman5daa0281999-03-15 19:49:42 +0000776 int started = 0;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000777 union {
778 long val;
779 char x[sizeof(long)];
780 } u;
781
782 if (addr & (sizeof(long) - 1)) {
783 /* addr not a multiple of sizeof(long) */
784 n = addr - (addr & -sizeof(long)); /* residue */
785 addr &= -sizeof(long); /* residue */
Roland McGratheb9e2e82009-06-02 16:49:22 -0700786 errno = 0;
787 u.val = ptrace(PTRACE_PEEKDATA, pid, (char *) addr, 0);
788 if (errno) {
789 if (started && (errno==EPERM || errno==EIO)) {
790 /* Ran into 'end of memory' - stupid "printpath" */
791 return 0;
792 }
793 /* But if not started, we had a bogus address. */
794 if (addr != 0 && errno != EIO && errno != ESRCH)
795 perror("ptrace: umoven");
796 return -1;
797 }
Wichert Akkerman5daa0281999-03-15 19:49:42 +0000798 started = 1;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000799 memcpy(laddr, &u.x[n], m = MIN(sizeof(long) - n, len));
800 addr += sizeof(long), laddr += m, len -= m;
801 }
802 while (len) {
Roland McGratheb9e2e82009-06-02 16:49:22 -0700803 errno = 0;
804 u.val = ptrace(PTRACE_PEEKDATA, pid, (char *) addr, 0);
805 if (errno) {
806 if (started && (errno==EPERM || errno==EIO)) {
807 /* Ran into 'end of memory' - stupid "printpath" */
808 return 0;
809 }
810 if (addr != 0 && errno != EIO && errno != ESRCH)
811 perror("ptrace: umoven");
812 return -1;
813 }
Wichert Akkerman5daa0281999-03-15 19:49:42 +0000814 started = 1;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000815 memcpy(laddr, u.x, m = MIN(sizeof(long), len));
816 addr += sizeof(long), laddr += m, len -= m;
817 }
818#endif /* LINUX */
819
820#ifdef SUNOS4
821 int pid = tcp->pid;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000822 int n;
823
824 while (len) {
825 n = MIN(len, PAGSIZ);
826 n = MIN(n, ((addr + PAGSIZ) & PAGMASK) - addr);
Roland McGratheb9e2e82009-06-02 16:49:22 -0700827 if (ptrace(PTRACE_READDATA, pid,
828 (char *) addr, len, laddr) < 0) {
829 if (errno != ESRCH) {
830 perror("umoven: ptrace(PTRACE_READDATA, ...)");
831 abort();
832 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000833 return -1;
834 }
835 len -= n;
836 addr += n;
837 laddr += n;
838 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000839#endif /* SUNOS4 */
840
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000841#ifdef USE_PROCFS
Wichert Akkermanea78f0f1999-11-29 15:34:02 +0000842#ifdef HAVE_MP_PROCFS
John Hughesaa09c6b2001-05-15 14:53:43 +0000843 int fd = tcp->pfd_as;
Wichert Akkerman9ce1a631999-08-29 23:15:07 +0000844#else
John Hughesaa09c6b2001-05-15 14:53:43 +0000845 int fd = tcp->pfd;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000846#endif
John Hughesaa09c6b2001-05-15 14:53:43 +0000847 lseek(fd, addr, SEEK_SET);
848 if (read(fd, laddr, len) == -1)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000849 return -1;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000850#endif /* USE_PROCFS */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000851
852 return 0;
853}
854
855/*
856 * like `umove' but make the additional effort of looking
857 * for a terminating zero byte.
858 */
859int
Denys Vlasenkoef2fbf82009-01-06 21:45:06 +0000860umovestr(struct tcb *tcp, long addr, int len, char *laddr)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000861{
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000862#ifdef USE_PROCFS
John Hughesaa09c6b2001-05-15 14:53:43 +0000863#ifdef HAVE_MP_PROCFS
864 int fd = tcp->pfd_as;
865#else
866 int fd = tcp->pfd;
867#endif
868 /* Some systems (e.g. FreeBSD) can be upset if we read off the
869 end of valid memory, avoid this by trying to read up
870 to page boundaries. But we don't know what a page is (and
871 getpagesize(2) (if it exists) doesn't necessarily return
872 hardware page size). Assume all pages >= 1024 (a-historical
873 I know) */
874
Denys Vlasenkob63256e2011-06-07 12:13:24 +0200875 int page = 1024; /* How to find this? */
John Hughesaa09c6b2001-05-15 14:53:43 +0000876 int move = page - (addr & (page - 1));
877 int left = len;
878
879 lseek(fd, addr, SEEK_SET);
880
881 while (left) {
Denys Vlasenko5d645812011-08-20 12:48:18 +0200882 if (move > left)
883 move = left;
884 move = read(fd, laddr, move);
885 if (move <= 0)
John Hughesaa09c6b2001-05-15 14:53:43 +0000886 return left != len ? 0 : -1;
Denys Vlasenko5d645812011-08-20 12:48:18 +0200887 if (memchr(laddr, 0, move))
888 break;
John Hughesaa09c6b2001-05-15 14:53:43 +0000889 left -= move;
890 laddr += move;
891 addr += move;
892 move = page;
893 }
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000894#else /* !USE_PROCFS */
Wichert Akkerman5daa0281999-03-15 19:49:42 +0000895 int started = 0;
Roland McGratheb9e2e82009-06-02 16:49:22 -0700896 int pid = tcp->pid;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000897 int i, n, m;
898 union {
899 long val;
900 char x[sizeof(long)];
901 } u;
902
903 if (addr & (sizeof(long) - 1)) {
904 /* addr not a multiple of sizeof(long) */
905 n = addr - (addr & -sizeof(long)); /* residue */
906 addr &= -sizeof(long); /* residue */
Roland McGratheb9e2e82009-06-02 16:49:22 -0700907 errno = 0;
908 u.val = ptrace(PTRACE_PEEKDATA, pid, (char *)addr, 0);
909 if (errno) {
910 if (started && (errno==EPERM || errno==EIO)) {
911 /* Ran into 'end of memory' - stupid "printpath" */
912 return 0;
913 }
914 if (addr != 0 && errno != EIO && errno != ESRCH)
915 perror("umovestr");
916 return -1;
917 }
Wichert Akkerman5daa0281999-03-15 19:49:42 +0000918 started = 1;
Denys Vlasenkob63256e2011-06-07 12:13:24 +0200919 memcpy(laddr, &u.x[n], m = MIN(sizeof(long)-n, len));
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000920 while (n & (sizeof(long) - 1))
921 if (u.x[n++] == '\0')
922 return 0;
923 addr += sizeof(long), laddr += m, len -= m;
924 }
925 while (len) {
Roland McGratheb9e2e82009-06-02 16:49:22 -0700926 errno = 0;
927 u.val = ptrace(PTRACE_PEEKDATA, pid, (char *)addr, 0);
928 if (errno) {
929 if (started && (errno==EPERM || errno==EIO)) {
930 /* Ran into 'end of memory' - stupid "printpath" */
931 return 0;
932 }
933 if (addr != 0 && errno != EIO && errno != ESRCH)
934 perror("umovestr");
935 return -1;
936 }
Wichert Akkerman5daa0281999-03-15 19:49:42 +0000937 started = 1;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000938 memcpy(laddr, u.x, m = MIN(sizeof(long), len));
939 for (i = 0; i < sizeof(long); i++)
940 if (u.x[i] == '\0')
941 return 0;
942
943 addr += sizeof(long), laddr += m, len -= m;
944 }
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000945#endif /* !USE_PROCFS */
John Hughesaa09c6b2001-05-15 14:53:43 +0000946 return 0;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000947}
948
949#ifdef LINUX
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +0000950# if !defined (SPARC) && !defined(SPARC64)
951# define PTRACE_WRITETEXT 101
952# define PTRACE_WRITEDATA 102
953# endif /* !SPARC && !SPARC64 */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000954#endif /* LINUX */
955
956#ifdef SUNOS4
957
958static int
Denys Vlasenko12014262011-05-30 14:00:14 +0200959uload(int cmd, int pid, long addr, int len, char *laddr)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000960{
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000961 int peek, poke;
962 int n, m;
963 union {
964 long val;
965 char x[sizeof(long)];
966 } u;
967
968 if (cmd == PTRACE_WRITETEXT) {
969 peek = PTRACE_PEEKTEXT;
970 poke = PTRACE_POKETEXT;
971 }
972 else {
973 peek = PTRACE_PEEKDATA;
974 poke = PTRACE_POKEDATA;
975 }
976 if (addr & (sizeof(long) - 1)) {
977 /* addr not a multiple of sizeof(long) */
978 n = addr - (addr & -sizeof(long)); /* residue */
979 addr &= -sizeof(long);
Roland McGratheb9e2e82009-06-02 16:49:22 -0700980 errno = 0;
981 u.val = ptrace(peek, pid, (char *) addr, 0);
982 if (errno) {
983 perror("uload: POKE");
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000984 return -1;
985 }
Roland McGratheb9e2e82009-06-02 16:49:22 -0700986 memcpy(&u.x[n], laddr, m = MIN(sizeof(long) - n, len));
987 if (ptrace(poke, pid, (char *)addr, u.val) < 0) {
988 perror("uload: POKE");
989 return -1;
990 }
991 addr += sizeof(long), laddr += m, len -= m;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000992 }
993 while (len) {
994 if (len < sizeof(long))
Roland McGratheb9e2e82009-06-02 16:49:22 -0700995 u.val = ptrace(peek, pid, (char *) addr, 0);
996 memcpy(u.x, laddr, m = MIN(sizeof(long), len));
997 if (ptrace(poke, pid, (char *) addr, u.val) < 0) {
998 perror("uload: POKE");
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000999 return -1;
1000 }
Roland McGratheb9e2e82009-06-02 16:49:22 -07001001 addr += sizeof(long), laddr += m, len -= m;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001002 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001003 return 0;
1004}
1005
Roland McGratheb9e2e82009-06-02 16:49:22 -07001006int
Denys Vlasenko12014262011-05-30 14:00:14 +02001007tload(int pid, int addr, int len, char *laddr)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001008{
Roland McGratheb9e2e82009-06-02 16:49:22 -07001009 return uload(PTRACE_WRITETEXT, pid, addr, len, laddr);
1010}
1011
1012int
Denys Vlasenko12014262011-05-30 14:00:14 +02001013dload(int pid, int addr, int len, char *laddr)
Roland McGratheb9e2e82009-06-02 16:49:22 -07001014{
1015 return uload(PTRACE_WRITEDATA, pid, addr, len, laddr);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001016}
1017
1018#endif /* SUNOS4 */
1019
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001020#ifndef USE_PROCFS
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001021
1022int
Denys Vlasenko12014262011-05-30 14:00:14 +02001023upeek(struct tcb *tcp, long off, long *res)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001024{
1025 long val;
1026
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001027# ifdef SUNOS4_KERNEL_ARCH_KLUDGE
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001028 {
1029 static int is_sun4m = -1;
1030 struct utsname name;
1031
1032 /* Round up the usual suspects. */
1033 if (is_sun4m == -1) {
1034 if (uname(&name) < 0) {
1035 perror("upeek: uname?");
1036 exit(1);
1037 }
1038 is_sun4m = strcmp(name.machine, "sun4m") == 0;
1039 if (is_sun4m) {
Roland McGrathd9f816f2004-09-04 03:39:20 +00001040 const struct xlat *x;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001041
1042 for (x = struct_user_offsets; x->str; x++)
1043 x->val += 1024;
1044 }
1045 }
1046 if (is_sun4m)
1047 off += 1024;
1048 }
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001049# endif /* SUNOS4_KERNEL_ARCH_KLUDGE */
Roland McGratheb9e2e82009-06-02 16:49:22 -07001050 errno = 0;
Denys Vlasenko732d1bf2008-12-17 19:21:59 +00001051 val = do_ptrace(PTRACE_PEEKUSER, tcp, (char *) off, 0);
Roland McGratheb9e2e82009-06-02 16:49:22 -07001052 if (val == -1 && errno) {
1053 if (errno != ESRCH) {
1054 char buf[60];
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001055 sprintf(buf, "upeek: ptrace(PTRACE_PEEKUSER,%d,%lu,0)", tcp->pid, off);
Roland McGratheb9e2e82009-06-02 16:49:22 -07001056 perror(buf);
1057 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001058 return -1;
Roland McGratheb9e2e82009-06-02 16:49:22 -07001059 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001060 *res = val;
1061 return 0;
1062}
1063
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001064#endif /* !USE_PROCFS */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001065
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001066void
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001067printcall(struct tcb *tcp)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001068{
Roland McGrath7a918832005-02-02 20:55:23 +00001069#define PRINTBADPC tprintf(sizeof(long) == 4 ? "[????????] " : \
1070 sizeof(long) == 8 ? "[????????????????] " : \
1071 NULL /* crash */)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001072
1073#ifdef LINUX
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001074# ifdef I386
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001075 long eip;
1076
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001077 if (upeek(tcp, 4*EIP, &eip) < 0) {
Roland McGrath7a918832005-02-02 20:55:23 +00001078 PRINTBADPC;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001079 return;
1080 }
1081 tprintf("[%08lx] ", eip);
Roland McGratheac26fc2005-02-02 02:48:53 +00001082
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001083# elif defined(S390) || defined(S390X)
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001084 long psw;
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001085 if (upeek(tcp, PT_PSWADDR, &psw) < 0) {
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001086 PRINTBADPC;
1087 return;
1088 }
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001089# ifdef S390
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001090 tprintf("[%08lx] ", psw);
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001091# elif S390X
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001092 tprintf("[%16lx] ", psw);
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001093# endif
Roland McGratheac26fc2005-02-02 02:48:53 +00001094
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001095# elif defined(X86_64)
Michal Ludvig0e035502002-09-23 15:41:01 +00001096 long rip;
1097
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001098 if (upeek(tcp, 8*RIP, &rip) < 0) {
Roland McGrath7a918832005-02-02 20:55:23 +00001099 PRINTBADPC;
Michal Ludvig0e035502002-09-23 15:41:01 +00001100 return;
1101 }
1102 tprintf("[%16lx] ", rip);
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001103# elif defined(IA64)
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00001104 long ip;
1105
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001106 if (upeek(tcp, PT_B0, &ip) < 0) {
Roland McGrath7a918832005-02-02 20:55:23 +00001107 PRINTBADPC;
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00001108 return;
1109 }
1110 tprintf("[%08lx] ", ip);
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001111# elif defined(POWERPC)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001112 long pc;
1113
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001114 if (upeek(tcp, sizeof(unsigned long)*PT_NIP, &pc) < 0) {
Andreas Schwabd69fa492010-07-12 21:39:57 +02001115 PRINTBADPC;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001116 return;
1117 }
Andreas Schwabd69fa492010-07-12 21:39:57 +02001118# ifdef POWERPC64
1119 tprintf("[%016lx] ", pc);
1120# else
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001121 tprintf("[%08lx] ", pc);
Andreas Schwabd69fa492010-07-12 21:39:57 +02001122# endif
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001123# elif defined(M68K)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001124 long pc;
1125
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001126 if (upeek(tcp, 4*PT_PC, &pc) < 0) {
Denys Vlasenko60fe8c12011-09-01 10:00:28 +02001127 tprints("[????????] ");
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001128 return;
1129 }
1130 tprintf("[%08lx] ", pc);
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001131# elif defined(ALPHA)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001132 long pc;
1133
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001134 if (upeek(tcp, REG_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(SPARC) || defined(SPARC64)
Mike Frysinger8566c502009-10-12 11:05:14 -04001140 struct pt_regs regs;
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001141 if (ptrace(PTRACE_GETREGS, tcp->pid, (char *)&regs, 0) < 0) {
Roland McGrath7a918832005-02-02 20:55:23 +00001142 PRINTBADPC;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001143 return;
1144 }
Mike Frysinger8566c502009-10-12 11:05:14 -04001145# if defined(SPARC64)
1146 tprintf("[%08lx] ", regs.tpc);
1147# else
1148 tprintf("[%08lx] ", regs.pc);
1149# endif
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001150# elif defined(HPPA)
Wichert Akkermanc1652e22001-03-27 12:17:16 +00001151 long pc;
1152
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001153 if (upeek(tcp, PT_IAOQ0, &pc) < 0) {
Denys Vlasenko60fe8c12011-09-01 10:00:28 +02001154 tprints("[????????] ");
Wichert Akkermanc1652e22001-03-27 12:17:16 +00001155 return;
1156 }
1157 tprintf("[%08lx] ", pc);
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001158# elif defined(MIPS)
Wichert Akkerman75c422b2001-04-10 10:22:50 +00001159 long pc;
1160
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001161 if (upeek(tcp, REG_EPC, &pc) < 0) {
Denys Vlasenko60fe8c12011-09-01 10:00:28 +02001162 tprints("[????????] ");
Wichert Akkerman75c422b2001-04-10 10:22:50 +00001163 return;
1164 }
1165 tprintf("[%08lx] ", pc);
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001166# elif defined(SH)
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001167 long pc;
Wichert Akkermanccef6372002-05-01 16:39:22 +00001168
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001169 if (upeek(tcp, 4*REG_PC, &pc) < 0) {
Denys Vlasenko60fe8c12011-09-01 10:00:28 +02001170 tprints("[????????] ");
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001171 return;
1172 }
1173 tprintf("[%08lx] ", pc);
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001174# elif defined(SH64)
Roland McGrathe1e584b2003-06-02 19:18:58 +00001175 long pc;
1176
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001177 if (upeek(tcp, REG_PC, &pc) < 0) {
Denys Vlasenko60fe8c12011-09-01 10:00:28 +02001178 tprints("[????????????????] ");
Roland McGrathe1e584b2003-06-02 19:18:58 +00001179 return;
1180 }
1181 tprintf("[%08lx] ", pc);
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001182# elif defined(ARM)
Roland McGrathef388682003-06-03 23:28:59 +00001183 long pc;
Roland McGrathe1e584b2003-06-02 19:18:58 +00001184
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001185 if (upeek(tcp, 4*15, &pc) < 0) {
Roland McGrath7a918832005-02-02 20:55:23 +00001186 PRINTBADPC;
Roland McGrathef388682003-06-03 23:28:59 +00001187 return;
1188 }
1189 tprintf("[%08lx] ", pc);
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00001190# elif defined(AVR32)
1191 long pc;
1192
1193 if (upeek(tcp, REG_PC, &pc) < 0) {
Denys Vlasenko60fe8c12011-09-01 10:00:28 +02001194 tprints("[????????] ");
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00001195 return;
1196 }
1197 tprintf("[%08lx] ", pc);
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001198# elif defined(BFIN)
Dmitry V. Levin87ea1f42008-11-10 22:21:41 +00001199 long pc;
1200
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001201 if (upeek(tcp, PT_PC, &pc) < 0) {
Dmitry V. Levin87ea1f42008-11-10 22:21:41 +00001202 PRINTBADPC;
1203 return;
1204 }
1205 tprintf("[%08lx] ", pc);
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001206#elif defined(CRISV10)
1207 long pc;
1208
Edgar E. Iglesiaseeb9ce32009-10-05 14:41:02 +00001209 if (upeek(tcp, 4*PT_IRP, &pc) < 0) {
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001210 PRINTBADPC;
1211 return;
1212 }
1213 tprintf("[%08lx] ", pc);
1214#elif defined(CRISV32)
1215 long pc;
1216
Edgar E. Iglesiaseeb9ce32009-10-05 14:41:02 +00001217 if (upeek(tcp, 4*PT_ERP, &pc) < 0) {
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001218 PRINTBADPC;
1219 return;
1220 }
1221 tprintf("[%08lx] ", pc);
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001222# endif /* architecture */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001223#endif /* LINUX */
1224
1225#ifdef SUNOS4
1226 struct regs regs;
1227
Roland McGratheb9e2e82009-06-02 16:49:22 -07001228 if (ptrace(PTRACE_GETREGS, tcp->pid, (char *) &regs, 0) < 0) {
1229 perror("printcall: ptrace(PTRACE_GETREGS, ...)");
Roland McGrath7a918832005-02-02 20:55:23 +00001230 PRINTBADPC;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001231 return;
1232 }
1233 tprintf("[%08x] ", regs.r_o7);
1234#endif /* SUNOS4 */
1235
1236#ifdef SVR4
1237 /* XXX */
Roland McGrath7a918832005-02-02 20:55:23 +00001238 PRINTBADPC;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001239#endif
1240
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001241#ifdef FREEBSD
1242 struct reg regs;
1243 pread(tcp->pfd_reg, &regs, sizeof(regs), 0);
1244 tprintf("[%08x] ", regs.r_eip);
1245#endif /* FREEBSD */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001246}
1247
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001248
1249/*
1250 * These #if's are huge, please indent them correctly.
1251 * It's easy to get confused otherwise.
1252 */
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001253#ifndef USE_PROCFS
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001254
Denys Vlasenkoe7c90242011-06-22 00:09:25 +02001255# ifdef LINUX
Roland McGrathd81f1d92003-01-09 06:53:34 +00001256
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001257# include "syscall.h"
Roland McGrath3291ef22008-05-20 00:34:34 +00001258
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001259# include <sys/syscall.h>
1260# ifndef CLONE_PTRACE
1261# define CLONE_PTRACE 0x00002000
1262# endif
1263# ifndef CLONE_VFORK
1264# define CLONE_VFORK 0x00004000
1265# endif
1266# ifndef CLONE_VM
1267# define CLONE_VM 0x00000100
1268# endif
1269# ifndef CLONE_STOPPED
1270# define CLONE_STOPPED 0x02000000
1271# endif
Roland McGrathd81f1d92003-01-09 06:53:34 +00001272
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001273# ifdef IA64
Roland McGrathd81f1d92003-01-09 06:53:34 +00001274
Roland McGrath08267b82004-02-20 22:56:43 +00001275/* We don't have fork()/vfork() syscalls on ia64 itself, but the ia32
1276 subsystem has them for x86... */
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001277# define SYS_fork 2
1278# define SYS_vfork 190
Roland McGrath08267b82004-02-20 22:56:43 +00001279
Roland McGrathd81f1d92003-01-09 06:53:34 +00001280typedef unsigned long *arg_setup_state;
1281
1282static int
1283arg_setup(struct tcb *tcp, arg_setup_state *state)
1284{
Jan Kratochvil1f942712008-08-06 21:38:52 +00001285 unsigned long cfm, sof, sol;
1286 long bsp;
Roland McGrathd81f1d92003-01-09 06:53:34 +00001287
Jan Kratochvil1f942712008-08-06 21:38:52 +00001288 if (ia32) {
1289 /* Satisfy a false GCC warning. */
1290 *state = NULL;
Roland McGrath08267b82004-02-20 22:56:43 +00001291 return 0;
Jan Kratochvil1f942712008-08-06 21:38:52 +00001292 }
Roland McGrath08267b82004-02-20 22:56:43 +00001293
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001294 if (upeek(tcp, PT_AR_BSP, &bsp) < 0)
Roland McGrathd81f1d92003-01-09 06:53:34 +00001295 return -1;
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001296 if (upeek(tcp, PT_CFM, (long *) &cfm) < 0)
Roland McGrathd81f1d92003-01-09 06:53:34 +00001297 return -1;
1298
1299 sof = (cfm >> 0) & 0x7f;
1300 sol = (cfm >> 7) & 0x7f;
Jan Kratochvil1f942712008-08-06 21:38:52 +00001301 bsp = (long) ia64_rse_skip_regs((unsigned long *) bsp, -sof + sol);
Roland McGrathd81f1d92003-01-09 06:53:34 +00001302
Jan Kratochvil1f942712008-08-06 21:38:52 +00001303 *state = (unsigned long *) bsp;
Roland McGrathd81f1d92003-01-09 06:53:34 +00001304 return 0;
1305}
1306
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001307# define arg_finish_change(tcp, state) 0
Roland McGrathd81f1d92003-01-09 06:53:34 +00001308
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001309# ifdef SYS_fork
Roland McGrathd81f1d92003-01-09 06:53:34 +00001310static int
Denys Vlasenko12014262011-05-30 14:00:14 +02001311get_arg0(struct tcb *tcp, arg_setup_state *state, long *valp)
Roland McGrathd81f1d92003-01-09 06:53:34 +00001312{
Roland McGrath08267b82004-02-20 22:56:43 +00001313 int ret;
1314
1315 if (ia32)
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001316 ret = upeek(tcp, PT_R11, valp);
Roland McGrath08267b82004-02-20 22:56:43 +00001317 else
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001318 ret = umoven(tcp,
Roland McGrath08267b82004-02-20 22:56:43 +00001319 (unsigned long) ia64_rse_skip_regs(*state, 0),
1320 sizeof(long), (void *) valp);
1321 return ret;
Roland McGrathd81f1d92003-01-09 06:53:34 +00001322}
1323
1324static int
Denys Vlasenko12014262011-05-30 14:00:14 +02001325get_arg1(struct tcb *tcp, arg_setup_state *state, long *valp)
Roland McGrathd81f1d92003-01-09 06:53:34 +00001326{
Roland McGrath08267b82004-02-20 22:56:43 +00001327 int ret;
1328
1329 if (ia32)
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001330 ret = upeek(tcp, PT_R9, valp);
Roland McGrath08267b82004-02-20 22:56:43 +00001331 else
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001332 ret = umoven(tcp,
Roland McGrath08267b82004-02-20 22:56:43 +00001333 (unsigned long) ia64_rse_skip_regs(*state, 1),
1334 sizeof(long), (void *) valp);
1335 return ret;
Roland McGrathd81f1d92003-01-09 06:53:34 +00001336}
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001337# endif
Roland McGrathd81f1d92003-01-09 06:53:34 +00001338
1339static int
Denys Vlasenko12014262011-05-30 14:00:14 +02001340set_arg0(struct tcb *tcp, arg_setup_state *state, long val)
Roland McGrathd81f1d92003-01-09 06:53:34 +00001341{
Roland McGrath08267b82004-02-20 22:56:43 +00001342 int req = PTRACE_POKEDATA;
1343 void *ap;
1344
1345 if (ia32) {
1346 ap = (void *) (intptr_t) PT_R11; /* r11 == EBX */
1347 req = PTRACE_POKEUSER;
1348 } else
1349 ap = ia64_rse_skip_regs(*state, 0);
Roland McGratheb9e2e82009-06-02 16:49:22 -07001350 errno = 0;
1351 ptrace(req, tcp->pid, ap, val);
1352 return errno ? -1 : 0;
Roland McGrathd81f1d92003-01-09 06:53:34 +00001353}
1354
1355static int
Denys Vlasenko12014262011-05-30 14:00:14 +02001356set_arg1(struct tcb *tcp, arg_setup_state *state, long val)
Roland McGrathd81f1d92003-01-09 06:53:34 +00001357{
Roland McGrath08267b82004-02-20 22:56:43 +00001358 int req = PTRACE_POKEDATA;
1359 void *ap;
1360
1361 if (ia32) {
1362 ap = (void *) (intptr_t) PT_R9; /* r9 == ECX */
1363 req = PTRACE_POKEUSER;
1364 } else
1365 ap = ia64_rse_skip_regs(*state, 1);
Roland McGratheb9e2e82009-06-02 16:49:22 -07001366 errno = 0;
1367 ptrace(req, tcp->pid, ap, val);
1368 return errno ? -1 : 0;
Roland McGrathd81f1d92003-01-09 06:53:34 +00001369}
1370
Roland McGrathb659f872008-07-18 01:19:36 +00001371/* ia64 does not return the input arguments from functions (and syscalls)
1372 according to ia64 RSE (Register Stack Engine) behavior. */
1373
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001374# define restore_arg0(tcp, state, val) ((void) (state), 0)
1375# define restore_arg1(tcp, state, val) ((void) (state), 0)
Roland McGrathb659f872008-07-18 01:19:36 +00001376
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001377# elif defined (SPARC) || defined (SPARC64)
Roland McGrathd81f1d92003-01-09 06:53:34 +00001378
Mike Frysinger8566c502009-10-12 11:05:14 -04001379typedef struct pt_regs arg_setup_state;
Roland McGrathd81f1d92003-01-09 06:53:34 +00001380
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001381# define arg_setup(tcp, state) \
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001382 (ptrace(PTRACE_GETREGS, tcp->pid, (char *) (state), 0))
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001383# define arg_finish_change(tcp, state) \
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001384 (ptrace(PTRACE_SETREGS, tcp->pid, (char *) (state), 0))
Roland McGrathd81f1d92003-01-09 06:53:34 +00001385
Mike Frysinger8566c502009-10-12 11:05:14 -04001386# define get_arg0(tcp, state, valp) (*(valp) = (state)->u_regs[U_REG_O0], 0)
1387# define get_arg1(tcp, state, valp) (*(valp) = (state)->u_regs[U_REG_O1], 0)
1388# define set_arg0(tcp, state, val) ((state)->u_regs[U_REG_O0] = (val), 0)
1389# define set_arg1(tcp, state, val) ((state)->u_regs[U_REG_O1] = (val), 0)
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001390# define restore_arg0(tcp, state, val) 0
Roland McGrathd81f1d92003-01-09 06:53:34 +00001391
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001392# else /* other architectures */
Roland McGrathd81f1d92003-01-09 06:53:34 +00001393
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001394# if defined S390 || defined S390X
Roland McGrath7b308222003-01-20 09:04:36 +00001395/* Note: this is only true for the `clone' system call, which handles
1396 arguments specially. We could as well say that its first two arguments
1397 are swapped relative to other architectures, but that would just be
1398 another #ifdef in the calls. */
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001399# define arg0_offset PT_GPR3
1400# define arg1_offset PT_ORIGGPR2
1401# define restore_arg0(tcp, state, val) ((void) (state), 0)
1402# define restore_arg1(tcp, state, val) ((void) (state), 0)
1403# define arg0_index 1
1404# define arg1_index 0
1405# elif defined (ALPHA) || defined (MIPS)
1406# define arg0_offset REG_A0
1407# define arg1_offset (REG_A0+1)
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00001408# elif defined (AVR32)
1409# define arg0_offset (REG_R12)
1410# define arg1_offset (REG_R11)
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001411# elif defined (POWERPC)
1412# define arg0_offset (sizeof(unsigned long)*PT_R3)
1413# define arg1_offset (sizeof(unsigned long)*PT_R4)
1414# define restore_arg0(tcp, state, val) ((void) (state), 0)
1415# elif defined (HPPA)
1416# define arg0_offset PT_GR26
1417# define arg1_offset (PT_GR26-4)
1418# elif defined (X86_64)
1419# define arg0_offset ((long)(8*(current_personality ? RBX : RDI)))
1420# define arg1_offset ((long)(8*(current_personality ? RCX : RSI)))
1421# elif defined (SH)
1422# define arg0_offset (4*(REG_REG0+4))
1423# define arg1_offset (4*(REG_REG0+5))
1424# elif defined (SH64)
1425 /* ABI defines arg0 & 1 in r2 & r3 */
1426# define arg0_offset (REG_OFFSET+16)
1427# define arg1_offset (REG_OFFSET+24)
1428# define restore_arg0(tcp, state, val) 0
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001429# elif defined CRISV10 || defined CRISV32
1430# define arg0_offset (4*PT_R11)
1431# define arg1_offset (4*PT_ORIG_R10)
1432# define restore_arg0(tcp, state, val) 0
1433# define restore_arg1(tcp, state, val) 0
1434# define arg0_index 1
1435# define arg1_index 0
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001436# else
1437# define arg0_offset 0
1438# define arg1_offset 4
1439# if defined ARM
1440# define restore_arg0(tcp, state, val) 0
1441# endif
1442# endif
Roland McGrathd81f1d92003-01-09 06:53:34 +00001443
1444typedef int arg_setup_state;
1445
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001446# define arg_setup(tcp, state) (0)
1447# define arg_finish_change(tcp, state) 0
1448# define get_arg0(tcp, cookie, valp) \
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001449 (upeek((tcp), arg0_offset, (valp)))
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001450# define get_arg1(tcp, cookie, valp) \
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001451 (upeek((tcp), arg1_offset, (valp)))
Roland McGrathd81f1d92003-01-09 06:53:34 +00001452
1453static int
Denys Vlasenko12014262011-05-30 14:00:14 +02001454set_arg0(struct tcb *tcp, void *cookie, long val)
Roland McGrathd81f1d92003-01-09 06:53:34 +00001455{
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001456 return ptrace(PTRACE_POKEUSER, tcp->pid, (char*)arg0_offset, val);
Roland McGrathd81f1d92003-01-09 06:53:34 +00001457}
1458
1459static int
Denys Vlasenko12014262011-05-30 14:00:14 +02001460set_arg1(struct tcb *tcp, void *cookie, long val)
Roland McGrathd81f1d92003-01-09 06:53:34 +00001461{
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001462 return ptrace(PTRACE_POKEUSER, tcp->pid, (char*)arg1_offset, val);
Roland McGrathd81f1d92003-01-09 06:53:34 +00001463}
1464
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001465# endif /* architectures */
Roland McGrathd81f1d92003-01-09 06:53:34 +00001466
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001467# ifndef restore_arg0
1468# define restore_arg0(tcp, state, val) set_arg0((tcp), (state), (val))
1469# endif
1470# ifndef restore_arg1
1471# define restore_arg1(tcp, state, val) set_arg1((tcp), (state), (val))
1472# endif
Roland McGrathd81f1d92003-01-09 06:53:34 +00001473
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001474# ifndef arg0_index
1475# define arg0_index 0
1476# define arg1_index 1
1477# endif
Roland McGrath90d0afd2004-03-01 21:05:16 +00001478
Roland McGrathd81f1d92003-01-09 06:53:34 +00001479int
Denys Vlasenko418d66a2009-01-17 01:52:54 +00001480setbpt(struct tcb *tcp)
Roland McGrathd81f1d92003-01-09 06:53:34 +00001481{
Roland McGrath3291ef22008-05-20 00:34:34 +00001482 static int clone_scno[SUPPORTED_PERSONALITIES] = { SYS_clone };
Roland McGrathd81f1d92003-01-09 06:53:34 +00001483 arg_setup_state state;
1484
1485 if (tcp->flags & TCB_BPTSET) {
1486 fprintf(stderr, "PANIC: TCB already set in pid %u\n", tcp->pid);
1487 return -1;
1488 }
1489
Roland McGrath3291ef22008-05-20 00:34:34 +00001490 /*
1491 * It's a silly kludge to initialize this with a search at runtime.
1492 * But it's better than maintaining another magic thing in the
1493 * godforsaken tables.
1494 */
1495 if (clone_scno[current_personality] == 0) {
1496 int i;
1497 for (i = 0; i < nsyscalls; ++i)
1498 if (sysent[i].sys_func == sys_clone) {
1499 clone_scno[current_personality] = i;
1500 break;
1501 }
1502 }
1503
Roland McGrath76989d72005-06-07 23:21:31 +00001504 switch (known_scno(tcp)) {
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001505# ifdef SYS_vfork
Roland McGrath9383c6c2003-01-18 00:19:31 +00001506 case SYS_vfork:
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001507# endif
1508# ifdef SYS_fork
Roland McGrathd81f1d92003-01-09 06:53:34 +00001509 case SYS_fork:
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001510# endif
1511# if defined SYS_fork || defined SYS_vfork
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001512 if (arg_setup(tcp, &state) < 0
1513 || get_arg0(tcp, &state, &tcp->inst[0]) < 0
1514 || get_arg1(tcp, &state, &tcp->inst[1]) < 0
Roland McGrath3291ef22008-05-20 00:34:34 +00001515 || change_syscall(tcp, clone_scno[current_personality]) < 0
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001516 || set_arg0(tcp, &state, CLONE_PTRACE|SIGCHLD) < 0
1517 || set_arg1(tcp, &state, 0) < 0
1518 || arg_finish_change(tcp, &state) < 0)
Roland McGrathd81f1d92003-01-09 06:53:34 +00001519 return -1;
Roland McGrathc9dc3c12004-03-01 20:57:09 +00001520 tcp->u_arg[arg0_index] = CLONE_PTRACE|SIGCHLD;
1521 tcp->u_arg[arg1_index] = 0;
Roland McGrathd81f1d92003-01-09 06:53:34 +00001522 tcp->flags |= TCB_BPTSET;
1523 return 0;
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001524# endif
Roland McGrathd81f1d92003-01-09 06:53:34 +00001525
Denys Vlasenkoc133bf02011-06-23 21:57:54 +02001526 case SYS_clone: ;
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001527# ifdef SYS_clone2
Denys Vlasenkoc133bf02011-06-23 21:57:54 +02001528 case SYS_clone2: ;
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001529# endif
Jan Kratochvil8fc95752008-08-06 21:43:35 +00001530 /* ia64 calls directly `clone (CLONE_VFORK | CLONE_VM)'
1531 contrary to x86 SYS_vfork above. Even on x86 we turn the
1532 vfork semantics into plain fork - each application must not
1533 depend on the vfork specifics according to POSIX. We would
1534 hang waiting for the parent resume otherwise. We need to
1535 clear also CLONE_VM but only in the CLONE_VFORK case as
1536 otherwise we would break pthread_create. */
1537
Denys Vlasenkoc133bf02011-06-23 21:57:54 +02001538 long new_arg0 = (tcp->u_arg[arg0_index] | CLONE_PTRACE);
1539 if (new_arg0 & CLONE_VFORK)
1540 new_arg0 &= ~(unsigned long)(CLONE_VFORK | CLONE_VM);
1541 if (arg_setup(tcp, &state) < 0
1542 || set_arg0(tcp, &state, new_arg0) < 0
1543 || arg_finish_change(tcp, &state) < 0)
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00001544 return -1;
Roland McGrathd81f1d92003-01-09 06:53:34 +00001545 tcp->flags |= TCB_BPTSET;
Roland McGrathc9dc3c12004-03-01 20:57:09 +00001546 tcp->inst[0] = tcp->u_arg[arg0_index];
1547 tcp->inst[1] = tcp->u_arg[arg1_index];
Roland McGrathd81f1d92003-01-09 06:53:34 +00001548 return 0;
1549
1550 default:
1551 fprintf(stderr, "PANIC: setbpt for syscall %ld on %u???\n",
1552 tcp->scno, tcp->pid);
1553 break;
1554 }
1555
1556 return -1;
1557}
1558
1559int
Denys Vlasenko12014262011-05-30 14:00:14 +02001560clearbpt(struct tcb *tcp)
Roland McGrathd81f1d92003-01-09 06:53:34 +00001561{
1562 arg_setup_state state;
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001563 if (arg_setup(tcp, &state) < 0
1564 || restore_arg0(tcp, &state, tcp->inst[0]) < 0
1565 || restore_arg1(tcp, &state, tcp->inst[1]) < 0
1566 || arg_finish_change(tcp, &state))
Denys Vlasenkoc133bf02011-06-23 21:57:54 +02001567 if (errno != ESRCH)
1568 return -1;
Roland McGrathd81f1d92003-01-09 06:53:34 +00001569 tcp->flags &= ~TCB_BPTSET;
1570 return 0;
1571}
1572
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001573# else /* !defined LINUX */
Roland McGrathd81f1d92003-01-09 06:53:34 +00001574
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001575int
Denys Vlasenko12014262011-05-30 14:00:14 +02001576setbpt(struct tcb *tcp)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001577{
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001578# ifdef SUNOS4
1579# ifdef SPARC /* This code is slightly sparc specific */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001580
Wichert Akkermane6f876c1999-06-22 15:28:30 +00001581 struct regs regs;
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001582# define BPT 0x91d02001 /* ta 1 */
1583# define LOOP 0x10800000 /* ba 0 */
1584# define LOOPA 0x30800000 /* ba,a 0 */
1585# define NOP 0x01000000
1586# if LOOPA
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001587 static int loopdeloop[1] = {LOOPA};
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001588# else
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001589 static int loopdeloop[2] = {LOOP, NOP};
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001590# endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001591
1592 if (tcp->flags & TCB_BPTSET) {
1593 fprintf(stderr, "PANIC: TCB already set in pid %u\n", tcp->pid);
1594 return -1;
1595 }
Roland McGratheb9e2e82009-06-02 16:49:22 -07001596 if (ptrace(PTRACE_GETREGS, tcp->pid, (char *)&regs, 0) < 0) {
1597 perror("setbpt: ptrace(PTRACE_GETREGS, ...)");
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001598 return -1;
1599 }
1600 tcp->baddr = regs.r_o7 + 8;
Roland McGratheb9e2e82009-06-02 16:49:22 -07001601 if (ptrace(PTRACE_READTEXT, tcp->pid, (char *)tcp->baddr,
1602 sizeof tcp->inst, (char *)tcp->inst) < 0) {
1603 perror("setbpt: ptrace(PTRACE_READTEXT, ...)");
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001604 return -1;
1605 }
1606
1607 /*
1608 * XXX - BRUTAL MODE ON
1609 * We cannot set a real BPT in the child, since it will not be
1610 * traced at the moment it will reach the trap and would probably
1611 * die with a core dump.
1612 * Thus, we are force our way in by taking out two instructions
1613 * and insert an eternal loop in stead, in expectance of the SIGSTOP
1614 * generated by out PTRACE_ATTACH.
1615 * Of cause, if we evaporate ourselves in the middle of all this...
1616 */
Roland McGratheb9e2e82009-06-02 16:49:22 -07001617 if (ptrace(PTRACE_WRITETEXT, tcp->pid, (char *) tcp->baddr,
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001618 sizeof loopdeloop, (char *) loopdeloop) < 0) {
Roland McGratheb9e2e82009-06-02 16:49:22 -07001619 perror("setbpt: ptrace(PTRACE_WRITETEXT, ...)");
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001620 return -1;
1621 }
1622 tcp->flags |= TCB_BPTSET;
1623
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001624# endif /* SPARC */
1625# endif /* SUNOS4 */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001626
1627 return 0;
1628}
1629
1630int
Denys Vlasenko12014262011-05-30 14:00:14 +02001631clearbpt(struct tcb *tcp)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001632{
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001633# ifdef SUNOS4
1634# ifdef SPARC
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001635
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001636# if !LOOPA
Wichert Akkermane6f876c1999-06-22 15:28:30 +00001637 struct regs regs;
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001638# endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001639
1640 if (!(tcp->flags & TCB_BPTSET)) {
1641 fprintf(stderr, "PANIC: TCB not set in pid %u\n", tcp->pid);
1642 return -1;
1643 }
Roland McGratheb9e2e82009-06-02 16:49:22 -07001644 if (ptrace(PTRACE_WRITETEXT, tcp->pid, (char *) tcp->baddr,
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001645 sizeof tcp->inst, (char *) tcp->inst) < 0) {
Roland McGratheb9e2e82009-06-02 16:49:22 -07001646 perror("clearbtp: ptrace(PTRACE_WRITETEXT, ...)");
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001647 return -1;
1648 }
1649 tcp->flags &= ~TCB_BPTSET;
1650
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001651# if !LOOPA
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001652 /*
1653 * Since we don't have a single instruction breakpoint, we may have
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001654 * to adjust the program counter after removing our `breakpoint'.
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001655 */
Roland McGratheb9e2e82009-06-02 16:49:22 -07001656 if (ptrace(PTRACE_GETREGS, tcp->pid, (char *)&regs, 0) < 0) {
1657 perror("clearbpt: ptrace(PTRACE_GETREGS, ...)");
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001658 return -1;
1659 }
Roland McGratheb9e2e82009-06-02 16:49:22 -07001660 if ((regs.r_pc < tcp->baddr) ||
1661 (regs.r_pc > tcp->baddr + 4)) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001662 /* The breakpoint has not been reached yet */
1663 if (debug)
1664 fprintf(stderr,
1665 "NOTE: PC not at bpt (pc %#x baddr %#x)\n",
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001666 regs.r_pc, tcp->baddr);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001667 return 0;
1668 }
1669 if (regs.r_pc != tcp->baddr)
1670 if (debug)
1671 fprintf(stderr, "NOTE: PC adjusted (%#x -> %#x\n",
1672 regs.r_pc, tcp->baddr);
1673
1674 regs.r_pc = tcp->baddr;
Roland McGratheb9e2e82009-06-02 16:49:22 -07001675 if (ptrace(PTRACE_SETREGS, tcp->pid, (char *)&regs, 0) < 0) {
1676 perror("clearbpt: ptrace(PTRACE_SETREGS, ...)");
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001677 return -1;
1678 }
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001679# endif /* LOOPA */
1680# endif /* SPARC */
1681# endif /* SUNOS4 */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001682
1683 return 0;
1684}
1685
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001686# endif /* !defined LINUX */
Roland McGrathd81f1d92003-01-09 06:53:34 +00001687
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001688#endif /* !USE_PROCFS */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001689
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001690
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001691#ifdef SUNOS4
1692
1693static int
Denys Vlasenko12014262011-05-30 14:00:14 +02001694getex(struct tcb *tcp, struct exec *hdr)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001695{
1696 int n;
1697
1698 for (n = 0; n < sizeof *hdr; n += 4) {
1699 long res;
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001700 if (upeek(tcp, uoff(u_exdata) + n, &res) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001701 return -1;
1702 memcpy(((char *) hdr) + n, &res, 4);
1703 }
1704 if (debug) {
1705 fprintf(stderr, "[struct exec: magic: %o version %u Mach %o\n",
1706 hdr->a_magic, hdr->a_toolversion, hdr->a_machtype);
1707 fprintf(stderr, "Text %lu Data %lu Bss %lu Syms %lu Entry %#lx]\n",
1708 hdr->a_text, hdr->a_data, hdr->a_bss, hdr->a_syms, hdr->a_entry);
1709 }
1710 return 0;
1711}
1712
1713int
Denys Vlasenko12014262011-05-30 14:00:14 +02001714fixvfork(struct tcb *tcp)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001715{
1716 int pid = tcp->pid;
1717 /*
1718 * Change `vfork' in a freshly exec'ed dynamically linked
1719 * executable's (internal) symbol table to plain old `fork'
1720 */
1721
1722 struct exec hdr;
1723 struct link_dynamic dyn;
1724 struct link_dynamic_2 ld;
1725 char *strtab, *cp;
1726
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001727 if (getex(tcp, &hdr) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001728 return -1;
1729 if (!hdr.a_dynamic)
1730 return -1;
1731
1732 if (umove(tcp, (int) N_DATADDR(hdr), &dyn) < 0) {
1733 fprintf(stderr, "Cannot read DYNAMIC\n");
1734 return -1;
1735 }
1736 if (umove(tcp, (int) dyn.ld_un.ld_2, &ld) < 0) {
1737 fprintf(stderr, "Cannot read link_dynamic_2\n");
1738 return -1;
1739 }
Denys Vlasenko5d645812011-08-20 12:48:18 +02001740 strtab = malloc((unsigned)ld.ld_symb_size);
Denys Vlasenko1d46ba52011-08-31 14:00:02 +02001741 if (!strtab)
1742 die_out_of_memory();
Roland McGratheb9e2e82009-06-02 16:49:22 -07001743 if (umoven(tcp, (int)ld.ld_symbols+(int)N_TXTADDR(hdr),
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001744 (int)ld.ld_symb_size, strtab) < 0)
1745 goto err;
1746
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001747 for (cp = strtab; cp < strtab + ld.ld_symb_size; ) {
1748 if (strcmp(cp, "_vfork") == 0) {
1749 if (debug)
1750 fprintf(stderr, "fixvfork: FOUND _vfork\n");
1751 strcpy(cp, "_fork");
1752 break;
1753 }
1754 cp += strlen(cp)+1;
1755 }
1756 if (cp < strtab + ld.ld_symb_size)
1757 /*
1758 * Write entire symbol table back to avoid
1759 * memory alignment bugs in ptrace
1760 */
Roland McGratheb9e2e82009-06-02 16:49:22 -07001761 if (tload(pid, (int)ld.ld_symbols+(int)N_TXTADDR(hdr),
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001762 (int)ld.ld_symb_size, strtab) < 0)
1763 goto err;
1764
1765 free(strtab);
1766 return 0;
1767
1768err:
1769 free(strtab);
1770 return -1;
1771}
1772
1773#endif /* SUNOS4 */