blob: 7d1af70281ae0187b920fa46cdef570580bdc09d [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";
227 fprintf(stderr, "strace: ptrace(PTRACE_%s,1,%d): %s\n",
228 msg, sig, strerror(err));
Denys Vlasenko732d1bf2008-12-17 19:21:59 +0000229 return -1;
230}
231
232/*
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000233 * Print entry in struct xlat table, if there.
234 */
235void
Dmitry V. Levinab9008b2007-01-11 22:05:04 +0000236printxval(const struct xlat *xlat, int val, const char *dflt)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000237{
Dmitry V. Levinab9008b2007-01-11 22:05:04 +0000238 const char *str = xlookup(xlat, val);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000239
240 if (str)
Denys Vlasenko5940e652011-09-01 09:55:05 +0200241 tprints(str);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000242 else
243 tprintf("%#x /* %s */", val, dflt);
244}
245
Andreas Schwabb5600fc2009-11-04 17:08:34 +0100246#if HAVE_LONG_LONG
247/*
248 * Print 64bit argument at position llarg and return the index of the next
249 * argument.
250 */
251int
252printllval(struct tcb *tcp, const char *format, int llarg)
253{
254# if defined(FREEBSD) \
Andreas Schwabd69fa492010-07-12 21:39:57 +0200255 || (defined(LINUX) && defined(POWERPC) && !defined(POWERPC64)) \
Dmitry V. Levin7a5b08f2011-05-28 20:47:43 +0000256 || defined(LINUX_MIPSO32) \
257 || defined(__ARM_EABI__)
Andreas Schwabb5600fc2009-11-04 17:08:34 +0100258 /* Align 64bit argument to 64bit boundary. */
Denys Vlasenko4b08df42011-08-19 15:58:24 +0200259 llarg = (llarg + 1) & 0x1e;
Andreas Schwabb5600fc2009-11-04 17:08:34 +0100260# endif
Andreas Schwabd69fa492010-07-12 21:39:57 +0200261# if defined LINUX && (defined X86_64 || defined POWERPC64)
Andreas Schwabb5600fc2009-11-04 17:08:34 +0100262 if (current_personality == 0) {
263 tprintf(format, tcp->u_arg[llarg]);
264 llarg++;
265 } else {
Andreas Schwabd69fa492010-07-12 21:39:57 +0200266# ifdef POWERPC64
267 /* Align 64bit argument to 64bit boundary. */
Denys Vlasenko4b08df42011-08-19 15:58:24 +0200268 llarg = (llarg + 1) & 0x1e;
Andreas Schwabd69fa492010-07-12 21:39:57 +0200269# endif
Andreas Schwabb5600fc2009-11-04 17:08:34 +0100270 tprintf(format, LONG_LONG(tcp->u_arg[llarg], tcp->u_arg[llarg + 1]));
271 llarg += 2;
272 }
Andreas Schwabd69fa492010-07-12 21:39:57 +0200273# elif defined IA64 || defined ALPHA
Andreas Schwabb5600fc2009-11-04 17:08:34 +0100274 tprintf(format, tcp->u_arg[llarg]);
275 llarg++;
276# elif defined LINUX_MIPSN32
277 tprintf(format, tcp->ext_arg[llarg]);
278 llarg++;
279# else
280 tprintf(format, LONG_LONG(tcp->u_arg[llarg], tcp->u_arg[llarg + 1]));
281 llarg += 2;
282# endif
283 return llarg;
284}
285#endif
286
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000287/*
288 * Interpret `xlat' as an array of flags
289 * print the entries whose bits are on in `flags'
290 * return # of flags printed.
291 */
Denys Vlasenko4924dbd2011-08-19 18:06:46 +0200292void
Denys Vlasenko12014262011-05-30 14:00:14 +0200293addflags(const struct xlat *xlat, int flags)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000294{
Denys Vlasenko4924dbd2011-08-19 18:06:46 +0200295 for (; xlat->str; xlat++) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000296 if (xlat->val && (flags & xlat->val) == xlat->val) {
297 tprintf("|%s", xlat->str);
298 flags &= ~xlat->val;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000299 }
300 }
301 if (flags) {
302 tprintf("|%#x", flags);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000303 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000304}
305
Roland McGratha6c0d8c2007-11-01 21:46:22 +0000306/*
Denys Vlasenko4924dbd2011-08-19 18:06:46 +0200307 * Interpret `xlat' as an array of flags.
Roland McGratha6c0d8c2007-11-01 21:46:22 +0000308 * Print to static string the entries whose bits are on in `flags'
309 * Return static string.
310 */
311const char *
312sprintflags(const char *prefix, const struct xlat *xlat, int flags)
313{
314 static char outstr[1024];
Denys Vlasenko52845572011-08-31 12:07:38 +0200315 char *outptr;
Roland McGratha6c0d8c2007-11-01 21:46:22 +0000316 int found = 0;
317
Denys Vlasenko52845572011-08-31 12:07:38 +0200318 outptr = stpcpy(outstr, prefix);
Roland McGratha6c0d8c2007-11-01 21:46:22 +0000319
320 for (; xlat->str; xlat++) {
321 if ((flags & xlat->val) == xlat->val) {
322 if (found)
Denys Vlasenko52845572011-08-31 12:07:38 +0200323 *outptr++ = '|';
324 outptr = stpcpy(outptr, xlat->str);
Roland McGratha6c0d8c2007-11-01 21:46:22 +0000325 flags &= ~xlat->val;
326 found = 1;
327 }
328 }
329 if (flags) {
330 if (found)
Denys Vlasenko52845572011-08-31 12:07:38 +0200331 *outptr++ = '|';
332 outptr += sprintf(outptr, "%#x", flags);
Roland McGratha6c0d8c2007-11-01 21:46:22 +0000333 }
334
335 return outstr;
336}
337
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000338int
Dmitry V. Levin30145dd2010-09-06 22:08:24 +0000339printflags(const struct xlat *xlat, int flags, const char *dflt)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000340{
341 int n;
Dmitry V. Levin30145dd2010-09-06 22:08:24 +0000342 const char *sep;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000343
344 if (flags == 0 && xlat->val == 0) {
Denys Vlasenko5940e652011-09-01 09:55:05 +0200345 tprints(xlat->str);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000346 return 1;
347 }
348
349 sep = "";
350 for (n = 0; xlat->str; xlat++) {
351 if (xlat->val && (flags & xlat->val) == xlat->val) {
352 tprintf("%s%s", sep, xlat->str);
353 flags &= ~xlat->val;
354 sep = "|";
355 n++;
356 }
357 }
Roland McGrathb2dee132005-06-01 19:02:36 +0000358
359 if (n) {
360 if (flags) {
361 tprintf("%s%#x", sep, flags);
362 n++;
363 }
364 } else {
365 if (flags) {
366 tprintf("%#x", flags);
367 if (dflt)
368 tprintf(" /* %s */", dflt);
369 } else {
370 if (dflt)
Denys Vlasenko60fe8c12011-09-01 10:00:28 +0200371 tprints("0");
Roland McGrathb2dee132005-06-01 19:02:36 +0000372 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000373 }
Roland McGrathb2dee132005-06-01 19:02:36 +0000374
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000375 return n;
376}
377
378void
Dmitry V. Levin30145dd2010-09-06 22:08:24 +0000379printnum(struct tcb *tcp, long addr, const char *fmt)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000380{
Roland McGratheb285352003-01-14 09:59:00 +0000381 long num;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000382
383 if (!addr) {
Denys Vlasenko60fe8c12011-09-01 10:00:28 +0200384 tprints("NULL");
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000385 return;
386 }
387 if (umove(tcp, addr, &num) < 0) {
388 tprintf("%#lx", addr);
389 return;
390 }
Denys Vlasenko60fe8c12011-09-01 10:00:28 +0200391 tprints("[");
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000392 tprintf(fmt, num);
Denys Vlasenko60fe8c12011-09-01 10:00:28 +0200393 tprints("]");
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000394}
395
Roland McGrath6bc12202003-11-13 22:32:27 +0000396void
Dmitry V. Levin30145dd2010-09-06 22:08:24 +0000397printnum_int(struct tcb *tcp, long addr, const char *fmt)
Roland McGrath9814a942005-07-04 23:28:10 +0000398{
399 int num;
400
401 if (!addr) {
Denys Vlasenko60fe8c12011-09-01 10:00:28 +0200402 tprints("NULL");
Roland McGrath9814a942005-07-04 23:28:10 +0000403 return;
404 }
405 if (umove(tcp, addr, &num) < 0) {
406 tprintf("%#lx", addr);
407 return;
408 }
Denys Vlasenko60fe8c12011-09-01 10:00:28 +0200409 tprints("[");
Roland McGrath9814a942005-07-04 23:28:10 +0000410 tprintf(fmt, num);
Denys Vlasenko60fe8c12011-09-01 10:00:28 +0200411 tprints("]");
Roland McGrath9814a942005-07-04 23:28:10 +0000412}
413
414void
Dmitry V. Levin31382132011-03-04 05:08:02 +0300415printfd(struct tcb *tcp, int fd)
416{
Grant Edwards8a082772011-04-07 20:25:40 +0000417 const char *p;
418
419 if (show_fd_path && (p = getfdpath(tcp, fd)))
420 tprintf("%d<%s>", fd, p);
421 else
422 tprintf("%d", fd);
Dmitry V. Levin31382132011-03-04 05:08:02 +0300423}
424
425void
Denys Vlasenko12014262011-05-30 14:00:14 +0200426printuid(const char *text, unsigned long uid)
Roland McGrath6bc12202003-11-13 22:32:27 +0000427{
Denys Vlasenko5940e652011-09-01 09:55:05 +0200428 tprintf((uid == -1) ? "%s%ld" : "%s%lu", text, uid);
Roland McGrath6bc12202003-11-13 22:32:27 +0000429}
430
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000431static char path[MAXPATHLEN + 1];
432
Dmitry V. Levina501f142008-11-10 23:19:13 +0000433/*
434 * Quote string `instr' of length `size'
435 * Write up to (3 + `size' * 4) bytes to `outstr' buffer.
436 * If `len' < 0, treat `instr' as a NUL-terminated string
437 * and quote at most (`size' - 1) bytes.
438 */
Roland McGrath6d970322007-11-01 23:53:59 +0000439static int
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000440string_quote(const char *instr, char *outstr, int len, int size)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000441{
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000442 const unsigned char *ustr = (const unsigned char *) instr;
443 char *s = outstr;
Denys Vlasenko8778bff2011-08-31 12:22:56 +0200444 int usehex, c, i, eol;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000445
Denys Vlasenko8778bff2011-08-31 12:22:56 +0200446 eol = 0x100; /* this can never match a char */
447 if (len < 0) {
448 size--;
449 eol = '\0';
450 }
451
452 usehex = 0;
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000453 if (xflag > 1)
454 usehex = 1;
455 else if (xflag) {
Dmitry V. Levina501f142008-11-10 23:19:13 +0000456 /* Check for presence of symbol which require
457 to hex-quote the whole string. */
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000458 for (i = 0; i < size; ++i) {
459 c = ustr[i];
Dmitry V. Levina501f142008-11-10 23:19:13 +0000460 /* Check for NUL-terminated string. */
Denys Vlasenko8778bff2011-08-31 12:22:56 +0200461 if (c == eol)
462 break;
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000463 if (!isprint(c) && !isspace(c)) {
464 usehex = 1;
465 break;
466 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000467 }
468 }
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000469
470 *s++ = '\"';
471
472 if (usehex) {
Dmitry V. Levina501f142008-11-10 23:19:13 +0000473 /* Hex-quote the whole string. */
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000474 for (i = 0; i < size; ++i) {
475 c = ustr[i];
Dmitry V. Levina501f142008-11-10 23:19:13 +0000476 /* Check for NUL-terminated string. */
Denys Vlasenko8778bff2011-08-31 12:22:56 +0200477 if (c == eol)
478 goto asciz_ended;
479 *s++ = '\\';
480 *s++ = 'x';
481 *s++ = "0123456789abcdef"[c >> 4];
482 *s++ = "0123456789abcdef"[c & 0xf];
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000483 }
484 } else {
485 for (i = 0; i < size; ++i) {
486 c = ustr[i];
Dmitry V. Levina501f142008-11-10 23:19:13 +0000487 /* Check for NUL-terminated string. */
Denys Vlasenko8778bff2011-08-31 12:22:56 +0200488 if (c == eol)
489 goto asciz_ended;
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000490 switch (c) {
491 case '\"': case '\\':
492 *s++ = '\\';
493 *s++ = c;
494 break;
495 case '\f':
496 *s++ = '\\';
497 *s++ = 'f';
498 break;
499 case '\n':
500 *s++ = '\\';
501 *s++ = 'n';
502 break;
503 case '\r':
504 *s++ = '\\';
505 *s++ = 'r';
506 break;
507 case '\t':
508 *s++ = '\\';
509 *s++ = 't';
510 break;
511 case '\v':
512 *s++ = '\\';
513 *s++ = 'v';
514 break;
515 default:
516 if (isprint(c))
517 *s++ = c;
Denys Vlasenko8778bff2011-08-31 12:22:56 +0200518 else {
519 /* Print \octal */
520 *s++ = '\\';
521 if (i + 1 < size
522 && ustr[i + 1] >= '0'
523 && ustr[i + 1] <= '9'
524 ) {
525 /* Print \ooo */
526 *s++ = '0' + (c >> 6);
527 *s++ = '0' + ((c >> 3) & 0x7);
528 } else {
529 /* Print \[[o]o]o */
530 if ((c >> 3) != 0) {
531 if ((c >> 6) != 0)
532 *s++ = '0' + (c >> 6);
533 *s++ = '0' + ((c >> 3) & 0x7);
534 }
535 }
536 *s++ = '0' + (c & 0x7);
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000537 }
538 break;
539 }
540 }
541 }
542
543 *s++ = '\"';
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000544 *s = '\0';
Roland McGrath6d970322007-11-01 23:53:59 +0000545
Denys Vlasenko8778bff2011-08-31 12:22:56 +0200546 /* Return zero if we printed entire ASCIZ string (didn't truncate it) */
547 if (len < 0 && ustr[i] == '\0') {
548 /* We didn't see NUL yet (otherwise we'd jump to 'asciz_ended')
549 * but next char is NUL.
550 */
551 return 0;
552 }
553
554 return 1;
555
556 asciz_ended:
557 *s++ = '\"';
558 *s = '\0';
559 /* Return zero: we printed entire ASCIZ string (didn't truncate it) */
560 return 0;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000561}
562
Dmitry V. Levina501f142008-11-10 23:19:13 +0000563/*
564 * Print path string specified by address `addr' and length `n'.
565 * If path length exceeds `n', append `...' to the output.
566 */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000567void
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000568printpathn(struct tcb *tcp, long addr, int n)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000569{
Dmitry V. Levina501f142008-11-10 23:19:13 +0000570 if (!addr) {
Denys Vlasenko60fe8c12011-09-01 10:00:28 +0200571 tprints("NULL");
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000572 return;
573 }
574
Dmitry V. Levina501f142008-11-10 23:19:13 +0000575 /* Cap path length to the path buffer size,
576 and NUL-terminate the buffer. */
577 if (n > sizeof path - 1)
578 n = sizeof path - 1;
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000579 path[n] = '\0';
Dmitry V. Levina501f142008-11-10 23:19:13 +0000580
581 /* Fetch one byte more to find out whether path length > n. */
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000582 if (umovestr(tcp, addr, n + 1, path) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000583 tprintf("%#lx", addr);
584 else {
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000585 static char outstr[4*(sizeof path - 1) + sizeof "\"...\""];
Denys Vlasenko52845572011-08-31 12:07:38 +0200586 const char *fmt;
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000587 int trunc = (path[n] != '\0');
588
589 if (trunc)
590 path[n] = '\0';
Denys Vlasenko52845572011-08-31 12:07:38 +0200591 string_quote(path, outstr, -1, n + 1);
592 fmt = "%s";
Dmitry V. Levina501f142008-11-10 23:19:13 +0000593 if (trunc)
Denys Vlasenko52845572011-08-31 12:07:38 +0200594 fmt = "%s...";
595 tprintf(fmt, outstr);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000596 }
597}
598
599void
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000600printpath(struct tcb *tcp, long addr)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000601{
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000602 printpathn(tcp, addr, sizeof path - 1);
603}
604
Dmitry V. Levina501f142008-11-10 23:19:13 +0000605/*
606 * Print string specified by address `addr' and length `len'.
607 * If `len' < 0, treat the string as a NUL-terminated string.
608 * If string length exceeds `max_strlen', append `...' to the output.
609 */
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000610void
611printstr(struct tcb *tcp, long addr, int len)
612{
613 static char *str = NULL;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000614 static char *outstr;
Roland McGrath6d970322007-11-01 23:53:59 +0000615 int size;
Denys Vlasenko52845572011-08-31 12:07:38 +0200616 const char *fmt;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000617
618 if (!addr) {
Denys Vlasenko60fe8c12011-09-01 10:00:28 +0200619 tprints("NULL");
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000620 return;
621 }
Dmitry V. Levina501f142008-11-10 23:19:13 +0000622 /* Allocate static buffers if they are not allocated yet. */
Denys Vlasenko1d46ba52011-08-31 14:00:02 +0200623 if (!str) {
Dmitry V. Levina501f142008-11-10 23:19:13 +0000624 str = malloc(max_strlen + 1);
Denys Vlasenko1d46ba52011-08-31 14:00:02 +0200625 if (!str)
626 die_out_of_memory();
627 }
628 if (!outstr) {
Dmitry V. Levina501f142008-11-10 23:19:13 +0000629 outstr = malloc(4 * max_strlen + sizeof "\"...\"");
Denys Vlasenko1d46ba52011-08-31 14:00:02 +0200630 if (!outstr)
631 die_out_of_memory();
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000632 }
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000633
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000634 if (len < 0) {
Dmitry V. Levina501f142008-11-10 23:19:13 +0000635 /*
636 * Treat as a NUL-terminated string: fetch one byte more
637 * because string_quote() quotes one byte less.
638 */
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000639 size = max_strlen + 1;
Dmitry V. Levina501f142008-11-10 23:19:13 +0000640 str[max_strlen] = '\0';
Denys Vlasenko52845572011-08-31 12:07:38 +0200641 /* FIXME! umovestr can overwrite the '\0' stored above??? */
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000642 if (umovestr(tcp, addr, size, str) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000643 tprintf("%#lx", addr);
644 return;
645 }
646 }
647 else {
Dmitry V. Levina501f142008-11-10 23:19:13 +0000648 size = MIN(len, max_strlen);
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000649 if (umoven(tcp, addr, size, str) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000650 tprintf("%#lx", addr);
651 return;
652 }
653 }
654
Denys Vlasenko52845572011-08-31 12:07:38 +0200655 fmt = "%s";
Dmitry V. Levina501f142008-11-10 23:19:13 +0000656 if (string_quote(str, outstr, len, size) &&
657 (len < 0 || len > max_strlen))
Denys Vlasenko52845572011-08-31 12:07:38 +0200658 fmt = "%s...";
Roland McGratha503dcf2007-08-02 02:06:26 +0000659
Denys Vlasenko52845572011-08-31 12:07:38 +0200660 tprintf(fmt, outstr);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000661}
662
John Hughes1d08dcf2001-07-10 13:48:44 +0000663#if HAVE_SYS_UIO_H
664void
Denys Vlasenko12014262011-05-30 14:00:14 +0200665dumpiov(struct tcb *tcp, int len, long addr)
John Hughes1d08dcf2001-07-10 13:48:44 +0000666{
Dmitry V. Levin4ebb4e32006-12-13 17:08:08 +0000667#if defined(LINUX) && SUPPORTED_PERSONALITIES > 1
668 union {
669 struct { u_int32_t base; u_int32_t len; } *iov32;
670 struct { u_int64_t base; u_int64_t len; } *iov64;
671 } iovu;
672#define iov iovu.iov64
673#define sizeof_iov \
674 (personality_wordsize[current_personality] == 4 \
675 ? sizeof(*iovu.iov32) : sizeof(*iovu.iov64))
676#define iov_iov_base(i) \
677 (personality_wordsize[current_personality] == 4 \
678 ? (u_int64_t) iovu.iov32[i].base : iovu.iov64[i].base)
679#define iov_iov_len(i) \
680 (personality_wordsize[current_personality] == 4 \
681 ? (u_int64_t) iovu.iov32[i].len : iovu.iov64[i].len)
682#else
John Hughes1d08dcf2001-07-10 13:48:44 +0000683 struct iovec *iov;
Dmitry V. Levin4ebb4e32006-12-13 17:08:08 +0000684#define sizeof_iov sizeof(*iov)
685#define iov_iov_base(i) iov[i].iov_base
686#define iov_iov_len(i) iov[i].iov_len
687#endif
John Hughes1d08dcf2001-07-10 13:48:44 +0000688 int i;
Roland McGrathaa524c82005-06-01 19:22:06 +0000689 unsigned long size;
John Hughes1d08dcf2001-07-10 13:48:44 +0000690
Dmitry V. Levin4ebb4e32006-12-13 17:08:08 +0000691 size = sizeof_iov * (unsigned long) len;
Denys Vlasenko1d46ba52011-08-31 14:00:02 +0200692 if (size / sizeof_iov != len /* overflow? */
Dmitry V. Levin4ebb4e32006-12-13 17:08:08 +0000693 || (iov = malloc(size)) == NULL) {
Denys Vlasenko1d46ba52011-08-31 14:00:02 +0200694 die_out_of_memory();
John Hughes1d08dcf2001-07-10 13:48:44 +0000695 }
Roland McGrathaa524c82005-06-01 19:22:06 +0000696 if (umoven(tcp, addr, size, (char *) iov) >= 0) {
John Hughes1d08dcf2001-07-10 13:48:44 +0000697 for (i = 0; i < len; i++) {
Denys Vlasenkoadedb512008-12-30 18:47:55 +0000698 /* include the buffer number to make it easy to
699 * match up the trace with the source */
700 tprintf(" * %lu bytes in buffer %d\n",
701 (unsigned long)iov_iov_len(i), i);
702 dumpstr(tcp, (long) iov_iov_base(i),
703 iov_iov_len(i));
704 }
John Hughes1d08dcf2001-07-10 13:48:44 +0000705 }
706 free((char *) iov);
Dmitry V. Levin4ebb4e32006-12-13 17:08:08 +0000707#undef sizeof_iov
708#undef iov_iov_base
709#undef iov_iov_len
710#undef iov
John Hughes1d08dcf2001-07-10 13:48:44 +0000711}
712#endif
713
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000714void
Denys Vlasenko12014262011-05-30 14:00:14 +0200715dumpstr(struct tcb *tcp, long addr, int len)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000716{
717 static int strsize = -1;
718 static unsigned char *str;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000719 char *s;
720 int i, j;
721
722 if (strsize < len) {
Denys Vlasenko5d645812011-08-20 12:48:18 +0200723 free(str);
724 str = malloc(len);
Denys Vlasenko1d46ba52011-08-31 14:00:02 +0200725 if (!str)
726 die_out_of_memory();
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000727 strsize = len;
728 }
729
730 if (umoven(tcp, addr, len, (char *) str) < 0)
731 return;
732
733 for (i = 0; i < len; i += 16) {
Denys Vlasenko1d46ba52011-08-31 14:00:02 +0200734 char outstr[80];
735
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000736 s = outstr;
737 sprintf(s, " | %05x ", i);
738 s += 9;
739 for (j = 0; j < 16; j++) {
740 if (j == 8)
741 *s++ = ' ';
742 if (i + j < len) {
743 sprintf(s, " %02x", str[i + j]);
744 s += 3;
745 }
746 else {
747 *s++ = ' '; *s++ = ' '; *s++ = ' ';
748 }
749 }
750 *s++ = ' '; *s++ = ' ';
751 for (j = 0; j < 16; j++) {
752 if (j == 8)
753 *s++ = ' ';
754 if (i + j < len) {
755 if (isprint(str[i + j]))
756 *s++ = str[i + j];
757 else
758 *s++ = '.';
759 }
760 else
761 *s++ = ' ';
762 }
763 tprintf("%s |\n", outstr);
764 }
765}
766
767#define PAGMASK (~(PAGSIZ - 1))
768/*
769 * move `len' bytes of data from process `pid'
770 * at address `addr' to our space at `laddr'
771 */
772int
Denys Vlasenkoef2fbf82009-01-06 21:45:06 +0000773umoven(struct tcb *tcp, long addr, int len, char *laddr)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000774{
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000775#ifdef LINUX
Roland McGratheb9e2e82009-06-02 16:49:22 -0700776 int pid = tcp->pid;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000777 int n, m;
Wichert Akkerman5daa0281999-03-15 19:49:42 +0000778 int started = 0;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000779 union {
780 long val;
781 char x[sizeof(long)];
782 } u;
783
784 if (addr & (sizeof(long) - 1)) {
785 /* addr not a multiple of sizeof(long) */
786 n = addr - (addr & -sizeof(long)); /* residue */
787 addr &= -sizeof(long); /* residue */
Roland McGratheb9e2e82009-06-02 16:49:22 -0700788 errno = 0;
789 u.val = ptrace(PTRACE_PEEKDATA, pid, (char *) addr, 0);
790 if (errno) {
791 if (started && (errno==EPERM || errno==EIO)) {
792 /* Ran into 'end of memory' - stupid "printpath" */
793 return 0;
794 }
795 /* But if not started, we had a bogus address. */
796 if (addr != 0 && errno != EIO && errno != ESRCH)
797 perror("ptrace: umoven");
798 return -1;
799 }
Wichert Akkerman5daa0281999-03-15 19:49:42 +0000800 started = 1;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000801 memcpy(laddr, &u.x[n], m = MIN(sizeof(long) - n, len));
802 addr += sizeof(long), laddr += m, len -= m;
803 }
804 while (len) {
Roland McGratheb9e2e82009-06-02 16:49:22 -0700805 errno = 0;
806 u.val = ptrace(PTRACE_PEEKDATA, pid, (char *) addr, 0);
807 if (errno) {
808 if (started && (errno==EPERM || errno==EIO)) {
809 /* Ran into 'end of memory' - stupid "printpath" */
810 return 0;
811 }
812 if (addr != 0 && errno != EIO && errno != ESRCH)
813 perror("ptrace: umoven");
814 return -1;
815 }
Wichert Akkerman5daa0281999-03-15 19:49:42 +0000816 started = 1;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000817 memcpy(laddr, u.x, m = MIN(sizeof(long), len));
818 addr += sizeof(long), laddr += m, len -= m;
819 }
820#endif /* LINUX */
821
822#ifdef SUNOS4
823 int pid = tcp->pid;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000824 int n;
825
826 while (len) {
827 n = MIN(len, PAGSIZ);
828 n = MIN(n, ((addr + PAGSIZ) & PAGMASK) - addr);
Roland McGratheb9e2e82009-06-02 16:49:22 -0700829 if (ptrace(PTRACE_READDATA, pid,
830 (char *) addr, len, laddr) < 0) {
831 if (errno != ESRCH) {
832 perror("umoven: ptrace(PTRACE_READDATA, ...)");
833 abort();
834 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000835 return -1;
836 }
837 len -= n;
838 addr += n;
839 laddr += n;
840 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000841#endif /* SUNOS4 */
842
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000843#ifdef USE_PROCFS
Wichert Akkermanea78f0f1999-11-29 15:34:02 +0000844#ifdef HAVE_MP_PROCFS
John Hughesaa09c6b2001-05-15 14:53:43 +0000845 int fd = tcp->pfd_as;
Wichert Akkerman9ce1a631999-08-29 23:15:07 +0000846#else
John Hughesaa09c6b2001-05-15 14:53:43 +0000847 int fd = tcp->pfd;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000848#endif
John Hughesaa09c6b2001-05-15 14:53:43 +0000849 lseek(fd, addr, SEEK_SET);
850 if (read(fd, laddr, len) == -1)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000851 return -1;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000852#endif /* USE_PROCFS */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000853
854 return 0;
855}
856
857/*
858 * like `umove' but make the additional effort of looking
859 * for a terminating zero byte.
860 */
861int
Denys Vlasenkoef2fbf82009-01-06 21:45:06 +0000862umovestr(struct tcb *tcp, long addr, int len, char *laddr)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000863{
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000864#ifdef USE_PROCFS
John Hughesaa09c6b2001-05-15 14:53:43 +0000865#ifdef HAVE_MP_PROCFS
866 int fd = tcp->pfd_as;
867#else
868 int fd = tcp->pfd;
869#endif
870 /* Some systems (e.g. FreeBSD) can be upset if we read off the
871 end of valid memory, avoid this by trying to read up
872 to page boundaries. But we don't know what a page is (and
873 getpagesize(2) (if it exists) doesn't necessarily return
874 hardware page size). Assume all pages >= 1024 (a-historical
875 I know) */
876
Denys Vlasenkob63256e2011-06-07 12:13:24 +0200877 int page = 1024; /* How to find this? */
John Hughesaa09c6b2001-05-15 14:53:43 +0000878 int move = page - (addr & (page - 1));
879 int left = len;
880
881 lseek(fd, addr, SEEK_SET);
882
883 while (left) {
Denys Vlasenko5d645812011-08-20 12:48:18 +0200884 if (move > left)
885 move = left;
886 move = read(fd, laddr, move);
887 if (move <= 0)
John Hughesaa09c6b2001-05-15 14:53:43 +0000888 return left != len ? 0 : -1;
Denys Vlasenko5d645812011-08-20 12:48:18 +0200889 if (memchr(laddr, 0, move))
890 break;
John Hughesaa09c6b2001-05-15 14:53:43 +0000891 left -= move;
892 laddr += move;
893 addr += move;
894 move = page;
895 }
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000896#else /* !USE_PROCFS */
Wichert Akkerman5daa0281999-03-15 19:49:42 +0000897 int started = 0;
Roland McGratheb9e2e82009-06-02 16:49:22 -0700898 int pid = tcp->pid;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000899 int i, n, m;
900 union {
901 long val;
902 char x[sizeof(long)];
903 } u;
904
905 if (addr & (sizeof(long) - 1)) {
906 /* addr not a multiple of sizeof(long) */
907 n = addr - (addr & -sizeof(long)); /* residue */
908 addr &= -sizeof(long); /* residue */
Roland McGratheb9e2e82009-06-02 16:49:22 -0700909 errno = 0;
910 u.val = ptrace(PTRACE_PEEKDATA, pid, (char *)addr, 0);
911 if (errno) {
912 if (started && (errno==EPERM || errno==EIO)) {
913 /* Ran into 'end of memory' - stupid "printpath" */
914 return 0;
915 }
916 if (addr != 0 && errno != EIO && errno != ESRCH)
917 perror("umovestr");
918 return -1;
919 }
Wichert Akkerman5daa0281999-03-15 19:49:42 +0000920 started = 1;
Denys Vlasenkob63256e2011-06-07 12:13:24 +0200921 memcpy(laddr, &u.x[n], m = MIN(sizeof(long)-n, len));
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000922 while (n & (sizeof(long) - 1))
923 if (u.x[n++] == '\0')
924 return 0;
925 addr += sizeof(long), laddr += m, len -= m;
926 }
927 while (len) {
Roland McGratheb9e2e82009-06-02 16:49:22 -0700928 errno = 0;
929 u.val = ptrace(PTRACE_PEEKDATA, pid, (char *)addr, 0);
930 if (errno) {
931 if (started && (errno==EPERM || errno==EIO)) {
932 /* Ran into 'end of memory' - stupid "printpath" */
933 return 0;
934 }
935 if (addr != 0 && errno != EIO && errno != ESRCH)
936 perror("umovestr");
937 return -1;
938 }
Wichert Akkerman5daa0281999-03-15 19:49:42 +0000939 started = 1;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000940 memcpy(laddr, u.x, m = MIN(sizeof(long), len));
941 for (i = 0; i < sizeof(long); i++)
942 if (u.x[i] == '\0')
943 return 0;
944
945 addr += sizeof(long), laddr += m, len -= m;
946 }
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000947#endif /* !USE_PROCFS */
John Hughesaa09c6b2001-05-15 14:53:43 +0000948 return 0;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000949}
950
951#ifdef LINUX
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +0000952# if !defined (SPARC) && !defined(SPARC64)
953# define PTRACE_WRITETEXT 101
954# define PTRACE_WRITEDATA 102
955# endif /* !SPARC && !SPARC64 */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000956#endif /* LINUX */
957
958#ifdef SUNOS4
959
960static int
Denys Vlasenko12014262011-05-30 14:00:14 +0200961uload(int cmd, int pid, long addr, int len, char *laddr)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000962{
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000963 int peek, poke;
964 int n, m;
965 union {
966 long val;
967 char x[sizeof(long)];
968 } u;
969
970 if (cmd == PTRACE_WRITETEXT) {
971 peek = PTRACE_PEEKTEXT;
972 poke = PTRACE_POKETEXT;
973 }
974 else {
975 peek = PTRACE_PEEKDATA;
976 poke = PTRACE_POKEDATA;
977 }
978 if (addr & (sizeof(long) - 1)) {
979 /* addr not a multiple of sizeof(long) */
980 n = addr - (addr & -sizeof(long)); /* residue */
981 addr &= -sizeof(long);
Roland McGratheb9e2e82009-06-02 16:49:22 -0700982 errno = 0;
983 u.val = ptrace(peek, pid, (char *) addr, 0);
984 if (errno) {
985 perror("uload: POKE");
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000986 return -1;
987 }
Roland McGratheb9e2e82009-06-02 16:49:22 -0700988 memcpy(&u.x[n], laddr, m = MIN(sizeof(long) - n, len));
989 if (ptrace(poke, pid, (char *)addr, u.val) < 0) {
990 perror("uload: POKE");
991 return -1;
992 }
993 addr += sizeof(long), laddr += m, len -= m;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000994 }
995 while (len) {
996 if (len < sizeof(long))
Roland McGratheb9e2e82009-06-02 16:49:22 -0700997 u.val = ptrace(peek, pid, (char *) addr, 0);
998 memcpy(u.x, laddr, m = MIN(sizeof(long), len));
999 if (ptrace(poke, pid, (char *) addr, u.val) < 0) {
1000 perror("uload: POKE");
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001001 return -1;
1002 }
Roland McGratheb9e2e82009-06-02 16:49:22 -07001003 addr += sizeof(long), laddr += m, len -= m;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001004 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001005 return 0;
1006}
1007
Roland McGratheb9e2e82009-06-02 16:49:22 -07001008int
Denys Vlasenko12014262011-05-30 14:00:14 +02001009tload(int pid, int addr, int len, char *laddr)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001010{
Roland McGratheb9e2e82009-06-02 16:49:22 -07001011 return uload(PTRACE_WRITETEXT, pid, addr, len, laddr);
1012}
1013
1014int
Denys Vlasenko12014262011-05-30 14:00:14 +02001015dload(int pid, int addr, int len, char *laddr)
Roland McGratheb9e2e82009-06-02 16:49:22 -07001016{
1017 return uload(PTRACE_WRITEDATA, pid, addr, len, laddr);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001018}
1019
1020#endif /* SUNOS4 */
1021
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001022#ifndef USE_PROCFS
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001023
1024int
Denys Vlasenko12014262011-05-30 14:00:14 +02001025upeek(struct tcb *tcp, long off, long *res)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001026{
1027 long val;
1028
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001029# ifdef SUNOS4_KERNEL_ARCH_KLUDGE
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001030 {
1031 static int is_sun4m = -1;
1032 struct utsname name;
1033
1034 /* Round up the usual suspects. */
1035 if (is_sun4m == -1) {
1036 if (uname(&name) < 0) {
1037 perror("upeek: uname?");
1038 exit(1);
1039 }
1040 is_sun4m = strcmp(name.machine, "sun4m") == 0;
1041 if (is_sun4m) {
Roland McGrathd9f816f2004-09-04 03:39:20 +00001042 const struct xlat *x;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001043
1044 for (x = struct_user_offsets; x->str; x++)
1045 x->val += 1024;
1046 }
1047 }
1048 if (is_sun4m)
1049 off += 1024;
1050 }
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001051# endif /* SUNOS4_KERNEL_ARCH_KLUDGE */
Roland McGratheb9e2e82009-06-02 16:49:22 -07001052 errno = 0;
Denys Vlasenko732d1bf2008-12-17 19:21:59 +00001053 val = do_ptrace(PTRACE_PEEKUSER, tcp, (char *) off, 0);
Roland McGratheb9e2e82009-06-02 16:49:22 -07001054 if (val == -1 && errno) {
1055 if (errno != ESRCH) {
1056 char buf[60];
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001057 sprintf(buf, "upeek: ptrace(PTRACE_PEEKUSER,%d,%lu,0)", tcp->pid, off);
Roland McGratheb9e2e82009-06-02 16:49:22 -07001058 perror(buf);
1059 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001060 return -1;
Roland McGratheb9e2e82009-06-02 16:49:22 -07001061 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001062 *res = val;
1063 return 0;
1064}
1065
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001066#endif /* !USE_PROCFS */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001067
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001068void
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001069printcall(struct tcb *tcp)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001070{
Roland McGrath7a918832005-02-02 20:55:23 +00001071#define PRINTBADPC tprintf(sizeof(long) == 4 ? "[????????] " : \
1072 sizeof(long) == 8 ? "[????????????????] " : \
1073 NULL /* crash */)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001074
1075#ifdef LINUX
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001076# ifdef I386
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001077 long eip;
1078
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001079 if (upeek(tcp, 4*EIP, &eip) < 0) {
Roland McGrath7a918832005-02-02 20:55:23 +00001080 PRINTBADPC;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001081 return;
1082 }
1083 tprintf("[%08lx] ", eip);
Roland McGratheac26fc2005-02-02 02:48:53 +00001084
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001085# elif defined(S390) || defined(S390X)
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001086 long psw;
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001087 if (upeek(tcp, PT_PSWADDR, &psw) < 0) {
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001088 PRINTBADPC;
1089 return;
1090 }
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001091# ifdef S390
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001092 tprintf("[%08lx] ", psw);
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001093# elif S390X
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001094 tprintf("[%16lx] ", psw);
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001095# endif
Roland McGratheac26fc2005-02-02 02:48:53 +00001096
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001097# elif defined(X86_64)
Michal Ludvig0e035502002-09-23 15:41:01 +00001098 long rip;
1099
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001100 if (upeek(tcp, 8*RIP, &rip) < 0) {
Roland McGrath7a918832005-02-02 20:55:23 +00001101 PRINTBADPC;
Michal Ludvig0e035502002-09-23 15:41:01 +00001102 return;
1103 }
1104 tprintf("[%16lx] ", rip);
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001105# elif defined(IA64)
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00001106 long ip;
1107
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001108 if (upeek(tcp, PT_B0, &ip) < 0) {
Roland McGrath7a918832005-02-02 20:55:23 +00001109 PRINTBADPC;
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00001110 return;
1111 }
1112 tprintf("[%08lx] ", ip);
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001113# elif defined(POWERPC)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001114 long pc;
1115
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001116 if (upeek(tcp, sizeof(unsigned long)*PT_NIP, &pc) < 0) {
Andreas Schwabd69fa492010-07-12 21:39:57 +02001117 PRINTBADPC;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001118 return;
1119 }
Andreas Schwabd69fa492010-07-12 21:39:57 +02001120# ifdef POWERPC64
1121 tprintf("[%016lx] ", pc);
1122# else
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001123 tprintf("[%08lx] ", pc);
Andreas Schwabd69fa492010-07-12 21:39:57 +02001124# endif
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001125# elif defined(M68K)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001126 long pc;
1127
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001128 if (upeek(tcp, 4*PT_PC, &pc) < 0) {
Denys Vlasenko60fe8c12011-09-01 10:00:28 +02001129 tprints("[????????] ");
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001130 return;
1131 }
1132 tprintf("[%08lx] ", pc);
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001133# elif defined(ALPHA)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001134 long pc;
1135
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001136 if (upeek(tcp, REG_PC, &pc) < 0) {
Denys Vlasenko60fe8c12011-09-01 10:00:28 +02001137 tprints("[????????????????] ");
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001138 return;
1139 }
1140 tprintf("[%08lx] ", pc);
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001141# elif defined(SPARC) || defined(SPARC64)
Mike Frysinger8566c502009-10-12 11:05:14 -04001142 struct pt_regs regs;
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001143 if (ptrace(PTRACE_GETREGS, tcp->pid, (char *)&regs, 0) < 0) {
Roland McGrath7a918832005-02-02 20:55:23 +00001144 PRINTBADPC;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001145 return;
1146 }
Mike Frysinger8566c502009-10-12 11:05:14 -04001147# if defined(SPARC64)
1148 tprintf("[%08lx] ", regs.tpc);
1149# else
1150 tprintf("[%08lx] ", regs.pc);
1151# endif
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001152# elif defined(HPPA)
Wichert Akkermanc1652e22001-03-27 12:17:16 +00001153 long pc;
1154
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001155 if (upeek(tcp, PT_IAOQ0, &pc) < 0) {
Denys Vlasenko60fe8c12011-09-01 10:00:28 +02001156 tprints("[????????] ");
Wichert Akkermanc1652e22001-03-27 12:17:16 +00001157 return;
1158 }
1159 tprintf("[%08lx] ", pc);
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001160# elif defined(MIPS)
Wichert Akkerman75c422b2001-04-10 10:22:50 +00001161 long pc;
1162
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001163 if (upeek(tcp, REG_EPC, &pc) < 0) {
Denys Vlasenko60fe8c12011-09-01 10:00:28 +02001164 tprints("[????????] ");
Wichert Akkerman75c422b2001-04-10 10:22:50 +00001165 return;
1166 }
1167 tprintf("[%08lx] ", pc);
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001168# elif defined(SH)
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001169 long pc;
Wichert Akkermanccef6372002-05-01 16:39:22 +00001170
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001171 if (upeek(tcp, 4*REG_PC, &pc) < 0) {
Denys Vlasenko60fe8c12011-09-01 10:00:28 +02001172 tprints("[????????] ");
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001173 return;
1174 }
1175 tprintf("[%08lx] ", pc);
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001176# elif defined(SH64)
Roland McGrathe1e584b2003-06-02 19:18:58 +00001177 long pc;
1178
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001179 if (upeek(tcp, REG_PC, &pc) < 0) {
Denys Vlasenko60fe8c12011-09-01 10:00:28 +02001180 tprints("[????????????????] ");
Roland McGrathe1e584b2003-06-02 19:18:58 +00001181 return;
1182 }
1183 tprintf("[%08lx] ", pc);
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001184# elif defined(ARM)
Roland McGrathef388682003-06-03 23:28:59 +00001185 long pc;
Roland McGrathe1e584b2003-06-02 19:18:58 +00001186
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001187 if (upeek(tcp, 4*15, &pc) < 0) {
Roland McGrath7a918832005-02-02 20:55:23 +00001188 PRINTBADPC;
Roland McGrathef388682003-06-03 23:28:59 +00001189 return;
1190 }
1191 tprintf("[%08lx] ", pc);
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00001192# elif defined(AVR32)
1193 long pc;
1194
1195 if (upeek(tcp, REG_PC, &pc) < 0) {
Denys Vlasenko60fe8c12011-09-01 10:00:28 +02001196 tprints("[????????] ");
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00001197 return;
1198 }
1199 tprintf("[%08lx] ", pc);
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001200# elif defined(BFIN)
Dmitry V. Levin87ea1f42008-11-10 22:21:41 +00001201 long pc;
1202
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001203 if (upeek(tcp, PT_PC, &pc) < 0) {
Dmitry V. Levin87ea1f42008-11-10 22:21:41 +00001204 PRINTBADPC;
1205 return;
1206 }
1207 tprintf("[%08lx] ", pc);
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001208#elif defined(CRISV10)
1209 long pc;
1210
Edgar E. Iglesiaseeb9ce32009-10-05 14:41:02 +00001211 if (upeek(tcp, 4*PT_IRP, &pc) < 0) {
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001212 PRINTBADPC;
1213 return;
1214 }
1215 tprintf("[%08lx] ", pc);
1216#elif defined(CRISV32)
1217 long pc;
1218
Edgar E. Iglesiaseeb9ce32009-10-05 14:41:02 +00001219 if (upeek(tcp, 4*PT_ERP, &pc) < 0) {
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001220 PRINTBADPC;
1221 return;
1222 }
1223 tprintf("[%08lx] ", pc);
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001224# endif /* architecture */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001225#endif /* LINUX */
1226
1227#ifdef SUNOS4
1228 struct regs regs;
1229
Roland McGratheb9e2e82009-06-02 16:49:22 -07001230 if (ptrace(PTRACE_GETREGS, tcp->pid, (char *) &regs, 0) < 0) {
1231 perror("printcall: ptrace(PTRACE_GETREGS, ...)");
Roland McGrath7a918832005-02-02 20:55:23 +00001232 PRINTBADPC;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001233 return;
1234 }
1235 tprintf("[%08x] ", regs.r_o7);
1236#endif /* SUNOS4 */
1237
1238#ifdef SVR4
1239 /* XXX */
Roland McGrath7a918832005-02-02 20:55:23 +00001240 PRINTBADPC;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001241#endif
1242
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001243#ifdef FREEBSD
1244 struct reg regs;
1245 pread(tcp->pfd_reg, &regs, sizeof(regs), 0);
1246 tprintf("[%08x] ", regs.r_eip);
1247#endif /* FREEBSD */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001248}
1249
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001250
1251/*
1252 * These #if's are huge, please indent them correctly.
1253 * It's easy to get confused otherwise.
1254 */
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001255#ifndef USE_PROCFS
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001256
Denys Vlasenkoe7c90242011-06-22 00:09:25 +02001257# ifdef LINUX
Roland McGrathd81f1d92003-01-09 06:53:34 +00001258
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001259# include "syscall.h"
Roland McGrath3291ef22008-05-20 00:34:34 +00001260
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001261# include <sys/syscall.h>
1262# ifndef CLONE_PTRACE
1263# define CLONE_PTRACE 0x00002000
1264# endif
1265# ifndef CLONE_VFORK
1266# define CLONE_VFORK 0x00004000
1267# endif
1268# ifndef CLONE_VM
1269# define CLONE_VM 0x00000100
1270# endif
1271# ifndef CLONE_STOPPED
1272# define CLONE_STOPPED 0x02000000
1273# endif
Roland McGrathd81f1d92003-01-09 06:53:34 +00001274
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001275# ifdef IA64
Roland McGrathd81f1d92003-01-09 06:53:34 +00001276
Roland McGrath08267b82004-02-20 22:56:43 +00001277/* We don't have fork()/vfork() syscalls on ia64 itself, but the ia32
1278 subsystem has them for x86... */
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001279# define SYS_fork 2
1280# define SYS_vfork 190
Roland McGrath08267b82004-02-20 22:56:43 +00001281
Roland McGrathd81f1d92003-01-09 06:53:34 +00001282typedef unsigned long *arg_setup_state;
1283
1284static int
1285arg_setup(struct tcb *tcp, arg_setup_state *state)
1286{
Jan Kratochvil1f942712008-08-06 21:38:52 +00001287 unsigned long cfm, sof, sol;
1288 long bsp;
Roland McGrathd81f1d92003-01-09 06:53:34 +00001289
Jan Kratochvil1f942712008-08-06 21:38:52 +00001290 if (ia32) {
1291 /* Satisfy a false GCC warning. */
1292 *state = NULL;
Roland McGrath08267b82004-02-20 22:56:43 +00001293 return 0;
Jan Kratochvil1f942712008-08-06 21:38:52 +00001294 }
Roland McGrath08267b82004-02-20 22:56:43 +00001295
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001296 if (upeek(tcp, PT_AR_BSP, &bsp) < 0)
Roland McGrathd81f1d92003-01-09 06:53:34 +00001297 return -1;
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001298 if (upeek(tcp, PT_CFM, (long *) &cfm) < 0)
Roland McGrathd81f1d92003-01-09 06:53:34 +00001299 return -1;
1300
1301 sof = (cfm >> 0) & 0x7f;
1302 sol = (cfm >> 7) & 0x7f;
Jan Kratochvil1f942712008-08-06 21:38:52 +00001303 bsp = (long) ia64_rse_skip_regs((unsigned long *) bsp, -sof + sol);
Roland McGrathd81f1d92003-01-09 06:53:34 +00001304
Jan Kratochvil1f942712008-08-06 21:38:52 +00001305 *state = (unsigned long *) bsp;
Roland McGrathd81f1d92003-01-09 06:53:34 +00001306 return 0;
1307}
1308
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001309# define arg_finish_change(tcp, state) 0
Roland McGrathd81f1d92003-01-09 06:53:34 +00001310
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001311# ifdef SYS_fork
Roland McGrathd81f1d92003-01-09 06:53:34 +00001312static int
Denys Vlasenko12014262011-05-30 14:00:14 +02001313get_arg0(struct tcb *tcp, arg_setup_state *state, long *valp)
Roland McGrathd81f1d92003-01-09 06:53:34 +00001314{
Roland McGrath08267b82004-02-20 22:56:43 +00001315 int ret;
1316
1317 if (ia32)
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001318 ret = upeek(tcp, PT_R11, valp);
Roland McGrath08267b82004-02-20 22:56:43 +00001319 else
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001320 ret = umoven(tcp,
Roland McGrath08267b82004-02-20 22:56:43 +00001321 (unsigned long) ia64_rse_skip_regs(*state, 0),
1322 sizeof(long), (void *) valp);
1323 return ret;
Roland McGrathd81f1d92003-01-09 06:53:34 +00001324}
1325
1326static int
Denys Vlasenko12014262011-05-30 14:00:14 +02001327get_arg1(struct tcb *tcp, arg_setup_state *state, long *valp)
Roland McGrathd81f1d92003-01-09 06:53:34 +00001328{
Roland McGrath08267b82004-02-20 22:56:43 +00001329 int ret;
1330
1331 if (ia32)
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001332 ret = upeek(tcp, PT_R9, valp);
Roland McGrath08267b82004-02-20 22:56:43 +00001333 else
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001334 ret = umoven(tcp,
Roland McGrath08267b82004-02-20 22:56:43 +00001335 (unsigned long) ia64_rse_skip_regs(*state, 1),
1336 sizeof(long), (void *) valp);
1337 return ret;
Roland McGrathd81f1d92003-01-09 06:53:34 +00001338}
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001339# endif
Roland McGrathd81f1d92003-01-09 06:53:34 +00001340
1341static int
Denys Vlasenko12014262011-05-30 14:00:14 +02001342set_arg0(struct tcb *tcp, arg_setup_state *state, long val)
Roland McGrathd81f1d92003-01-09 06:53:34 +00001343{
Roland McGrath08267b82004-02-20 22:56:43 +00001344 int req = PTRACE_POKEDATA;
1345 void *ap;
1346
1347 if (ia32) {
1348 ap = (void *) (intptr_t) PT_R11; /* r11 == EBX */
1349 req = PTRACE_POKEUSER;
1350 } else
1351 ap = ia64_rse_skip_regs(*state, 0);
Roland McGratheb9e2e82009-06-02 16:49:22 -07001352 errno = 0;
1353 ptrace(req, tcp->pid, ap, val);
1354 return errno ? -1 : 0;
Roland McGrathd81f1d92003-01-09 06:53:34 +00001355}
1356
1357static int
Denys Vlasenko12014262011-05-30 14:00:14 +02001358set_arg1(struct tcb *tcp, arg_setup_state *state, long val)
Roland McGrathd81f1d92003-01-09 06:53:34 +00001359{
Roland McGrath08267b82004-02-20 22:56:43 +00001360 int req = PTRACE_POKEDATA;
1361 void *ap;
1362
1363 if (ia32) {
1364 ap = (void *) (intptr_t) PT_R9; /* r9 == ECX */
1365 req = PTRACE_POKEUSER;
1366 } else
1367 ap = ia64_rse_skip_regs(*state, 1);
Roland McGratheb9e2e82009-06-02 16:49:22 -07001368 errno = 0;
1369 ptrace(req, tcp->pid, ap, val);
1370 return errno ? -1 : 0;
Roland McGrathd81f1d92003-01-09 06:53:34 +00001371}
1372
Roland McGrathb659f872008-07-18 01:19:36 +00001373/* ia64 does not return the input arguments from functions (and syscalls)
1374 according to ia64 RSE (Register Stack Engine) behavior. */
1375
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001376# define restore_arg0(tcp, state, val) ((void) (state), 0)
1377# define restore_arg1(tcp, state, val) ((void) (state), 0)
Roland McGrathb659f872008-07-18 01:19:36 +00001378
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001379# elif defined (SPARC) || defined (SPARC64)
Roland McGrathd81f1d92003-01-09 06:53:34 +00001380
Mike Frysinger8566c502009-10-12 11:05:14 -04001381typedef struct pt_regs arg_setup_state;
Roland McGrathd81f1d92003-01-09 06:53:34 +00001382
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001383# define arg_setup(tcp, state) \
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001384 (ptrace(PTRACE_GETREGS, tcp->pid, (char *) (state), 0))
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001385# define arg_finish_change(tcp, state) \
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001386 (ptrace(PTRACE_SETREGS, tcp->pid, (char *) (state), 0))
Roland McGrathd81f1d92003-01-09 06:53:34 +00001387
Mike Frysinger8566c502009-10-12 11:05:14 -04001388# define get_arg0(tcp, state, valp) (*(valp) = (state)->u_regs[U_REG_O0], 0)
1389# define get_arg1(tcp, state, valp) (*(valp) = (state)->u_regs[U_REG_O1], 0)
1390# define set_arg0(tcp, state, val) ((state)->u_regs[U_REG_O0] = (val), 0)
1391# define set_arg1(tcp, state, val) ((state)->u_regs[U_REG_O1] = (val), 0)
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001392# define restore_arg0(tcp, state, val) 0
Roland McGrathd81f1d92003-01-09 06:53:34 +00001393
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001394# else /* other architectures */
Roland McGrathd81f1d92003-01-09 06:53:34 +00001395
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001396# if defined S390 || defined S390X
Roland McGrath7b308222003-01-20 09:04:36 +00001397/* Note: this is only true for the `clone' system call, which handles
1398 arguments specially. We could as well say that its first two arguments
1399 are swapped relative to other architectures, but that would just be
1400 another #ifdef in the calls. */
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001401# define arg0_offset PT_GPR3
1402# define arg1_offset PT_ORIGGPR2
1403# define restore_arg0(tcp, state, val) ((void) (state), 0)
1404# define restore_arg1(tcp, state, val) ((void) (state), 0)
1405# define arg0_index 1
1406# define arg1_index 0
1407# elif defined (ALPHA) || defined (MIPS)
1408# define arg0_offset REG_A0
1409# define arg1_offset (REG_A0+1)
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00001410# elif defined (AVR32)
1411# define arg0_offset (REG_R12)
1412# define arg1_offset (REG_R11)
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001413# elif defined (POWERPC)
1414# define arg0_offset (sizeof(unsigned long)*PT_R3)
1415# define arg1_offset (sizeof(unsigned long)*PT_R4)
1416# define restore_arg0(tcp, state, val) ((void) (state), 0)
1417# elif defined (HPPA)
1418# define arg0_offset PT_GR26
1419# define arg1_offset (PT_GR26-4)
1420# elif defined (X86_64)
1421# define arg0_offset ((long)(8*(current_personality ? RBX : RDI)))
1422# define arg1_offset ((long)(8*(current_personality ? RCX : RSI)))
1423# elif defined (SH)
1424# define arg0_offset (4*(REG_REG0+4))
1425# define arg1_offset (4*(REG_REG0+5))
1426# elif defined (SH64)
1427 /* ABI defines arg0 & 1 in r2 & r3 */
1428# define arg0_offset (REG_OFFSET+16)
1429# define arg1_offset (REG_OFFSET+24)
1430# define restore_arg0(tcp, state, val) 0
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001431# elif defined CRISV10 || defined CRISV32
1432# define arg0_offset (4*PT_R11)
1433# define arg1_offset (4*PT_ORIG_R10)
1434# define restore_arg0(tcp, state, val) 0
1435# define restore_arg1(tcp, state, val) 0
1436# define arg0_index 1
1437# define arg1_index 0
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001438# else
1439# define arg0_offset 0
1440# define arg1_offset 4
1441# if defined ARM
1442# define restore_arg0(tcp, state, val) 0
1443# endif
1444# endif
Roland McGrathd81f1d92003-01-09 06:53:34 +00001445
1446typedef int arg_setup_state;
1447
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001448# define arg_setup(tcp, state) (0)
1449# define arg_finish_change(tcp, state) 0
1450# define get_arg0(tcp, cookie, valp) \
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001451 (upeek((tcp), arg0_offset, (valp)))
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001452# define get_arg1(tcp, cookie, valp) \
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001453 (upeek((tcp), arg1_offset, (valp)))
Roland McGrathd81f1d92003-01-09 06:53:34 +00001454
1455static int
Denys Vlasenko12014262011-05-30 14:00:14 +02001456set_arg0(struct tcb *tcp, void *cookie, long val)
Roland McGrathd81f1d92003-01-09 06:53:34 +00001457{
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001458 return ptrace(PTRACE_POKEUSER, tcp->pid, (char*)arg0_offset, val);
Roland McGrathd81f1d92003-01-09 06:53:34 +00001459}
1460
1461static int
Denys Vlasenko12014262011-05-30 14:00:14 +02001462set_arg1(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*)arg1_offset, val);
Roland McGrathd81f1d92003-01-09 06:53:34 +00001465}
1466
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001467# endif /* architectures */
Roland McGrathd81f1d92003-01-09 06:53:34 +00001468
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001469# ifndef restore_arg0
1470# define restore_arg0(tcp, state, val) set_arg0((tcp), (state), (val))
1471# endif
1472# ifndef restore_arg1
1473# define restore_arg1(tcp, state, val) set_arg1((tcp), (state), (val))
1474# endif
Roland McGrathd81f1d92003-01-09 06:53:34 +00001475
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001476# ifndef arg0_index
1477# define arg0_index 0
1478# define arg1_index 1
1479# endif
Roland McGrath90d0afd2004-03-01 21:05:16 +00001480
Roland McGrathd81f1d92003-01-09 06:53:34 +00001481int
Denys Vlasenko418d66a2009-01-17 01:52:54 +00001482setbpt(struct tcb *tcp)
Roland McGrathd81f1d92003-01-09 06:53:34 +00001483{
Roland McGrath3291ef22008-05-20 00:34:34 +00001484 static int clone_scno[SUPPORTED_PERSONALITIES] = { SYS_clone };
Roland McGrathd81f1d92003-01-09 06:53:34 +00001485 arg_setup_state state;
1486
1487 if (tcp->flags & TCB_BPTSET) {
1488 fprintf(stderr, "PANIC: TCB already set in pid %u\n", tcp->pid);
1489 return -1;
1490 }
1491
Roland McGrath3291ef22008-05-20 00:34:34 +00001492 /*
1493 * It's a silly kludge to initialize this with a search at runtime.
1494 * But it's better than maintaining another magic thing in the
1495 * godforsaken tables.
1496 */
1497 if (clone_scno[current_personality] == 0) {
1498 int i;
1499 for (i = 0; i < nsyscalls; ++i)
1500 if (sysent[i].sys_func == sys_clone) {
1501 clone_scno[current_personality] = i;
1502 break;
1503 }
1504 }
1505
Roland McGrath76989d72005-06-07 23:21:31 +00001506 switch (known_scno(tcp)) {
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001507# ifdef SYS_vfork
Roland McGrath9383c6c2003-01-18 00:19:31 +00001508 case SYS_vfork:
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001509# endif
1510# ifdef SYS_fork
Roland McGrathd81f1d92003-01-09 06:53:34 +00001511 case SYS_fork:
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001512# endif
1513# if defined SYS_fork || defined SYS_vfork
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001514 if (arg_setup(tcp, &state) < 0
1515 || get_arg0(tcp, &state, &tcp->inst[0]) < 0
1516 || get_arg1(tcp, &state, &tcp->inst[1]) < 0
Roland McGrath3291ef22008-05-20 00:34:34 +00001517 || change_syscall(tcp, clone_scno[current_personality]) < 0
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001518 || set_arg0(tcp, &state, CLONE_PTRACE|SIGCHLD) < 0
1519 || set_arg1(tcp, &state, 0) < 0
1520 || arg_finish_change(tcp, &state) < 0)
Roland McGrathd81f1d92003-01-09 06:53:34 +00001521 return -1;
Roland McGrathc9dc3c12004-03-01 20:57:09 +00001522 tcp->u_arg[arg0_index] = CLONE_PTRACE|SIGCHLD;
1523 tcp->u_arg[arg1_index] = 0;
Roland McGrathd81f1d92003-01-09 06:53:34 +00001524 tcp->flags |= TCB_BPTSET;
1525 return 0;
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001526# endif
Roland McGrathd81f1d92003-01-09 06:53:34 +00001527
Denys Vlasenkoc133bf02011-06-23 21:57:54 +02001528 case SYS_clone: ;
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001529# ifdef SYS_clone2
Denys Vlasenkoc133bf02011-06-23 21:57:54 +02001530 case SYS_clone2: ;
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001531# endif
Jan Kratochvil8fc95752008-08-06 21:43:35 +00001532 /* ia64 calls directly `clone (CLONE_VFORK | CLONE_VM)'
1533 contrary to x86 SYS_vfork above. Even on x86 we turn the
1534 vfork semantics into plain fork - each application must not
1535 depend on the vfork specifics according to POSIX. We would
1536 hang waiting for the parent resume otherwise. We need to
1537 clear also CLONE_VM but only in the CLONE_VFORK case as
1538 otherwise we would break pthread_create. */
1539
Denys Vlasenkoc133bf02011-06-23 21:57:54 +02001540 long new_arg0 = (tcp->u_arg[arg0_index] | CLONE_PTRACE);
1541 if (new_arg0 & CLONE_VFORK)
1542 new_arg0 &= ~(unsigned long)(CLONE_VFORK | CLONE_VM);
1543 if (arg_setup(tcp, &state) < 0
1544 || set_arg0(tcp, &state, new_arg0) < 0
1545 || arg_finish_change(tcp, &state) < 0)
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00001546 return -1;
Roland McGrathd81f1d92003-01-09 06:53:34 +00001547 tcp->flags |= TCB_BPTSET;
Roland McGrathc9dc3c12004-03-01 20:57:09 +00001548 tcp->inst[0] = tcp->u_arg[arg0_index];
1549 tcp->inst[1] = tcp->u_arg[arg1_index];
Roland McGrathd81f1d92003-01-09 06:53:34 +00001550 return 0;
1551
1552 default:
1553 fprintf(stderr, "PANIC: setbpt for syscall %ld on %u???\n",
1554 tcp->scno, tcp->pid);
1555 break;
1556 }
1557
1558 return -1;
1559}
1560
1561int
Denys Vlasenko12014262011-05-30 14:00:14 +02001562clearbpt(struct tcb *tcp)
Roland McGrathd81f1d92003-01-09 06:53:34 +00001563{
1564 arg_setup_state state;
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001565 if (arg_setup(tcp, &state) < 0
1566 || restore_arg0(tcp, &state, tcp->inst[0]) < 0
1567 || restore_arg1(tcp, &state, tcp->inst[1]) < 0
1568 || arg_finish_change(tcp, &state))
Denys Vlasenkoc133bf02011-06-23 21:57:54 +02001569 if (errno != ESRCH)
1570 return -1;
Roland McGrathd81f1d92003-01-09 06:53:34 +00001571 tcp->flags &= ~TCB_BPTSET;
1572 return 0;
1573}
1574
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001575# else /* !defined LINUX */
Roland McGrathd81f1d92003-01-09 06:53:34 +00001576
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001577int
Denys Vlasenko12014262011-05-30 14:00:14 +02001578setbpt(struct tcb *tcp)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001579{
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001580# ifdef SUNOS4
1581# ifdef SPARC /* This code is slightly sparc specific */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001582
Wichert Akkermane6f876c1999-06-22 15:28:30 +00001583 struct regs regs;
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001584# define BPT 0x91d02001 /* ta 1 */
1585# define LOOP 0x10800000 /* ba 0 */
1586# define LOOPA 0x30800000 /* ba,a 0 */
1587# define NOP 0x01000000
1588# if LOOPA
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001589 static int loopdeloop[1] = {LOOPA};
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001590# else
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001591 static int loopdeloop[2] = {LOOP, NOP};
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001592# endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001593
1594 if (tcp->flags & TCB_BPTSET) {
1595 fprintf(stderr, "PANIC: TCB already set in pid %u\n", tcp->pid);
1596 return -1;
1597 }
Roland McGratheb9e2e82009-06-02 16:49:22 -07001598 if (ptrace(PTRACE_GETREGS, tcp->pid, (char *)&regs, 0) < 0) {
1599 perror("setbpt: ptrace(PTRACE_GETREGS, ...)");
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001600 return -1;
1601 }
1602 tcp->baddr = regs.r_o7 + 8;
Roland McGratheb9e2e82009-06-02 16:49:22 -07001603 if (ptrace(PTRACE_READTEXT, tcp->pid, (char *)tcp->baddr,
1604 sizeof tcp->inst, (char *)tcp->inst) < 0) {
1605 perror("setbpt: ptrace(PTRACE_READTEXT, ...)");
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001606 return -1;
1607 }
1608
1609 /*
1610 * XXX - BRUTAL MODE ON
1611 * We cannot set a real BPT in the child, since it will not be
1612 * traced at the moment it will reach the trap and would probably
1613 * die with a core dump.
1614 * Thus, we are force our way in by taking out two instructions
1615 * and insert an eternal loop in stead, in expectance of the SIGSTOP
1616 * generated by out PTRACE_ATTACH.
1617 * Of cause, if we evaporate ourselves in the middle of all this...
1618 */
Roland McGratheb9e2e82009-06-02 16:49:22 -07001619 if (ptrace(PTRACE_WRITETEXT, tcp->pid, (char *) tcp->baddr,
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001620 sizeof loopdeloop, (char *) loopdeloop) < 0) {
Roland McGratheb9e2e82009-06-02 16:49:22 -07001621 perror("setbpt: ptrace(PTRACE_WRITETEXT, ...)");
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001622 return -1;
1623 }
1624 tcp->flags |= TCB_BPTSET;
1625
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001626# endif /* SPARC */
1627# endif /* SUNOS4 */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001628
1629 return 0;
1630}
1631
1632int
Denys Vlasenko12014262011-05-30 14:00:14 +02001633clearbpt(struct tcb *tcp)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001634{
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001635# ifdef SUNOS4
1636# ifdef SPARC
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001637
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001638# if !LOOPA
Wichert Akkermane6f876c1999-06-22 15:28:30 +00001639 struct regs regs;
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001640# endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001641
1642 if (!(tcp->flags & TCB_BPTSET)) {
1643 fprintf(stderr, "PANIC: TCB not set in pid %u\n", tcp->pid);
1644 return -1;
1645 }
Roland McGratheb9e2e82009-06-02 16:49:22 -07001646 if (ptrace(PTRACE_WRITETEXT, tcp->pid, (char *) tcp->baddr,
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001647 sizeof tcp->inst, (char *) tcp->inst) < 0) {
Roland McGratheb9e2e82009-06-02 16:49:22 -07001648 perror("clearbtp: ptrace(PTRACE_WRITETEXT, ...)");
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001649 return -1;
1650 }
1651 tcp->flags &= ~TCB_BPTSET;
1652
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001653# if !LOOPA
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001654 /*
1655 * Since we don't have a single instruction breakpoint, we may have
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001656 * to adjust the program counter after removing our `breakpoint'.
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001657 */
Roland McGratheb9e2e82009-06-02 16:49:22 -07001658 if (ptrace(PTRACE_GETREGS, tcp->pid, (char *)&regs, 0) < 0) {
1659 perror("clearbpt: ptrace(PTRACE_GETREGS, ...)");
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001660 return -1;
1661 }
Roland McGratheb9e2e82009-06-02 16:49:22 -07001662 if ((regs.r_pc < tcp->baddr) ||
1663 (regs.r_pc > tcp->baddr + 4)) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001664 /* The breakpoint has not been reached yet */
1665 if (debug)
1666 fprintf(stderr,
1667 "NOTE: PC not at bpt (pc %#x baddr %#x)\n",
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001668 regs.r_pc, tcp->baddr);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001669 return 0;
1670 }
1671 if (regs.r_pc != tcp->baddr)
1672 if (debug)
1673 fprintf(stderr, "NOTE: PC adjusted (%#x -> %#x\n",
1674 regs.r_pc, tcp->baddr);
1675
1676 regs.r_pc = tcp->baddr;
Roland McGratheb9e2e82009-06-02 16:49:22 -07001677 if (ptrace(PTRACE_SETREGS, tcp->pid, (char *)&regs, 0) < 0) {
1678 perror("clearbpt: ptrace(PTRACE_SETREGS, ...)");
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001679 return -1;
1680 }
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001681# endif /* LOOPA */
1682# endif /* SPARC */
1683# endif /* SUNOS4 */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001684
1685 return 0;
1686}
1687
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001688# endif /* !defined LINUX */
Roland McGrathd81f1d92003-01-09 06:53:34 +00001689
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001690#endif /* !USE_PROCFS */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001691
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001692
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001693#ifdef SUNOS4
1694
1695static int
Denys Vlasenko12014262011-05-30 14:00:14 +02001696getex(struct tcb *tcp, struct exec *hdr)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001697{
1698 int n;
1699
1700 for (n = 0; n < sizeof *hdr; n += 4) {
1701 long res;
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001702 if (upeek(tcp, uoff(u_exdata) + n, &res) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001703 return -1;
1704 memcpy(((char *) hdr) + n, &res, 4);
1705 }
1706 if (debug) {
1707 fprintf(stderr, "[struct exec: magic: %o version %u Mach %o\n",
1708 hdr->a_magic, hdr->a_toolversion, hdr->a_machtype);
1709 fprintf(stderr, "Text %lu Data %lu Bss %lu Syms %lu Entry %#lx]\n",
1710 hdr->a_text, hdr->a_data, hdr->a_bss, hdr->a_syms, hdr->a_entry);
1711 }
1712 return 0;
1713}
1714
1715int
Denys Vlasenko12014262011-05-30 14:00:14 +02001716fixvfork(struct tcb *tcp)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001717{
1718 int pid = tcp->pid;
1719 /*
1720 * Change `vfork' in a freshly exec'ed dynamically linked
1721 * executable's (internal) symbol table to plain old `fork'
1722 */
1723
1724 struct exec hdr;
1725 struct link_dynamic dyn;
1726 struct link_dynamic_2 ld;
1727 char *strtab, *cp;
1728
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001729 if (getex(tcp, &hdr) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001730 return -1;
1731 if (!hdr.a_dynamic)
1732 return -1;
1733
1734 if (umove(tcp, (int) N_DATADDR(hdr), &dyn) < 0) {
1735 fprintf(stderr, "Cannot read DYNAMIC\n");
1736 return -1;
1737 }
1738 if (umove(tcp, (int) dyn.ld_un.ld_2, &ld) < 0) {
1739 fprintf(stderr, "Cannot read link_dynamic_2\n");
1740 return -1;
1741 }
Denys Vlasenko5d645812011-08-20 12:48:18 +02001742 strtab = malloc((unsigned)ld.ld_symb_size);
Denys Vlasenko1d46ba52011-08-31 14:00:02 +02001743 if (!strtab)
1744 die_out_of_memory();
Roland McGratheb9e2e82009-06-02 16:49:22 -07001745 if (umoven(tcp, (int)ld.ld_symbols+(int)N_TXTADDR(hdr),
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001746 (int)ld.ld_symb_size, strtab) < 0)
1747 goto err;
1748
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001749 for (cp = strtab; cp < strtab + ld.ld_symb_size; ) {
1750 if (strcmp(cp, "_vfork") == 0) {
1751 if (debug)
1752 fprintf(stderr, "fixvfork: FOUND _vfork\n");
1753 strcpy(cp, "_fork");
1754 break;
1755 }
1756 cp += strlen(cp)+1;
1757 }
1758 if (cp < strtab + ld.ld_symb_size)
1759 /*
1760 * Write entire symbol table back to avoid
1761 * memory alignment bugs in ptrace
1762 */
Roland McGratheb9e2e82009-06-02 16:49:22 -07001763 if (tload(pid, (int)ld.ld_symbols+(int)N_TXTADDR(hdr),
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001764 (int)ld.ld_symb_size, strtab) < 0)
1765 goto err;
1766
1767 free(strtab);
1768 return 0;
1769
1770err:
1771 free(strtab);
1772 return -1;
1773}
1774
1775#endif /* SUNOS4 */