blob: 85207cdf52088ba87feb952c7fb8a48b00f30158 [file] [log] [blame]
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001/*
2 * Copyright (c) 1991, 1992 Paul Kranenburg <pk@cs.few.eur.nl>
3 * Copyright (c) 1993 Branko Lankester <branko@hacktic.nl>
4 * Copyright (c) 1993, 1994, 1995, 1996 Rick Sladkey <jrs@world.std.com>
Wichert Akkerman4dc8a2a1999-12-23 14:20:14 +00005 * Copyright (c) 1996-1999 Wichert Akkerman <wichert@cistron.nl>
6 * Copyright (c) 1999 IBM Deutschland Entwicklung GmbH, IBM Corporation
7 * Linux for s390 port by D.J. Barrow
8 * <barrow_dj@mail.yahoo.com,djbarrow@de.ibm.com>
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00009 * All rights reserved.
10 *
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions
13 * are met:
14 * 1. Redistributions of source code must retain the above copyright
15 * notice, this list of conditions and the following disclaimer.
16 * 2. Redistributions in binary form must reproduce the above copyright
17 * notice, this list of conditions and the following disclaimer in the
18 * documentation and/or other materials provided with the distribution.
19 * 3. The name of the author may not be used to endorse or promote products
20 * derived from this software without specific prior written permission.
21 *
22 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
23 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
24 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
25 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
26 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
27 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
28 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
29 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
30 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
31 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32 *
33 * $Id$
34 */
35
36#include "defs.h"
37
Roland McGrathd81f1d92003-01-09 06:53:34 +000038#include <signal.h>
39#include <sys/syscall.h>
Wichert Akkerman76baf7c1999-02-19 00:21:36 +000040#include <sys/user.h>
41#include <sys/param.h>
42#include <fcntl.h>
John Hughes1d08dcf2001-07-10 13:48:44 +000043#if HAVE_SYS_UIO_H
44#include <sys/uio.h>
45#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +000046#ifdef SUNOS4
47#include <machine/reg.h>
48#include <a.out.h>
49#include <link.h>
50#endif /* SUNOS4 */
Wichert Akkerman36915a11999-07-13 15:45:02 +000051
Wichert Akkerman43a74822000-06-27 17:33:32 +000052#if defined(linux) && (__GLIBC__ < 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ < 1))
Wichert Akkerman36915a11999-07-13 15:45:02 +000053#include <linux/ptrace.h>
Roland McGrath1e85cf92002-12-16 20:40:54 +000054#endif
Wichert Akkerman36915a11999-07-13 15:45:02 +000055
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +000056#if defined(LINUX) && defined(IA64)
Roland McGrathd81f1d92003-01-09 06:53:34 +000057# include <asm/ptrace_offsets.h>
58# include <asm/rse.h>
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +000059#endif
60
Wichert Akkerman36915a11999-07-13 15:45:02 +000061#ifdef HAVE_SYS_REG_H
62#include <sys/reg.h>
Wichert Akkerman76baf7c1999-02-19 00:21:36 +000063# define PTRACE_PEEKUSR PTRACE_PEEKUSER
Wichert Akkermanfaf72222000-02-19 23:59:03 +000064#elif defined(HAVE_LINUX_PTRACE_H)
65#undef PTRACE_SYSCALL
Roland McGrathce9f0742004-03-01 21:29:22 +000066# ifdef HAVE_STRUCT_IA64_FPREG
67# define ia64_fpreg XXX_ia64_fpreg
68# endif
69# ifdef HAVE_STRUCT_PT_ALL_USER_REGS
70# define pt_all_user_regs XXX_pt_all_user_regs
71# endif
Wichert Akkermanfaf72222000-02-19 23:59:03 +000072#include <linux/ptrace.h>
Roland McGrathce9f0742004-03-01 21:29:22 +000073# undef ia64_fpreg
74# undef pt_all_user_regs
Wichert Akkerman2e2553a1999-05-09 00:29:58 +000075#endif
76
Wichert Akkerman76baf7c1999-02-19 00:21:36 +000077#ifdef SUNOS4_KERNEL_ARCH_KLUDGE
78#include <sys/utsname.h>
79#endif /* SUNOS4_KERNEL_ARCH_KLUDGE */
80
Mike Frysinger8566c502009-10-12 11:05:14 -040081#if defined(LINUXSPARC) && defined (SPARC64)
Roland McGrath6d1a65c2004-07-12 07:44:08 +000082# undef PTRACE_GETREGS
83# define PTRACE_GETREGS PTRACE_GETREGS64
84# undef PTRACE_SETREGS
85# define PTRACE_SETREGS PTRACE_SETREGS64
Wichert Akkerman9ce1a631999-08-29 23:15:07 +000086#endif
87
Wichert Akkerman76baf7c1999-02-19 00:21:36 +000088/* macros */
89#ifndef MAX
90#define MAX(a,b) (((a) > (b)) ? (a) : (b))
91#endif
92#ifndef MIN
93#define MIN(a,b) (((a) < (b)) ? (a) : (b))
94#endif
95
Wichert Akkerman76baf7c1999-02-19 00:21:36 +000096int
Denys Vlasenko12014262011-05-30 14:00:14 +020097tv_nz(struct timeval *a)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +000098{
99 return a->tv_sec || a->tv_usec;
100}
101
102int
Denys Vlasenko12014262011-05-30 14:00:14 +0200103tv_cmp(struct timeval *a, struct timeval *b)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000104{
105 if (a->tv_sec < b->tv_sec
106 || (a->tv_sec == b->tv_sec && a->tv_usec < b->tv_usec))
107 return -1;
108 if (a->tv_sec > b->tv_sec
109 || (a->tv_sec == b->tv_sec && a->tv_usec > b->tv_usec))
110 return 1;
111 return 0;
112}
113
114double
Denys Vlasenko12014262011-05-30 14:00:14 +0200115tv_float(struct timeval *tv)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000116{
117 return tv->tv_sec + tv->tv_usec/1000000.0;
118}
119
120void
Denys Vlasenko12014262011-05-30 14:00:14 +0200121tv_add(struct timeval *tv, struct timeval *a, struct timeval *b)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000122{
123 tv->tv_sec = a->tv_sec + b->tv_sec;
124 tv->tv_usec = a->tv_usec + b->tv_usec;
Roland McGrath58372f52007-07-24 01:38:22 +0000125 if (tv->tv_usec >= 1000000) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000126 tv->tv_sec++;
127 tv->tv_usec -= 1000000;
128 }
129}
130
131void
Denys Vlasenko12014262011-05-30 14:00:14 +0200132tv_sub(struct timeval *tv, struct timeval *a, struct timeval *b)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000133{
134 tv->tv_sec = a->tv_sec - b->tv_sec;
135 tv->tv_usec = a->tv_usec - b->tv_usec;
136 if (((long) tv->tv_usec) < 0) {
137 tv->tv_sec--;
138 tv->tv_usec += 1000000;
139 }
140}
141
142void
Denys Vlasenko12014262011-05-30 14:00:14 +0200143tv_div(struct timeval *tv, struct timeval *a, int n)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000144{
145 tv->tv_usec = (a->tv_sec % n * 1000000 + a->tv_usec + n / 2) / n;
146 tv->tv_sec = a->tv_sec / n + tv->tv_usec / 1000000;
147 tv->tv_usec %= 1000000;
148}
149
150void
Denys Vlasenko12014262011-05-30 14:00:14 +0200151tv_mul(struct timeval *tv, struct timeval *a, int n)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000152{
153 tv->tv_usec = a->tv_usec * n;
Dmitry V. Levinfefdd972007-06-29 21:25:56 +0000154 tv->tv_sec = a->tv_sec * n + tv->tv_usec / 1000000;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000155 tv->tv_usec %= 1000000;
156}
157
Dmitry V. Levinab9008b2007-01-11 22:05:04 +0000158const char *
159xlookup(const struct xlat *xlat, int val)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000160{
161 for (; xlat->str != NULL; xlat++)
162 if (xlat->val == val)
163 return xlat->str;
164 return NULL;
165}
166
Denys Vlasenko0a295bc2011-09-01 16:31:48 +0200167#if !defined HAVE_STPCPY
Denys Vlasenko52845572011-08-31 12:07:38 +0200168char *
169stpcpy(char *dst, const char *src)
170{
171 while ((*dst = *src++) != '\0')
172 dst++;
173 return dst;
174}
Denys Vlasenko0a295bc2011-09-01 16:31:48 +0200175#endif
Denys Vlasenko52845572011-08-31 12:07:38 +0200176
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000177/*
Roland McGratheb9e2e82009-06-02 16:49:22 -0700178 * Generic ptrace wrapper which tracks ESRCH errors
179 * by setting tcp->ptrace_errno to ESRCH.
Denys Vlasenko732d1bf2008-12-17 19:21:59 +0000180 *
181 * We assume that ESRCH indicates likely process death (SIGKILL?),
182 * modulo bugs where process somehow ended up not stopped.
183 * Unfortunately kernel uses ESRCH for that case too. Oh well.
Roland McGratheb9e2e82009-06-02 16:49:22 -0700184 *
185 * Currently used by upeek() only.
186 * TODO: use this in all other ptrace() calls while decoding.
Denys Vlasenko732d1bf2008-12-17 19:21:59 +0000187 */
Denys Vlasenko4dedd562009-02-24 15:17:53 +0000188long
Roland McGratheb9e2e82009-06-02 16:49:22 -0700189do_ptrace(int request, struct tcb *tcp, void *addr, void *data)
Denys Vlasenko4dedd562009-02-24 15:17:53 +0000190{
Denys Vlasenko732d1bf2008-12-17 19:21:59 +0000191 long l;
192
193 errno = 0;
Mike Frysinger09a13c22009-10-07 01:13:39 -0400194 l = ptrace(request, tcp->pid, addr, (long) data);
Roland McGratheb9e2e82009-06-02 16:49:22 -0700195 /* Non-ESRCH errors might be our invalid reg/mem accesses,
196 * we do not record them. */
197 if (errno == ESRCH)
198 tcp->ptrace_errno = ESRCH;
Denys Vlasenko732d1bf2008-12-17 19:21:59 +0000199 return l;
200}
201
202/*
203 * Used when we want to unblock stopped traced process.
204 * Should be only used with PTRACE_CONT, PTRACE_DETACH and PTRACE_SYSCALL.
205 * Returns 0 on success or if error was ESRCH
206 * (presumably process was killed while we talk to it).
207 * Otherwise prints error message and returns -1.
208 */
209int
Roland McGratheb9e2e82009-06-02 16:49:22 -0700210ptrace_restart(int op, struct tcb *tcp, int sig)
Denys Vlasenko732d1bf2008-12-17 19:21:59 +0000211{
212 int err;
Roland McGratheb9e2e82009-06-02 16:49:22 -0700213 const char *msg;
Denys Vlasenko732d1bf2008-12-17 19:21:59 +0000214
215 errno = 0;
Mike Frysinger09a13c22009-10-07 01:13:39 -0400216 ptrace(op, tcp->pid, (void *) 1, (long) sig);
Denys Vlasenko732d1bf2008-12-17 19:21:59 +0000217 err = errno;
218 if (!err || err == ESRCH)
219 return 0;
220
221 tcp->ptrace_errno = err;
Roland McGratheb9e2e82009-06-02 16:49:22 -0700222 msg = "SYSCALL";
223 if (op == PTRACE_CONT)
224 msg = "CONT";
225 if (op == PTRACE_DETACH)
226 msg = "DETACH";
Denys Vlasenko014ca3a2011-09-02 16:19:30 +0200227 perror_msg("ptrace(PTRACE_%s,1,%d)", msg, sig);
Denys Vlasenko732d1bf2008-12-17 19:21:59 +0000228 return -1;
229}
230
231/*
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000232 * Print entry in struct xlat table, if there.
233 */
234void
Dmitry V. Levinab9008b2007-01-11 22:05:04 +0000235printxval(const struct xlat *xlat, int val, const char *dflt)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000236{
Dmitry V. Levinab9008b2007-01-11 22:05:04 +0000237 const char *str = xlookup(xlat, val);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000238
239 if (str)
Denys Vlasenko5940e652011-09-01 09:55:05 +0200240 tprints(str);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000241 else
242 tprintf("%#x /* %s */", val, dflt);
243}
244
Andreas Schwabb5600fc2009-11-04 17:08:34 +0100245#if HAVE_LONG_LONG
246/*
247 * Print 64bit argument at position llarg and return the index of the next
248 * argument.
249 */
250int
251printllval(struct tcb *tcp, const char *format, int llarg)
252{
253# if defined(FREEBSD) \
Andreas Schwabd69fa492010-07-12 21:39:57 +0200254 || (defined(LINUX) && defined(POWERPC) && !defined(POWERPC64)) \
Dmitry V. Levin7a5b08f2011-05-28 20:47:43 +0000255 || defined(LINUX_MIPSO32) \
256 || defined(__ARM_EABI__)
Andreas Schwabb5600fc2009-11-04 17:08:34 +0100257 /* Align 64bit argument to 64bit boundary. */
Denys Vlasenko4b08df42011-08-19 15:58:24 +0200258 llarg = (llarg + 1) & 0x1e;
Andreas Schwabb5600fc2009-11-04 17:08:34 +0100259# endif
Andreas Schwabd69fa492010-07-12 21:39:57 +0200260# if defined LINUX && (defined X86_64 || defined POWERPC64)
Andreas Schwabb5600fc2009-11-04 17:08:34 +0100261 if (current_personality == 0) {
262 tprintf(format, tcp->u_arg[llarg]);
263 llarg++;
264 } else {
Andreas Schwabd69fa492010-07-12 21:39:57 +0200265# ifdef POWERPC64
266 /* Align 64bit argument to 64bit boundary. */
Denys Vlasenko4b08df42011-08-19 15:58:24 +0200267 llarg = (llarg + 1) & 0x1e;
Andreas Schwabd69fa492010-07-12 21:39:57 +0200268# endif
Andreas Schwabb5600fc2009-11-04 17:08:34 +0100269 tprintf(format, LONG_LONG(tcp->u_arg[llarg], tcp->u_arg[llarg + 1]));
270 llarg += 2;
271 }
Andreas Schwabd69fa492010-07-12 21:39:57 +0200272# elif defined IA64 || defined ALPHA
Andreas Schwabb5600fc2009-11-04 17:08:34 +0100273 tprintf(format, tcp->u_arg[llarg]);
274 llarg++;
275# elif defined LINUX_MIPSN32
276 tprintf(format, tcp->ext_arg[llarg]);
277 llarg++;
278# else
279 tprintf(format, LONG_LONG(tcp->u_arg[llarg], tcp->u_arg[llarg + 1]));
280 llarg += 2;
281# endif
282 return llarg;
283}
284#endif
285
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000286/*
287 * Interpret `xlat' as an array of flags
288 * print the entries whose bits are on in `flags'
289 * return # of flags printed.
290 */
Denys Vlasenko4924dbd2011-08-19 18:06:46 +0200291void
Denys Vlasenko12014262011-05-30 14:00:14 +0200292addflags(const struct xlat *xlat, int flags)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000293{
Denys Vlasenko4924dbd2011-08-19 18:06:46 +0200294 for (; xlat->str; xlat++) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000295 if (xlat->val && (flags & xlat->val) == xlat->val) {
296 tprintf("|%s", xlat->str);
297 flags &= ~xlat->val;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000298 }
299 }
300 if (flags) {
301 tprintf("|%#x", flags);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000302 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000303}
304
Roland McGratha6c0d8c2007-11-01 21:46:22 +0000305/*
Denys Vlasenko4924dbd2011-08-19 18:06:46 +0200306 * Interpret `xlat' as an array of flags.
Roland McGratha6c0d8c2007-11-01 21:46:22 +0000307 * Print to static string the entries whose bits are on in `flags'
308 * Return static string.
309 */
310const char *
311sprintflags(const char *prefix, const struct xlat *xlat, int flags)
312{
313 static char outstr[1024];
Denys Vlasenko52845572011-08-31 12:07:38 +0200314 char *outptr;
Roland McGratha6c0d8c2007-11-01 21:46:22 +0000315 int found = 0;
316
Denys Vlasenko52845572011-08-31 12:07:38 +0200317 outptr = stpcpy(outstr, prefix);
Roland McGratha6c0d8c2007-11-01 21:46:22 +0000318
319 for (; xlat->str; xlat++) {
320 if ((flags & xlat->val) == xlat->val) {
321 if (found)
Denys Vlasenko52845572011-08-31 12:07:38 +0200322 *outptr++ = '|';
323 outptr = stpcpy(outptr, xlat->str);
Roland McGratha6c0d8c2007-11-01 21:46:22 +0000324 flags &= ~xlat->val;
325 found = 1;
326 }
327 }
328 if (flags) {
329 if (found)
Denys Vlasenko52845572011-08-31 12:07:38 +0200330 *outptr++ = '|';
331 outptr += sprintf(outptr, "%#x", flags);
Roland McGratha6c0d8c2007-11-01 21:46:22 +0000332 }
333
334 return outstr;
335}
336
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000337int
Dmitry V. Levin30145dd2010-09-06 22:08:24 +0000338printflags(const struct xlat *xlat, int flags, const char *dflt)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000339{
340 int n;
Dmitry V. Levin30145dd2010-09-06 22:08:24 +0000341 const char *sep;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000342
343 if (flags == 0 && xlat->val == 0) {
Denys Vlasenko5940e652011-09-01 09:55:05 +0200344 tprints(xlat->str);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000345 return 1;
346 }
347
348 sep = "";
349 for (n = 0; xlat->str; xlat++) {
350 if (xlat->val && (flags & xlat->val) == xlat->val) {
351 tprintf("%s%s", sep, xlat->str);
352 flags &= ~xlat->val;
353 sep = "|";
354 n++;
355 }
356 }
Roland McGrathb2dee132005-06-01 19:02:36 +0000357
358 if (n) {
359 if (flags) {
360 tprintf("%s%#x", sep, flags);
361 n++;
362 }
363 } else {
364 if (flags) {
365 tprintf("%#x", flags);
366 if (dflt)
367 tprintf(" /* %s */", dflt);
368 } else {
369 if (dflt)
Denys Vlasenko60fe8c12011-09-01 10:00:28 +0200370 tprints("0");
Roland McGrathb2dee132005-06-01 19:02:36 +0000371 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000372 }
Roland McGrathb2dee132005-06-01 19:02:36 +0000373
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000374 return n;
375}
376
377void
Dmitry V. Levin30145dd2010-09-06 22:08:24 +0000378printnum(struct tcb *tcp, long addr, const char *fmt)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000379{
Roland McGratheb285352003-01-14 09:59:00 +0000380 long num;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000381
382 if (!addr) {
Denys Vlasenko60fe8c12011-09-01 10:00:28 +0200383 tprints("NULL");
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000384 return;
385 }
386 if (umove(tcp, addr, &num) < 0) {
387 tprintf("%#lx", addr);
388 return;
389 }
Denys Vlasenko60fe8c12011-09-01 10:00:28 +0200390 tprints("[");
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000391 tprintf(fmt, num);
Denys Vlasenko60fe8c12011-09-01 10:00:28 +0200392 tprints("]");
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000393}
394
Roland McGrath6bc12202003-11-13 22:32:27 +0000395void
Dmitry V. Levin30145dd2010-09-06 22:08:24 +0000396printnum_int(struct tcb *tcp, long addr, const char *fmt)
Roland McGrath9814a942005-07-04 23:28:10 +0000397{
398 int num;
399
400 if (!addr) {
Denys Vlasenko60fe8c12011-09-01 10:00:28 +0200401 tprints("NULL");
Roland McGrath9814a942005-07-04 23:28:10 +0000402 return;
403 }
404 if (umove(tcp, addr, &num) < 0) {
405 tprintf("%#lx", addr);
406 return;
407 }
Denys Vlasenko60fe8c12011-09-01 10:00:28 +0200408 tprints("[");
Roland McGrath9814a942005-07-04 23:28:10 +0000409 tprintf(fmt, num);
Denys Vlasenko60fe8c12011-09-01 10:00:28 +0200410 tprints("]");
Roland McGrath9814a942005-07-04 23:28:10 +0000411}
412
413void
Dmitry V. Levin31382132011-03-04 05:08:02 +0300414printfd(struct tcb *tcp, int fd)
415{
Grant Edwards8a082772011-04-07 20:25:40 +0000416 const char *p;
417
418 if (show_fd_path && (p = getfdpath(tcp, fd)))
419 tprintf("%d<%s>", fd, p);
420 else
421 tprintf("%d", fd);
Dmitry V. Levin31382132011-03-04 05:08:02 +0300422}
423
424void
Denys Vlasenko12014262011-05-30 14:00:14 +0200425printuid(const char *text, unsigned long uid)
Roland McGrath6bc12202003-11-13 22:32:27 +0000426{
Denys Vlasenko5940e652011-09-01 09:55:05 +0200427 tprintf((uid == -1) ? "%s%ld" : "%s%lu", text, uid);
Roland McGrath6bc12202003-11-13 22:32:27 +0000428}
429
Dmitry V. Levina501f142008-11-10 23:19:13 +0000430/*
431 * Quote string `instr' of length `size'
432 * Write up to (3 + `size' * 4) bytes to `outstr' buffer.
433 * If `len' < 0, treat `instr' as a NUL-terminated string
434 * and quote at most (`size' - 1) bytes.
Denys Vlasenko6cecba52012-01-20 11:56:00 +0100435 *
436 * Returns 0 if len < 0 and NUL was seen, 1 otherwise.
437 * Note that if len >= 0, always returns 1.
Dmitry V. Levina501f142008-11-10 23:19:13 +0000438 */
Roland McGrath6d970322007-11-01 23:53:59 +0000439static int
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000440string_quote(const char *instr, char *outstr, int len, int size)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000441{
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000442 const unsigned char *ustr = (const unsigned char *) instr;
443 char *s = outstr;
Denys Vlasenko8778bff2011-08-31 12:22:56 +0200444 int usehex, c, i, eol;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000445
Denys Vlasenko8778bff2011-08-31 12:22:56 +0200446 eol = 0x100; /* this can never match a char */
447 if (len < 0) {
448 size--;
449 eol = '\0';
450 }
451
452 usehex = 0;
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000453 if (xflag > 1)
454 usehex = 1;
455 else if (xflag) {
Dmitry V. Levina501f142008-11-10 23:19:13 +0000456 /* Check for presence of symbol which require
457 to hex-quote the whole string. */
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000458 for (i = 0; i < size; ++i) {
459 c = ustr[i];
Dmitry V. Levina501f142008-11-10 23:19:13 +0000460 /* Check for NUL-terminated string. */
Denys Vlasenko8778bff2011-08-31 12:22:56 +0200461 if (c == eol)
462 break;
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000463 if (!isprint(c) && !isspace(c)) {
464 usehex = 1;
465 break;
466 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000467 }
468 }
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000469
470 *s++ = '\"';
471
472 if (usehex) {
Dmitry V. Levina501f142008-11-10 23:19:13 +0000473 /* Hex-quote the whole string. */
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000474 for (i = 0; i < size; ++i) {
475 c = ustr[i];
Dmitry V. Levina501f142008-11-10 23:19:13 +0000476 /* Check for NUL-terminated string. */
Denys Vlasenko8778bff2011-08-31 12:22:56 +0200477 if (c == eol)
478 goto asciz_ended;
479 *s++ = '\\';
480 *s++ = 'x';
481 *s++ = "0123456789abcdef"[c >> 4];
482 *s++ = "0123456789abcdef"[c & 0xf];
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000483 }
484 } else {
485 for (i = 0; i < size; ++i) {
486 c = ustr[i];
Dmitry V. Levina501f142008-11-10 23:19:13 +0000487 /* Check for NUL-terminated string. */
Denys Vlasenko8778bff2011-08-31 12:22:56 +0200488 if (c == eol)
489 goto asciz_ended;
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000490 switch (c) {
491 case '\"': case '\\':
492 *s++ = '\\';
493 *s++ = c;
494 break;
495 case '\f':
496 *s++ = '\\';
497 *s++ = 'f';
498 break;
499 case '\n':
500 *s++ = '\\';
501 *s++ = 'n';
502 break;
503 case '\r':
504 *s++ = '\\';
505 *s++ = 'r';
506 break;
507 case '\t':
508 *s++ = '\\';
509 *s++ = 't';
510 break;
511 case '\v':
512 *s++ = '\\';
513 *s++ = 'v';
514 break;
515 default:
516 if (isprint(c))
517 *s++ = c;
Denys Vlasenko8778bff2011-08-31 12:22:56 +0200518 else {
519 /* Print \octal */
520 *s++ = '\\';
521 if (i + 1 < size
522 && ustr[i + 1] >= '0'
523 && ustr[i + 1] <= '9'
524 ) {
525 /* Print \ooo */
526 *s++ = '0' + (c >> 6);
527 *s++ = '0' + ((c >> 3) & 0x7);
528 } else {
529 /* Print \[[o]o]o */
530 if ((c >> 3) != 0) {
531 if ((c >> 6) != 0)
532 *s++ = '0' + (c >> 6);
533 *s++ = '0' + ((c >> 3) & 0x7);
534 }
535 }
536 *s++ = '0' + (c & 0x7);
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000537 }
538 break;
539 }
540 }
541 }
542
543 *s++ = '\"';
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000544 *s = '\0';
Roland McGrath6d970322007-11-01 23:53:59 +0000545
Denys Vlasenko8778bff2011-08-31 12:22:56 +0200546 /* Return zero if we printed entire ASCIZ string (didn't truncate it) */
547 if (len < 0 && ustr[i] == '\0') {
548 /* We didn't see NUL yet (otherwise we'd jump to 'asciz_ended')
549 * but next char is NUL.
550 */
551 return 0;
552 }
553
554 return 1;
555
556 asciz_ended:
557 *s++ = '\"';
558 *s = '\0';
559 /* Return zero: we printed entire ASCIZ string (didn't truncate it) */
560 return 0;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000561}
562
Dmitry V. Levina501f142008-11-10 23:19:13 +0000563/*
564 * Print path string specified by address `addr' and length `n'.
565 * If path length exceeds `n', append `...' to the output.
566 */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000567void
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000568printpathn(struct tcb *tcp, long addr, int n)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000569{
Denys Vlasenkob3c52cf2012-01-19 17:20:23 +0100570 char path[MAXPATHLEN + 1];
Denys Vlasenko6cecba52012-01-20 11:56:00 +0100571 int nul_seen;
Denys Vlasenkob3c52cf2012-01-19 17:20:23 +0100572
Dmitry V. Levina501f142008-11-10 23:19:13 +0000573 if (!addr) {
Denys Vlasenko60fe8c12011-09-01 10:00:28 +0200574 tprints("NULL");
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000575 return;
576 }
577
Denys Vlasenko6cecba52012-01-20 11:56:00 +0100578 /* Cap path length to the path buffer size */
Dmitry V. Levina501f142008-11-10 23:19:13 +0000579 if (n > sizeof path - 1)
580 n = sizeof path - 1;
Dmitry V. Levina501f142008-11-10 23:19:13 +0000581
582 /* Fetch one byte more to find out whether path length > n. */
Denys Vlasenko6cecba52012-01-20 11:56:00 +0100583 nul_seen = umovestr(tcp, addr, n + 1, path);
584 if (nul_seen < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000585 tprintf("%#lx", addr);
586 else {
Denys Vlasenkob3c52cf2012-01-19 17:20:23 +0100587 char *outstr;
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000588
Denys Vlasenko6cecba52012-01-20 11:56:00 +0100589 path[n] = '\0';
Denys Vlasenkob3c52cf2012-01-19 17:20:23 +0100590 n++;
Denys Vlasenko6cecba52012-01-20 11:56:00 +0100591 outstr = alloca(4 * n); /* 4*(n-1) + 3 for quotes and NUL */
Denys Vlasenkob3c52cf2012-01-19 17:20:23 +0100592 string_quote(path, outstr, -1, n);
593 tprints(outstr);
Denys Vlasenko6cecba52012-01-20 11:56:00 +0100594 if (!nul_seen)
Denys Vlasenkob3c52cf2012-01-19 17:20:23 +0100595 tprints("...");
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000596 }
597}
598
599void
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000600printpath(struct tcb *tcp, long addr)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000601{
Denys Vlasenkob3c52cf2012-01-19 17:20:23 +0100602 /* Size must correspond to char path[] size in printpathn */
603 printpathn(tcp, addr, MAXPATHLEN);
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000604}
605
Dmitry V. Levina501f142008-11-10 23:19:13 +0000606/*
607 * Print string specified by address `addr' and length `len'.
608 * If `len' < 0, treat the string as a NUL-terminated string.
609 * If string length exceeds `max_strlen', append `...' to the output.
610 */
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000611void
612printstr(struct tcb *tcp, long addr, int len)
613{
614 static char *str = NULL;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000615 static char *outstr;
Roland McGrath6d970322007-11-01 23:53:59 +0000616 int size;
Denys Vlasenkob3c52cf2012-01-19 17:20:23 +0100617 int ellipsis;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000618
619 if (!addr) {
Denys Vlasenko60fe8c12011-09-01 10:00:28 +0200620 tprints("NULL");
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000621 return;
622 }
Dmitry V. Levina501f142008-11-10 23:19:13 +0000623 /* Allocate static buffers if they are not allocated yet. */
Denys Vlasenko1d46ba52011-08-31 14:00:02 +0200624 if (!str) {
Dmitry V. Levina501f142008-11-10 23:19:13 +0000625 str = malloc(max_strlen + 1);
Denys Vlasenko1d46ba52011-08-31 14:00:02 +0200626 if (!str)
627 die_out_of_memory();
Denys Vlasenko6cecba52012-01-20 11:56:00 +0100628 outstr = malloc(4 * max_strlen + /*for quotes and NUL:*/ 3);
Denys Vlasenko1d46ba52011-08-31 14:00:02 +0200629 if (!outstr)
630 die_out_of_memory();
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000631 }
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000632
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000633 if (len < 0) {
Dmitry V. Levina501f142008-11-10 23:19:13 +0000634 /*
635 * Treat as a NUL-terminated string: fetch one byte more
636 * because string_quote() quotes one byte less.
637 */
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000638 size = max_strlen + 1;
639 if (umovestr(tcp, addr, size, str) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000640 tprintf("%#lx", addr);
641 return;
642 }
643 }
644 else {
Dmitry V. Levina501f142008-11-10 23:19:13 +0000645 size = MIN(len, max_strlen);
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000646 if (umoven(tcp, addr, size, str) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000647 tprintf("%#lx", addr);
648 return;
649 }
650 }
651
Denys Vlasenko6cecba52012-01-20 11:56:00 +0100652 /* If string_quote didn't see NUL and (it was supposed to be ASCIZ str
653 * or we were requested to print more than -s NUM chars)...
654 */
Denys Vlasenkob3c52cf2012-01-19 17:20:23 +0100655 ellipsis = (string_quote(str, outstr, len, size) &&
656 (len < 0 || len > max_strlen));
Roland McGratha503dcf2007-08-02 02:06:26 +0000657
Denys Vlasenkob3c52cf2012-01-19 17:20:23 +0100658 tprints(outstr);
659 if (ellipsis)
660 tprints("...");
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000661}
662
John Hughes1d08dcf2001-07-10 13:48:44 +0000663#if HAVE_SYS_UIO_H
664void
Denys Vlasenko12014262011-05-30 14:00:14 +0200665dumpiov(struct tcb *tcp, int len, long addr)
John Hughes1d08dcf2001-07-10 13:48:44 +0000666{
Dmitry V. Levin4ebb4e32006-12-13 17:08:08 +0000667#if defined(LINUX) && SUPPORTED_PERSONALITIES > 1
668 union {
669 struct { u_int32_t base; u_int32_t len; } *iov32;
670 struct { u_int64_t base; u_int64_t len; } *iov64;
671 } iovu;
672#define iov iovu.iov64
673#define sizeof_iov \
674 (personality_wordsize[current_personality] == 4 \
675 ? sizeof(*iovu.iov32) : sizeof(*iovu.iov64))
676#define iov_iov_base(i) \
677 (personality_wordsize[current_personality] == 4 \
678 ? (u_int64_t) iovu.iov32[i].base : iovu.iov64[i].base)
679#define iov_iov_len(i) \
680 (personality_wordsize[current_personality] == 4 \
681 ? (u_int64_t) iovu.iov32[i].len : iovu.iov64[i].len)
682#else
John Hughes1d08dcf2001-07-10 13:48:44 +0000683 struct iovec *iov;
Dmitry V. Levin4ebb4e32006-12-13 17:08:08 +0000684#define sizeof_iov sizeof(*iov)
685#define iov_iov_base(i) iov[i].iov_base
686#define iov_iov_len(i) iov[i].iov_len
687#endif
John Hughes1d08dcf2001-07-10 13:48:44 +0000688 int i;
Denys Vlasenko79a79ea2011-09-01 16:35:44 +0200689 unsigned size;
John Hughes1d08dcf2001-07-10 13:48:44 +0000690
Denys Vlasenko79a79ea2011-09-01 16:35:44 +0200691 size = sizeof_iov * len;
692 /* Assuming no sane program has millions of iovs */
693 if ((unsigned)len > 1024*1024 /* insane or negative size? */
Dmitry V. Levin4ebb4e32006-12-13 17:08:08 +0000694 || (iov = malloc(size)) == NULL) {
Denys Vlasenko79a79ea2011-09-01 16:35:44 +0200695 fprintf(stderr, "Out of memory\n");
696 return;
John Hughes1d08dcf2001-07-10 13:48:44 +0000697 }
Roland McGrathaa524c82005-06-01 19:22:06 +0000698 if (umoven(tcp, addr, size, (char *) iov) >= 0) {
John Hughes1d08dcf2001-07-10 13:48:44 +0000699 for (i = 0; i < len; i++) {
Denys Vlasenkoadedb512008-12-30 18:47:55 +0000700 /* include the buffer number to make it easy to
701 * match up the trace with the source */
702 tprintf(" * %lu bytes in buffer %d\n",
703 (unsigned long)iov_iov_len(i), i);
704 dumpstr(tcp, (long) iov_iov_base(i),
705 iov_iov_len(i));
706 }
John Hughes1d08dcf2001-07-10 13:48:44 +0000707 }
Denys Vlasenko79a79ea2011-09-01 16:35:44 +0200708 free(iov);
Dmitry V. Levin4ebb4e32006-12-13 17:08:08 +0000709#undef sizeof_iov
710#undef iov_iov_base
711#undef iov_iov_len
712#undef iov
John Hughes1d08dcf2001-07-10 13:48:44 +0000713}
714#endif
715
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000716void
Denys Vlasenko12014262011-05-30 14:00:14 +0200717dumpstr(struct tcb *tcp, long addr, int len)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000718{
719 static int strsize = -1;
720 static unsigned char *str;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000721 char *s;
722 int i, j;
723
724 if (strsize < len) {
Denys Vlasenko5d645812011-08-20 12:48:18 +0200725 free(str);
726 str = malloc(len);
Denys Vlasenko79a79ea2011-09-01 16:35:44 +0200727 if (!str) {
728 strsize = -1;
729 fprintf(stderr, "Out of memory\n");
730 return;
731 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000732 strsize = len;
733 }
734
735 if (umoven(tcp, addr, len, (char *) str) < 0)
736 return;
737
738 for (i = 0; i < len; i += 16) {
Denys Vlasenko1d46ba52011-08-31 14:00:02 +0200739 char outstr[80];
740
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000741 s = outstr;
742 sprintf(s, " | %05x ", i);
743 s += 9;
744 for (j = 0; j < 16; j++) {
745 if (j == 8)
746 *s++ = ' ';
747 if (i + j < len) {
748 sprintf(s, " %02x", str[i + j]);
749 s += 3;
750 }
751 else {
752 *s++ = ' '; *s++ = ' '; *s++ = ' ';
753 }
754 }
755 *s++ = ' '; *s++ = ' ';
756 for (j = 0; j < 16; j++) {
757 if (j == 8)
758 *s++ = ' ';
759 if (i + j < len) {
760 if (isprint(str[i + j]))
761 *s++ = str[i + j];
762 else
763 *s++ = '.';
764 }
765 else
766 *s++ = ' ';
767 }
768 tprintf("%s |\n", outstr);
769 }
770}
771
Denys Vlasenko3af224c2012-01-28 01:46:33 +0100772
773/* Need to do this since process_vm_readv() is not yet available in libc.
774 * When libc is be updated, only "static bool process_vm_readv_not_supported"
775 * line should remain.
776 */
777#if !defined(__NR_process_vm_readv)
778# if defined(I386)
779# define __NR_process_vm_readv 347
780# elif defined(X86_64)
781# define __NR_process_vm_readv 310
782# elif defined(POWERPC)
783# define __NR_process_vm_readv 351
784# endif
785#endif
786
787#if defined(__NR_process_vm_readv)
788static bool process_vm_readv_not_supported = 0;
789static ssize_t process_vm_readv(pid_t pid,
790 const struct iovec *lvec,
791 unsigned long liovcnt,
792 const struct iovec *rvec,
793 unsigned long riovcnt,
794 unsigned long flags)
795{
796 return syscall(__NR_process_vm_readv, (long)pid, lvec, liovcnt, rvec, riovcnt, flags);
797}
798#else
799static bool process_vm_readv_not_supported = 1;
800# define process_vm_readv(...) (errno = ENOSYS, -1)
801#endif
802/* end of hack */
803
804
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000805#define PAGMASK (~(PAGSIZ - 1))
806/*
807 * move `len' bytes of data from process `pid'
808 * at address `addr' to our space at `laddr'
809 */
810int
Denys Vlasenkoef2fbf82009-01-06 21:45:06 +0000811umoven(struct tcb *tcp, long addr, int len, char *laddr)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000812{
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000813#ifdef LINUX
Roland McGratheb9e2e82009-06-02 16:49:22 -0700814 int pid = tcp->pid;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000815 int n, m;
Denys Vlasenkoa47e6b92012-01-21 04:01:56 +0100816 int started;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000817 union {
818 long val;
819 char x[sizeof(long)];
820 } u;
821
Denys Vlasenko3af224c2012-01-28 01:46:33 +0100822 if (!process_vm_readv_not_supported) {
823 struct iovec local[1], remote[1];
824 int r;
825
826 local[0].iov_base = laddr;
827 remote[0].iov_base = (void*)addr;
828 local[0].iov_len = remote[0].iov_len = len;
829 r = process_vm_readv(pid,
830 local, 1,
831 remote, 1,
832 /*flags:*/ 0
833 );
834 if (r < 0) {
835 if (errno == ENOSYS)
836 process_vm_readv_not_supported = 1;
837 else /* strange... */
838 perror("process_vm_readv");
839 goto vm_readv_didnt_work;
840 }
841 return r;
842 }
843 vm_readv_didnt_work:
844
Dmitry V. Levin856c7ed2011-12-26 20:12:02 +0000845#if SUPPORTED_PERSONALITIES > 1
846 if (personality_wordsize[current_personality] < sizeof(addr))
847 addr &= (1ul << 8 * personality_wordsize[current_personality]) - 1;
848#endif
849
Denys Vlasenkoa47e6b92012-01-21 04:01:56 +0100850 started = 0;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000851 if (addr & (sizeof(long) - 1)) {
852 /* addr not a multiple of sizeof(long) */
853 n = addr - (addr & -sizeof(long)); /* residue */
854 addr &= -sizeof(long); /* residue */
Roland McGratheb9e2e82009-06-02 16:49:22 -0700855 errno = 0;
856 u.val = ptrace(PTRACE_PEEKDATA, pid, (char *) addr, 0);
857 if (errno) {
Roland McGratheb9e2e82009-06-02 16:49:22 -0700858 /* But if not started, we had a bogus address. */
859 if (addr != 0 && errno != EIO && errno != ESRCH)
860 perror("ptrace: umoven");
861 return -1;
862 }
Wichert Akkerman5daa0281999-03-15 19:49:42 +0000863 started = 1;
Denys Vlasenkoa47e6b92012-01-21 04:01:56 +0100864 m = MIN(sizeof(long) - n, len);
865 memcpy(laddr, &u.x[n], m);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000866 addr += sizeof(long), laddr += m, len -= m;
867 }
868 while (len) {
Roland McGratheb9e2e82009-06-02 16:49:22 -0700869 errno = 0;
870 u.val = ptrace(PTRACE_PEEKDATA, pid, (char *) addr, 0);
871 if (errno) {
872 if (started && (errno==EPERM || errno==EIO)) {
873 /* Ran into 'end of memory' - stupid "printpath" */
874 return 0;
875 }
876 if (addr != 0 && errno != EIO && errno != ESRCH)
877 perror("ptrace: umoven");
878 return -1;
879 }
Wichert Akkerman5daa0281999-03-15 19:49:42 +0000880 started = 1;
Denys Vlasenkoa47e6b92012-01-21 04:01:56 +0100881 m = MIN(sizeof(long), len);
882 memcpy(laddr, u.x, m);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000883 addr += sizeof(long), laddr += m, len -= m;
884 }
885#endif /* LINUX */
886
887#ifdef SUNOS4
888 int pid = tcp->pid;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000889 int n;
890
891 while (len) {
892 n = MIN(len, PAGSIZ);
893 n = MIN(n, ((addr + PAGSIZ) & PAGMASK) - addr);
Roland McGratheb9e2e82009-06-02 16:49:22 -0700894 if (ptrace(PTRACE_READDATA, pid,
895 (char *) addr, len, laddr) < 0) {
896 if (errno != ESRCH) {
897 perror("umoven: ptrace(PTRACE_READDATA, ...)");
898 abort();
899 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000900 return -1;
901 }
902 len -= n;
903 addr += n;
904 laddr += n;
905 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000906#endif /* SUNOS4 */
907
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000908#ifdef USE_PROCFS
Wichert Akkermanea78f0f1999-11-29 15:34:02 +0000909#ifdef HAVE_MP_PROCFS
John Hughesaa09c6b2001-05-15 14:53:43 +0000910 int fd = tcp->pfd_as;
Wichert Akkerman9ce1a631999-08-29 23:15:07 +0000911#else
John Hughesaa09c6b2001-05-15 14:53:43 +0000912 int fd = tcp->pfd;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000913#endif
John Hughesaa09c6b2001-05-15 14:53:43 +0000914 lseek(fd, addr, SEEK_SET);
915 if (read(fd, laddr, len) == -1)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000916 return -1;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000917#endif /* USE_PROCFS */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000918
919 return 0;
920}
921
922/*
Denys Vlasenko6cecba52012-01-20 11:56:00 +0100923 * Like `umove' but make the additional effort of looking
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000924 * for a terminating zero byte.
Denys Vlasenko6cecba52012-01-20 11:56:00 +0100925 *
926 * Returns < 0 on error, > 0 if NUL was seen,
927 * (TODO if useful: return count of bytes including NUL),
928 * else 0 if len bytes were read but no NUL byte seen.
929 *
930 * Note: there is no guarantee we won't overwrite some bytes
931 * in laddr[] _after_ terminating NUL (but, of course,
932 * we never write past laddr[len-1]).
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000933 */
934int
Denys Vlasenkoef2fbf82009-01-06 21:45:06 +0000935umovestr(struct tcb *tcp, long addr, int len, char *laddr)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000936{
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000937#ifdef USE_PROCFS
Denys Vlasenkoa47e6b92012-01-21 04:01:56 +0100938# ifdef HAVE_MP_PROCFS
John Hughesaa09c6b2001-05-15 14:53:43 +0000939 int fd = tcp->pfd_as;
Denys Vlasenkoa47e6b92012-01-21 04:01:56 +0100940# else
John Hughesaa09c6b2001-05-15 14:53:43 +0000941 int fd = tcp->pfd;
Denys Vlasenkoa47e6b92012-01-21 04:01:56 +0100942# endif
John Hughesaa09c6b2001-05-15 14:53:43 +0000943 /* Some systems (e.g. FreeBSD) can be upset if we read off the
944 end of valid memory, avoid this by trying to read up
945 to page boundaries. But we don't know what a page is (and
946 getpagesize(2) (if it exists) doesn't necessarily return
947 hardware page size). Assume all pages >= 1024 (a-historical
948 I know) */
949
Denys Vlasenkob63256e2011-06-07 12:13:24 +0200950 int page = 1024; /* How to find this? */
John Hughesaa09c6b2001-05-15 14:53:43 +0000951 int move = page - (addr & (page - 1));
952 int left = len;
953
954 lseek(fd, addr, SEEK_SET);
955
956 while (left) {
Denys Vlasenko5d645812011-08-20 12:48:18 +0200957 if (move > left)
958 move = left;
959 move = read(fd, laddr, move);
960 if (move <= 0)
John Hughesaa09c6b2001-05-15 14:53:43 +0000961 return left != len ? 0 : -1;
Denys Vlasenko5d645812011-08-20 12:48:18 +0200962 if (memchr(laddr, 0, move))
Denys Vlasenko6cecba52012-01-20 11:56:00 +0100963 return 1;
John Hughesaa09c6b2001-05-15 14:53:43 +0000964 left -= move;
965 laddr += move;
966 addr += move;
967 move = page;
968 }
Denys Vlasenkoa47e6b92012-01-21 04:01:56 +0100969 return 0;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000970#else /* !USE_PROCFS */
Denys Vlasenkoa47e6b92012-01-21 04:01:56 +0100971 int started;
Roland McGratheb9e2e82009-06-02 16:49:22 -0700972 int pid = tcp->pid;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000973 int i, n, m;
974 union {
975 long val;
976 char x[sizeof(long)];
977 } u;
978
Dmitry V. Levin856c7ed2011-12-26 20:12:02 +0000979#if SUPPORTED_PERSONALITIES > 1
980 if (personality_wordsize[current_personality] < sizeof(addr))
981 addr &= (1ul << 8 * personality_wordsize[current_personality]) - 1;
982#endif
983
Denys Vlasenko3af224c2012-01-28 01:46:33 +0100984 if (!process_vm_readv_not_supported) {
985 struct iovec local[1], remote[1];
986
987 local[0].iov_base = laddr;
988 remote[0].iov_base = (void*)addr;
989
990 while (len > 0) {
991 int end_in_page;
992 int r;
993 int chunk_len;
994
995 /* Don't read kilobytes: most strings are short */
996 chunk_len = len;
997 if (chunk_len > 256)
998 chunk_len = 256;
999 /* Don't cross pages. I guess otherwise we can get EFAULT
1000 * and fail to notice that terminating NUL lies
1001 * in the existing (first) page.
1002 * (I hope there aren't arches with pages < 4K)
1003 */
1004 end_in_page = ((addr + chunk_len) & 4095);
1005 r = chunk_len - end_in_page;
1006 if (r > 0) /* if chunk_len > end_in_page */
1007 chunk_len = r; /* chunk_len -= end_in_page */
1008
1009 local[0].iov_len = remote[0].iov_len = chunk_len;
1010 r = process_vm_readv(pid,
1011 local, 1,
1012 remote, 1,
1013 /*flags:*/ 0
1014 );
1015 if (r < 0) {
1016 if (errno == ENOSYS)
1017 process_vm_readv_not_supported = 1;
1018 else /* strange... */
1019 perror("process_vm_readv");
1020 goto vm_readv_didnt_work;
1021 }
1022 if (memchr(local[0].iov_base, '\0', r))
1023 return 1;
1024 local[0].iov_base += r;
1025 remote[0].iov_base += r;
1026 len -= r;
1027 }
1028 return 0;
1029 }
1030 vm_readv_didnt_work:
1031
Denys Vlasenkoa47e6b92012-01-21 04:01:56 +01001032 started = 0;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001033 if (addr & (sizeof(long) - 1)) {
1034 /* addr not a multiple of sizeof(long) */
1035 n = addr - (addr & -sizeof(long)); /* residue */
1036 addr &= -sizeof(long); /* residue */
Roland McGratheb9e2e82009-06-02 16:49:22 -07001037 errno = 0;
1038 u.val = ptrace(PTRACE_PEEKDATA, pid, (char *)addr, 0);
1039 if (errno) {
Roland McGratheb9e2e82009-06-02 16:49:22 -07001040 if (addr != 0 && errno != EIO && errno != ESRCH)
1041 perror("umovestr");
1042 return -1;
1043 }
Wichert Akkerman5daa0281999-03-15 19:49:42 +00001044 started = 1;
Denys Vlasenkoa47e6b92012-01-21 04:01:56 +01001045 m = MIN(sizeof(long) - n, len);
1046 memcpy(laddr, &u.x[n], m);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001047 while (n & (sizeof(long) - 1))
1048 if (u.x[n++] == '\0')
Denys Vlasenko6cecba52012-01-20 11:56:00 +01001049 return 1;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001050 addr += sizeof(long), laddr += m, len -= m;
1051 }
1052 while (len) {
Roland McGratheb9e2e82009-06-02 16:49:22 -07001053 errno = 0;
1054 u.val = ptrace(PTRACE_PEEKDATA, pid, (char *)addr, 0);
1055 if (errno) {
1056 if (started && (errno==EPERM || errno==EIO)) {
1057 /* Ran into 'end of memory' - stupid "printpath" */
1058 return 0;
1059 }
1060 if (addr != 0 && errno != EIO && errno != ESRCH)
1061 perror("umovestr");
1062 return -1;
1063 }
Wichert Akkerman5daa0281999-03-15 19:49:42 +00001064 started = 1;
Denys Vlasenkoa47e6b92012-01-21 04:01:56 +01001065 m = MIN(sizeof(long), len);
1066 memcpy(laddr, u.x, m);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001067 for (i = 0; i < sizeof(long); i++)
1068 if (u.x[i] == '\0')
Denys Vlasenko6cecba52012-01-20 11:56:00 +01001069 return 1;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001070 addr += sizeof(long), laddr += m, len -= m;
1071 }
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001072#endif /* !USE_PROCFS */
John Hughesaa09c6b2001-05-15 14:53:43 +00001073 return 0;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001074}
1075
1076#ifdef LINUX
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001077# if !defined (SPARC) && !defined(SPARC64)
1078# define PTRACE_WRITETEXT 101
1079# define PTRACE_WRITEDATA 102
1080# endif /* !SPARC && !SPARC64 */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001081#endif /* LINUX */
1082
1083#ifdef SUNOS4
1084
1085static int
Denys Vlasenko12014262011-05-30 14:00:14 +02001086uload(int cmd, int pid, long addr, int len, char *laddr)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001087{
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001088 int peek, poke;
1089 int n, m;
1090 union {
1091 long val;
1092 char x[sizeof(long)];
1093 } u;
1094
1095 if (cmd == PTRACE_WRITETEXT) {
1096 peek = PTRACE_PEEKTEXT;
1097 poke = PTRACE_POKETEXT;
1098 }
1099 else {
1100 peek = PTRACE_PEEKDATA;
1101 poke = PTRACE_POKEDATA;
1102 }
1103 if (addr & (sizeof(long) - 1)) {
1104 /* addr not a multiple of sizeof(long) */
1105 n = addr - (addr & -sizeof(long)); /* residue */
1106 addr &= -sizeof(long);
Roland McGratheb9e2e82009-06-02 16:49:22 -07001107 errno = 0;
1108 u.val = ptrace(peek, pid, (char *) addr, 0);
1109 if (errno) {
1110 perror("uload: POKE");
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001111 return -1;
1112 }
Denys Vlasenkoa47e6b92012-01-21 04:01:56 +01001113 m = MIN(sizeof(long) - n, len);
1114 memcpy(&u.x[n], laddr, m);
Roland McGratheb9e2e82009-06-02 16:49:22 -07001115 if (ptrace(poke, pid, (char *)addr, u.val) < 0) {
1116 perror("uload: POKE");
1117 return -1;
1118 }
1119 addr += sizeof(long), laddr += m, len -= m;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001120 }
1121 while (len) {
1122 if (len < sizeof(long))
Roland McGratheb9e2e82009-06-02 16:49:22 -07001123 u.val = ptrace(peek, pid, (char *) addr, 0);
Denys Vlasenkoa47e6b92012-01-21 04:01:56 +01001124 m = MIN(sizeof(long), len);
1125 memcpy(u.x, laddr, m);
Roland McGratheb9e2e82009-06-02 16:49:22 -07001126 if (ptrace(poke, pid, (char *) addr, u.val) < 0) {
1127 perror("uload: POKE");
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001128 return -1;
1129 }
Roland McGratheb9e2e82009-06-02 16:49:22 -07001130 addr += sizeof(long), laddr += m, len -= m;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001131 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001132 return 0;
1133}
1134
Roland McGratheb9e2e82009-06-02 16:49:22 -07001135int
Denys Vlasenko12014262011-05-30 14:00:14 +02001136tload(int pid, int addr, int len, char *laddr)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001137{
Roland McGratheb9e2e82009-06-02 16:49:22 -07001138 return uload(PTRACE_WRITETEXT, pid, addr, len, laddr);
1139}
1140
1141int
Denys Vlasenko12014262011-05-30 14:00:14 +02001142dload(int pid, int addr, int len, char *laddr)
Roland McGratheb9e2e82009-06-02 16:49:22 -07001143{
1144 return uload(PTRACE_WRITEDATA, pid, addr, len, laddr);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001145}
1146
1147#endif /* SUNOS4 */
1148
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001149#ifndef USE_PROCFS
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001150
1151int
Denys Vlasenko12014262011-05-30 14:00:14 +02001152upeek(struct tcb *tcp, long off, long *res)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001153{
1154 long val;
1155
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001156# ifdef SUNOS4_KERNEL_ARCH_KLUDGE
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001157 {
1158 static int is_sun4m = -1;
1159 struct utsname name;
1160
1161 /* Round up the usual suspects. */
1162 if (is_sun4m == -1) {
1163 if (uname(&name) < 0) {
1164 perror("upeek: uname?");
1165 exit(1);
1166 }
1167 is_sun4m = strcmp(name.machine, "sun4m") == 0;
1168 if (is_sun4m) {
Roland McGrathd9f816f2004-09-04 03:39:20 +00001169 const struct xlat *x;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001170
1171 for (x = struct_user_offsets; x->str; x++)
1172 x->val += 1024;
1173 }
1174 }
1175 if (is_sun4m)
1176 off += 1024;
1177 }
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001178# endif /* SUNOS4_KERNEL_ARCH_KLUDGE */
Roland McGratheb9e2e82009-06-02 16:49:22 -07001179 errno = 0;
Denys Vlasenko732d1bf2008-12-17 19:21:59 +00001180 val = do_ptrace(PTRACE_PEEKUSER, tcp, (char *) off, 0);
Roland McGratheb9e2e82009-06-02 16:49:22 -07001181 if (val == -1 && errno) {
1182 if (errno != ESRCH) {
1183 char buf[60];
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001184 sprintf(buf, "upeek: ptrace(PTRACE_PEEKUSER,%d,%lu,0)", tcp->pid, off);
Roland McGratheb9e2e82009-06-02 16:49:22 -07001185 perror(buf);
1186 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001187 return -1;
Roland McGratheb9e2e82009-06-02 16:49:22 -07001188 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001189 *res = val;
1190 return 0;
1191}
1192
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001193#endif /* !USE_PROCFS */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001194
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001195void
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001196printcall(struct tcb *tcp)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001197{
Roland McGrath7a918832005-02-02 20:55:23 +00001198#define PRINTBADPC tprintf(sizeof(long) == 4 ? "[????????] " : \
1199 sizeof(long) == 8 ? "[????????????????] " : \
1200 NULL /* crash */)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001201
1202#ifdef LINUX
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001203# ifdef I386
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001204 long eip;
1205
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001206 if (upeek(tcp, 4*EIP, &eip) < 0) {
Roland McGrath7a918832005-02-02 20:55:23 +00001207 PRINTBADPC;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001208 return;
1209 }
1210 tprintf("[%08lx] ", eip);
Roland McGratheac26fc2005-02-02 02:48:53 +00001211
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001212# elif defined(S390) || defined(S390X)
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001213 long psw;
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001214 if (upeek(tcp, PT_PSWADDR, &psw) < 0) {
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001215 PRINTBADPC;
1216 return;
1217 }
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001218# ifdef S390
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001219 tprintf("[%08lx] ", psw);
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001220# elif S390X
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001221 tprintf("[%16lx] ", psw);
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001222# endif
Roland McGratheac26fc2005-02-02 02:48:53 +00001223
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001224# elif defined(X86_64)
Michal Ludvig0e035502002-09-23 15:41:01 +00001225 long rip;
1226
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001227 if (upeek(tcp, 8*RIP, &rip) < 0) {
Roland McGrath7a918832005-02-02 20:55:23 +00001228 PRINTBADPC;
Michal Ludvig0e035502002-09-23 15:41:01 +00001229 return;
1230 }
1231 tprintf("[%16lx] ", rip);
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001232# elif defined(IA64)
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00001233 long ip;
1234
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001235 if (upeek(tcp, PT_B0, &ip) < 0) {
Roland McGrath7a918832005-02-02 20:55:23 +00001236 PRINTBADPC;
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00001237 return;
1238 }
1239 tprintf("[%08lx] ", ip);
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001240# elif defined(POWERPC)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001241 long pc;
1242
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001243 if (upeek(tcp, sizeof(unsigned long)*PT_NIP, &pc) < 0) {
Andreas Schwabd69fa492010-07-12 21:39:57 +02001244 PRINTBADPC;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001245 return;
1246 }
Andreas Schwabd69fa492010-07-12 21:39:57 +02001247# ifdef POWERPC64
1248 tprintf("[%016lx] ", pc);
1249# else
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001250 tprintf("[%08lx] ", pc);
Andreas Schwabd69fa492010-07-12 21:39:57 +02001251# endif
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001252# elif defined(M68K)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001253 long pc;
1254
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001255 if (upeek(tcp, 4*PT_PC, &pc) < 0) {
Denys Vlasenko60fe8c12011-09-01 10:00:28 +02001256 tprints("[????????] ");
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001257 return;
1258 }
1259 tprintf("[%08lx] ", pc);
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001260# elif defined(ALPHA)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001261 long pc;
1262
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001263 if (upeek(tcp, REG_PC, &pc) < 0) {
Denys Vlasenko60fe8c12011-09-01 10:00:28 +02001264 tprints("[????????????????] ");
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001265 return;
1266 }
1267 tprintf("[%08lx] ", pc);
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001268# elif defined(SPARC) || defined(SPARC64)
Mike Frysinger8566c502009-10-12 11:05:14 -04001269 struct pt_regs regs;
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001270 if (ptrace(PTRACE_GETREGS, tcp->pid, (char *)&regs, 0) < 0) {
Roland McGrath7a918832005-02-02 20:55:23 +00001271 PRINTBADPC;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001272 return;
1273 }
Mike Frysinger8566c502009-10-12 11:05:14 -04001274# if defined(SPARC64)
1275 tprintf("[%08lx] ", regs.tpc);
1276# else
1277 tprintf("[%08lx] ", regs.pc);
1278# endif
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001279# elif defined(HPPA)
Wichert Akkermanc1652e22001-03-27 12:17:16 +00001280 long pc;
1281
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001282 if (upeek(tcp, PT_IAOQ0, &pc) < 0) {
Denys Vlasenko60fe8c12011-09-01 10:00:28 +02001283 tprints("[????????] ");
Wichert Akkermanc1652e22001-03-27 12:17:16 +00001284 return;
1285 }
1286 tprintf("[%08lx] ", pc);
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001287# elif defined(MIPS)
Wichert Akkerman75c422b2001-04-10 10:22:50 +00001288 long pc;
1289
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001290 if (upeek(tcp, REG_EPC, &pc) < 0) {
Denys Vlasenko60fe8c12011-09-01 10:00:28 +02001291 tprints("[????????] ");
Wichert Akkerman75c422b2001-04-10 10:22:50 +00001292 return;
1293 }
1294 tprintf("[%08lx] ", pc);
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001295# elif defined(SH)
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001296 long pc;
Wichert Akkermanccef6372002-05-01 16:39:22 +00001297
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001298 if (upeek(tcp, 4*REG_PC, &pc) < 0) {
Denys Vlasenko60fe8c12011-09-01 10:00:28 +02001299 tprints("[????????] ");
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001300 return;
1301 }
1302 tprintf("[%08lx] ", pc);
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001303# elif defined(SH64)
Roland McGrathe1e584b2003-06-02 19:18:58 +00001304 long pc;
1305
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001306 if (upeek(tcp, REG_PC, &pc) < 0) {
Denys Vlasenko60fe8c12011-09-01 10:00:28 +02001307 tprints("[????????????????] ");
Roland McGrathe1e584b2003-06-02 19:18:58 +00001308 return;
1309 }
1310 tprintf("[%08lx] ", pc);
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001311# elif defined(ARM)
Roland McGrathef388682003-06-03 23:28:59 +00001312 long pc;
Roland McGrathe1e584b2003-06-02 19:18:58 +00001313
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001314 if (upeek(tcp, 4*15, &pc) < 0) {
Roland McGrath7a918832005-02-02 20:55:23 +00001315 PRINTBADPC;
Roland McGrathef388682003-06-03 23:28:59 +00001316 return;
1317 }
1318 tprintf("[%08lx] ", pc);
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00001319# elif defined(AVR32)
1320 long pc;
1321
1322 if (upeek(tcp, REG_PC, &pc) < 0) {
Denys Vlasenko60fe8c12011-09-01 10:00:28 +02001323 tprints("[????????] ");
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00001324 return;
1325 }
1326 tprintf("[%08lx] ", pc);
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001327# elif defined(BFIN)
Dmitry V. Levin87ea1f42008-11-10 22:21:41 +00001328 long pc;
1329
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001330 if (upeek(tcp, PT_PC, &pc) < 0) {
Dmitry V. Levin87ea1f42008-11-10 22:21:41 +00001331 PRINTBADPC;
1332 return;
1333 }
1334 tprintf("[%08lx] ", pc);
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001335#elif defined(CRISV10)
1336 long pc;
1337
Edgar E. Iglesiaseeb9ce32009-10-05 14:41:02 +00001338 if (upeek(tcp, 4*PT_IRP, &pc) < 0) {
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001339 PRINTBADPC;
1340 return;
1341 }
1342 tprintf("[%08lx] ", pc);
1343#elif defined(CRISV32)
1344 long pc;
1345
Edgar E. Iglesiaseeb9ce32009-10-05 14:41:02 +00001346 if (upeek(tcp, 4*PT_ERP, &pc) < 0) {
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001347 PRINTBADPC;
1348 return;
1349 }
1350 tprintf("[%08lx] ", pc);
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001351# endif /* architecture */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001352#endif /* LINUX */
1353
1354#ifdef SUNOS4
1355 struct regs regs;
1356
Roland McGratheb9e2e82009-06-02 16:49:22 -07001357 if (ptrace(PTRACE_GETREGS, tcp->pid, (char *) &regs, 0) < 0) {
1358 perror("printcall: ptrace(PTRACE_GETREGS, ...)");
Roland McGrath7a918832005-02-02 20:55:23 +00001359 PRINTBADPC;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001360 return;
1361 }
1362 tprintf("[%08x] ", regs.r_o7);
1363#endif /* SUNOS4 */
1364
1365#ifdef SVR4
1366 /* XXX */
Roland McGrath7a918832005-02-02 20:55:23 +00001367 PRINTBADPC;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001368#endif
1369
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001370#ifdef FREEBSD
1371 struct reg regs;
1372 pread(tcp->pfd_reg, &regs, sizeof(regs), 0);
1373 tprintf("[%08x] ", regs.r_eip);
1374#endif /* FREEBSD */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001375}
1376
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001377
1378/*
1379 * These #if's are huge, please indent them correctly.
1380 * It's easy to get confused otherwise.
1381 */
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001382#ifndef USE_PROCFS
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001383
Denys Vlasenkoe7c90242011-06-22 00:09:25 +02001384# ifdef LINUX
Roland McGrathd81f1d92003-01-09 06:53:34 +00001385
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001386# include "syscall.h"
Roland McGrath3291ef22008-05-20 00:34:34 +00001387
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001388# include <sys/syscall.h>
1389# ifndef CLONE_PTRACE
1390# define CLONE_PTRACE 0x00002000
1391# endif
1392# ifndef CLONE_VFORK
1393# define CLONE_VFORK 0x00004000
1394# endif
1395# ifndef CLONE_VM
1396# define CLONE_VM 0x00000100
1397# endif
1398# ifndef CLONE_STOPPED
1399# define CLONE_STOPPED 0x02000000
1400# endif
Roland McGrathd81f1d92003-01-09 06:53:34 +00001401
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001402# ifdef IA64
Roland McGrathd81f1d92003-01-09 06:53:34 +00001403
Roland McGrath08267b82004-02-20 22:56:43 +00001404/* We don't have fork()/vfork() syscalls on ia64 itself, but the ia32
1405 subsystem has them for x86... */
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001406# define SYS_fork 2
1407# define SYS_vfork 190
Roland McGrath08267b82004-02-20 22:56:43 +00001408
Roland McGrathd81f1d92003-01-09 06:53:34 +00001409typedef unsigned long *arg_setup_state;
1410
1411static int
1412arg_setup(struct tcb *tcp, arg_setup_state *state)
1413{
Jan Kratochvil1f942712008-08-06 21:38:52 +00001414 unsigned long cfm, sof, sol;
1415 long bsp;
Roland McGrathd81f1d92003-01-09 06:53:34 +00001416
Jan Kratochvil1f942712008-08-06 21:38:52 +00001417 if (ia32) {
1418 /* Satisfy a false GCC warning. */
1419 *state = NULL;
Roland McGrath08267b82004-02-20 22:56:43 +00001420 return 0;
Jan Kratochvil1f942712008-08-06 21:38:52 +00001421 }
Roland McGrath08267b82004-02-20 22:56:43 +00001422
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001423 if (upeek(tcp, PT_AR_BSP, &bsp) < 0)
Roland McGrathd81f1d92003-01-09 06:53:34 +00001424 return -1;
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001425 if (upeek(tcp, PT_CFM, (long *) &cfm) < 0)
Roland McGrathd81f1d92003-01-09 06:53:34 +00001426 return -1;
1427
1428 sof = (cfm >> 0) & 0x7f;
1429 sol = (cfm >> 7) & 0x7f;
Jan Kratochvil1f942712008-08-06 21:38:52 +00001430 bsp = (long) ia64_rse_skip_regs((unsigned long *) bsp, -sof + sol);
Roland McGrathd81f1d92003-01-09 06:53:34 +00001431
Jan Kratochvil1f942712008-08-06 21:38:52 +00001432 *state = (unsigned long *) bsp;
Roland McGrathd81f1d92003-01-09 06:53:34 +00001433 return 0;
1434}
1435
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001436# define arg_finish_change(tcp, state) 0
Roland McGrathd81f1d92003-01-09 06:53:34 +00001437
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001438# ifdef SYS_fork
Roland McGrathd81f1d92003-01-09 06:53:34 +00001439static int
Denys Vlasenko12014262011-05-30 14:00:14 +02001440get_arg0(struct tcb *tcp, arg_setup_state *state, long *valp)
Roland McGrathd81f1d92003-01-09 06:53:34 +00001441{
Roland McGrath08267b82004-02-20 22:56:43 +00001442 int ret;
1443
1444 if (ia32)
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001445 ret = upeek(tcp, PT_R11, valp);
Roland McGrath08267b82004-02-20 22:56:43 +00001446 else
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001447 ret = umoven(tcp,
Roland McGrath08267b82004-02-20 22:56:43 +00001448 (unsigned long) ia64_rse_skip_regs(*state, 0),
1449 sizeof(long), (void *) valp);
1450 return ret;
Roland McGrathd81f1d92003-01-09 06:53:34 +00001451}
1452
1453static int
Denys Vlasenko12014262011-05-30 14:00:14 +02001454get_arg1(struct tcb *tcp, arg_setup_state *state, long *valp)
Roland McGrathd81f1d92003-01-09 06:53:34 +00001455{
Roland McGrath08267b82004-02-20 22:56:43 +00001456 int ret;
1457
1458 if (ia32)
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001459 ret = upeek(tcp, PT_R9, valp);
Roland McGrath08267b82004-02-20 22:56:43 +00001460 else
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001461 ret = umoven(tcp,
Roland McGrath08267b82004-02-20 22:56:43 +00001462 (unsigned long) ia64_rse_skip_regs(*state, 1),
1463 sizeof(long), (void *) valp);
1464 return ret;
Roland McGrathd81f1d92003-01-09 06:53:34 +00001465}
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001466# endif
Roland McGrathd81f1d92003-01-09 06:53:34 +00001467
1468static int
Denys Vlasenko12014262011-05-30 14:00:14 +02001469set_arg0(struct tcb *tcp, arg_setup_state *state, long val)
Roland McGrathd81f1d92003-01-09 06:53:34 +00001470{
Roland McGrath08267b82004-02-20 22:56:43 +00001471 int req = PTRACE_POKEDATA;
1472 void *ap;
1473
1474 if (ia32) {
1475 ap = (void *) (intptr_t) PT_R11; /* r11 == EBX */
1476 req = PTRACE_POKEUSER;
1477 } else
1478 ap = ia64_rse_skip_regs(*state, 0);
Roland McGratheb9e2e82009-06-02 16:49:22 -07001479 errno = 0;
1480 ptrace(req, tcp->pid, ap, val);
1481 return errno ? -1 : 0;
Roland McGrathd81f1d92003-01-09 06:53:34 +00001482}
1483
1484static int
Denys Vlasenko12014262011-05-30 14:00:14 +02001485set_arg1(struct tcb *tcp, arg_setup_state *state, long val)
Roland McGrathd81f1d92003-01-09 06:53:34 +00001486{
Roland McGrath08267b82004-02-20 22:56:43 +00001487 int req = PTRACE_POKEDATA;
1488 void *ap;
1489
1490 if (ia32) {
1491 ap = (void *) (intptr_t) PT_R9; /* r9 == ECX */
1492 req = PTRACE_POKEUSER;
1493 } else
1494 ap = ia64_rse_skip_regs(*state, 1);
Roland McGratheb9e2e82009-06-02 16:49:22 -07001495 errno = 0;
1496 ptrace(req, tcp->pid, ap, val);
1497 return errno ? -1 : 0;
Roland McGrathd81f1d92003-01-09 06:53:34 +00001498}
1499
Roland McGrathb659f872008-07-18 01:19:36 +00001500/* ia64 does not return the input arguments from functions (and syscalls)
1501 according to ia64 RSE (Register Stack Engine) behavior. */
1502
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001503# define restore_arg0(tcp, state, val) ((void) (state), 0)
1504# define restore_arg1(tcp, state, val) ((void) (state), 0)
Roland McGrathb659f872008-07-18 01:19:36 +00001505
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001506# elif defined (SPARC) || defined (SPARC64)
Roland McGrathd81f1d92003-01-09 06:53:34 +00001507
Mike Frysinger8566c502009-10-12 11:05:14 -04001508typedef struct pt_regs arg_setup_state;
Roland McGrathd81f1d92003-01-09 06:53:34 +00001509
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001510# define arg_setup(tcp, state) \
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001511 (ptrace(PTRACE_GETREGS, tcp->pid, (char *) (state), 0))
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001512# define arg_finish_change(tcp, state) \
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001513 (ptrace(PTRACE_SETREGS, tcp->pid, (char *) (state), 0))
Roland McGrathd81f1d92003-01-09 06:53:34 +00001514
Mike Frysinger8566c502009-10-12 11:05:14 -04001515# define get_arg0(tcp, state, valp) (*(valp) = (state)->u_regs[U_REG_O0], 0)
1516# define get_arg1(tcp, state, valp) (*(valp) = (state)->u_regs[U_REG_O1], 0)
1517# define set_arg0(tcp, state, val) ((state)->u_regs[U_REG_O0] = (val), 0)
1518# define set_arg1(tcp, state, val) ((state)->u_regs[U_REG_O1] = (val), 0)
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001519# define restore_arg0(tcp, state, val) 0
Roland McGrathd81f1d92003-01-09 06:53:34 +00001520
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001521# else /* other architectures */
Roland McGrathd81f1d92003-01-09 06:53:34 +00001522
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001523# if defined S390 || defined S390X
Roland McGrath7b308222003-01-20 09:04:36 +00001524/* Note: this is only true for the `clone' system call, which handles
1525 arguments specially. We could as well say that its first two arguments
1526 are swapped relative to other architectures, but that would just be
1527 another #ifdef in the calls. */
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001528# define arg0_offset PT_GPR3
1529# define arg1_offset PT_ORIGGPR2
1530# define restore_arg0(tcp, state, val) ((void) (state), 0)
1531# define restore_arg1(tcp, state, val) ((void) (state), 0)
1532# define arg0_index 1
1533# define arg1_index 0
1534# elif defined (ALPHA) || defined (MIPS)
1535# define arg0_offset REG_A0
1536# define arg1_offset (REG_A0+1)
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00001537# elif defined (AVR32)
1538# define arg0_offset (REG_R12)
1539# define arg1_offset (REG_R11)
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001540# elif defined (POWERPC)
1541# define arg0_offset (sizeof(unsigned long)*PT_R3)
1542# define arg1_offset (sizeof(unsigned long)*PT_R4)
1543# define restore_arg0(tcp, state, val) ((void) (state), 0)
1544# elif defined (HPPA)
1545# define arg0_offset PT_GR26
1546# define arg1_offset (PT_GR26-4)
1547# elif defined (X86_64)
1548# define arg0_offset ((long)(8*(current_personality ? RBX : RDI)))
1549# define arg1_offset ((long)(8*(current_personality ? RCX : RSI)))
1550# elif defined (SH)
1551# define arg0_offset (4*(REG_REG0+4))
1552# define arg1_offset (4*(REG_REG0+5))
1553# elif defined (SH64)
1554 /* ABI defines arg0 & 1 in r2 & r3 */
1555# define arg0_offset (REG_OFFSET+16)
1556# define arg1_offset (REG_OFFSET+24)
1557# define restore_arg0(tcp, state, val) 0
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001558# elif defined CRISV10 || defined CRISV32
1559# define arg0_offset (4*PT_R11)
1560# define arg1_offset (4*PT_ORIG_R10)
1561# define restore_arg0(tcp, state, val) 0
1562# define restore_arg1(tcp, state, val) 0
1563# define arg0_index 1
1564# define arg1_index 0
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001565# else
1566# define arg0_offset 0
1567# define arg1_offset 4
1568# if defined ARM
1569# define restore_arg0(tcp, state, val) 0
1570# endif
1571# endif
Roland McGrathd81f1d92003-01-09 06:53:34 +00001572
1573typedef int arg_setup_state;
1574
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001575# define arg_setup(tcp, state) (0)
1576# define arg_finish_change(tcp, state) 0
1577# define get_arg0(tcp, cookie, valp) \
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001578 (upeek((tcp), arg0_offset, (valp)))
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001579# define get_arg1(tcp, cookie, valp) \
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001580 (upeek((tcp), arg1_offset, (valp)))
Roland McGrathd81f1d92003-01-09 06:53:34 +00001581
1582static int
Denys Vlasenko12014262011-05-30 14:00:14 +02001583set_arg0(struct tcb *tcp, void *cookie, long val)
Roland McGrathd81f1d92003-01-09 06:53:34 +00001584{
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001585 return ptrace(PTRACE_POKEUSER, tcp->pid, (char*)arg0_offset, val);
Roland McGrathd81f1d92003-01-09 06:53:34 +00001586}
1587
1588static int
Denys Vlasenko12014262011-05-30 14:00:14 +02001589set_arg1(struct tcb *tcp, void *cookie, long val)
Roland McGrathd81f1d92003-01-09 06:53:34 +00001590{
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001591 return ptrace(PTRACE_POKEUSER, tcp->pid, (char*)arg1_offset, val);
Roland McGrathd81f1d92003-01-09 06:53:34 +00001592}
1593
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001594# endif /* architectures */
Roland McGrathd81f1d92003-01-09 06:53:34 +00001595
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001596# ifndef restore_arg0
1597# define restore_arg0(tcp, state, val) set_arg0((tcp), (state), (val))
1598# endif
1599# ifndef restore_arg1
1600# define restore_arg1(tcp, state, val) set_arg1((tcp), (state), (val))
1601# endif
Roland McGrathd81f1d92003-01-09 06:53:34 +00001602
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001603# ifndef arg0_index
1604# define arg0_index 0
1605# define arg1_index 1
1606# endif
Roland McGrath90d0afd2004-03-01 21:05:16 +00001607
Roland McGrathd81f1d92003-01-09 06:53:34 +00001608int
Denys Vlasenko418d66a2009-01-17 01:52:54 +00001609setbpt(struct tcb *tcp)
Roland McGrathd81f1d92003-01-09 06:53:34 +00001610{
Roland McGrath3291ef22008-05-20 00:34:34 +00001611 static int clone_scno[SUPPORTED_PERSONALITIES] = { SYS_clone };
Roland McGrathd81f1d92003-01-09 06:53:34 +00001612 arg_setup_state state;
1613
1614 if (tcp->flags & TCB_BPTSET) {
1615 fprintf(stderr, "PANIC: TCB already set in pid %u\n", tcp->pid);
1616 return -1;
1617 }
1618
Roland McGrath3291ef22008-05-20 00:34:34 +00001619 /*
1620 * It's a silly kludge to initialize this with a search at runtime.
1621 * But it's better than maintaining another magic thing in the
1622 * godforsaken tables.
1623 */
1624 if (clone_scno[current_personality] == 0) {
1625 int i;
1626 for (i = 0; i < nsyscalls; ++i)
1627 if (sysent[i].sys_func == sys_clone) {
1628 clone_scno[current_personality] = i;
1629 break;
1630 }
1631 }
1632
Roland McGrath76989d72005-06-07 23:21:31 +00001633 switch (known_scno(tcp)) {
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001634# ifdef SYS_vfork
Roland McGrath9383c6c2003-01-18 00:19:31 +00001635 case SYS_vfork:
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001636# endif
1637# ifdef SYS_fork
Roland McGrathd81f1d92003-01-09 06:53:34 +00001638 case SYS_fork:
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001639# endif
1640# if defined SYS_fork || defined SYS_vfork
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001641 if (arg_setup(tcp, &state) < 0
1642 || get_arg0(tcp, &state, &tcp->inst[0]) < 0
1643 || get_arg1(tcp, &state, &tcp->inst[1]) < 0
Roland McGrath3291ef22008-05-20 00:34:34 +00001644 || change_syscall(tcp, clone_scno[current_personality]) < 0
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001645 || set_arg0(tcp, &state, CLONE_PTRACE|SIGCHLD) < 0
1646 || set_arg1(tcp, &state, 0) < 0
1647 || arg_finish_change(tcp, &state) < 0)
Roland McGrathd81f1d92003-01-09 06:53:34 +00001648 return -1;
Roland McGrathc9dc3c12004-03-01 20:57:09 +00001649 tcp->u_arg[arg0_index] = CLONE_PTRACE|SIGCHLD;
1650 tcp->u_arg[arg1_index] = 0;
Roland McGrathd81f1d92003-01-09 06:53:34 +00001651 tcp->flags |= TCB_BPTSET;
1652 return 0;
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001653# endif
Roland McGrathd81f1d92003-01-09 06:53:34 +00001654
Denys Vlasenkoc133bf02011-06-23 21:57:54 +02001655 case SYS_clone: ;
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001656# ifdef SYS_clone2
Denys Vlasenkoc133bf02011-06-23 21:57:54 +02001657 case SYS_clone2: ;
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001658# endif
Jan Kratochvil8fc95752008-08-06 21:43:35 +00001659 /* ia64 calls directly `clone (CLONE_VFORK | CLONE_VM)'
1660 contrary to x86 SYS_vfork above. Even on x86 we turn the
1661 vfork semantics into plain fork - each application must not
1662 depend on the vfork specifics according to POSIX. We would
1663 hang waiting for the parent resume otherwise. We need to
1664 clear also CLONE_VM but only in the CLONE_VFORK case as
1665 otherwise we would break pthread_create. */
1666
Denys Vlasenkoc133bf02011-06-23 21:57:54 +02001667 long new_arg0 = (tcp->u_arg[arg0_index] | CLONE_PTRACE);
1668 if (new_arg0 & CLONE_VFORK)
1669 new_arg0 &= ~(unsigned long)(CLONE_VFORK | CLONE_VM);
1670 if (arg_setup(tcp, &state) < 0
1671 || set_arg0(tcp, &state, new_arg0) < 0
1672 || arg_finish_change(tcp, &state) < 0)
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00001673 return -1;
Roland McGrathd81f1d92003-01-09 06:53:34 +00001674 tcp->flags |= TCB_BPTSET;
Roland McGrathc9dc3c12004-03-01 20:57:09 +00001675 tcp->inst[0] = tcp->u_arg[arg0_index];
1676 tcp->inst[1] = tcp->u_arg[arg1_index];
Roland McGrathd81f1d92003-01-09 06:53:34 +00001677 return 0;
1678
1679 default:
1680 fprintf(stderr, "PANIC: setbpt for syscall %ld on %u???\n",
1681 tcp->scno, tcp->pid);
1682 break;
1683 }
1684
1685 return -1;
1686}
1687
1688int
Denys Vlasenko12014262011-05-30 14:00:14 +02001689clearbpt(struct tcb *tcp)
Roland McGrathd81f1d92003-01-09 06:53:34 +00001690{
1691 arg_setup_state state;
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001692 if (arg_setup(tcp, &state) < 0
1693 || restore_arg0(tcp, &state, tcp->inst[0]) < 0
1694 || restore_arg1(tcp, &state, tcp->inst[1]) < 0
1695 || arg_finish_change(tcp, &state))
Denys Vlasenkoc133bf02011-06-23 21:57:54 +02001696 if (errno != ESRCH)
1697 return -1;
Roland McGrathd81f1d92003-01-09 06:53:34 +00001698 tcp->flags &= ~TCB_BPTSET;
1699 return 0;
1700}
1701
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001702# else /* !defined LINUX */
Roland McGrathd81f1d92003-01-09 06:53:34 +00001703
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001704int
Denys Vlasenko12014262011-05-30 14:00:14 +02001705setbpt(struct tcb *tcp)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001706{
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001707# ifdef SUNOS4
1708# ifdef SPARC /* This code is slightly sparc specific */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001709
Wichert Akkermane6f876c1999-06-22 15:28:30 +00001710 struct regs regs;
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001711# define BPT 0x91d02001 /* ta 1 */
1712# define LOOP 0x10800000 /* ba 0 */
1713# define LOOPA 0x30800000 /* ba,a 0 */
1714# define NOP 0x01000000
1715# if LOOPA
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001716 static int loopdeloop[1] = {LOOPA};
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001717# else
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001718 static int loopdeloop[2] = {LOOP, NOP};
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001719# endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001720
1721 if (tcp->flags & TCB_BPTSET) {
1722 fprintf(stderr, "PANIC: TCB already set in pid %u\n", tcp->pid);
1723 return -1;
1724 }
Roland McGratheb9e2e82009-06-02 16:49:22 -07001725 if (ptrace(PTRACE_GETREGS, tcp->pid, (char *)&regs, 0) < 0) {
1726 perror("setbpt: ptrace(PTRACE_GETREGS, ...)");
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001727 return -1;
1728 }
1729 tcp->baddr = regs.r_o7 + 8;
Roland McGratheb9e2e82009-06-02 16:49:22 -07001730 if (ptrace(PTRACE_READTEXT, tcp->pid, (char *)tcp->baddr,
1731 sizeof tcp->inst, (char *)tcp->inst) < 0) {
1732 perror("setbpt: ptrace(PTRACE_READTEXT, ...)");
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001733 return -1;
1734 }
1735
1736 /*
1737 * XXX - BRUTAL MODE ON
1738 * We cannot set a real BPT in the child, since it will not be
1739 * traced at the moment it will reach the trap and would probably
1740 * die with a core dump.
1741 * Thus, we are force our way in by taking out two instructions
1742 * and insert an eternal loop in stead, in expectance of the SIGSTOP
1743 * generated by out PTRACE_ATTACH.
1744 * Of cause, if we evaporate ourselves in the middle of all this...
1745 */
Roland McGratheb9e2e82009-06-02 16:49:22 -07001746 if (ptrace(PTRACE_WRITETEXT, tcp->pid, (char *) tcp->baddr,
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001747 sizeof loopdeloop, (char *) loopdeloop) < 0) {
Roland McGratheb9e2e82009-06-02 16:49:22 -07001748 perror("setbpt: ptrace(PTRACE_WRITETEXT, ...)");
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001749 return -1;
1750 }
1751 tcp->flags |= TCB_BPTSET;
1752
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001753# endif /* SPARC */
1754# endif /* SUNOS4 */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001755
1756 return 0;
1757}
1758
1759int
Denys Vlasenko12014262011-05-30 14:00:14 +02001760clearbpt(struct tcb *tcp)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001761{
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001762# ifdef SUNOS4
1763# ifdef SPARC
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001764
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001765# if !LOOPA
Wichert Akkermane6f876c1999-06-22 15:28:30 +00001766 struct regs regs;
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001767# endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001768
1769 if (!(tcp->flags & TCB_BPTSET)) {
1770 fprintf(stderr, "PANIC: TCB not set in pid %u\n", tcp->pid);
1771 return -1;
1772 }
Roland McGratheb9e2e82009-06-02 16:49:22 -07001773 if (ptrace(PTRACE_WRITETEXT, tcp->pid, (char *) tcp->baddr,
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001774 sizeof tcp->inst, (char *) tcp->inst) < 0) {
Roland McGratheb9e2e82009-06-02 16:49:22 -07001775 perror("clearbtp: ptrace(PTRACE_WRITETEXT, ...)");
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001776 return -1;
1777 }
1778 tcp->flags &= ~TCB_BPTSET;
1779
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001780# if !LOOPA
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001781 /*
1782 * Since we don't have a single instruction breakpoint, we may have
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001783 * to adjust the program counter after removing our `breakpoint'.
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001784 */
Roland McGratheb9e2e82009-06-02 16:49:22 -07001785 if (ptrace(PTRACE_GETREGS, tcp->pid, (char *)&regs, 0) < 0) {
1786 perror("clearbpt: ptrace(PTRACE_GETREGS, ...)");
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001787 return -1;
1788 }
Roland McGratheb9e2e82009-06-02 16:49:22 -07001789 if ((regs.r_pc < tcp->baddr) ||
1790 (regs.r_pc > tcp->baddr + 4)) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001791 /* The breakpoint has not been reached yet */
1792 if (debug)
1793 fprintf(stderr,
1794 "NOTE: PC not at bpt (pc %#x baddr %#x)\n",
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001795 regs.r_pc, tcp->baddr);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001796 return 0;
1797 }
1798 if (regs.r_pc != tcp->baddr)
1799 if (debug)
1800 fprintf(stderr, "NOTE: PC adjusted (%#x -> %#x\n",
1801 regs.r_pc, tcp->baddr);
1802
1803 regs.r_pc = tcp->baddr;
Roland McGratheb9e2e82009-06-02 16:49:22 -07001804 if (ptrace(PTRACE_SETREGS, tcp->pid, (char *)&regs, 0) < 0) {
1805 perror("clearbpt: ptrace(PTRACE_SETREGS, ...)");
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001806 return -1;
1807 }
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001808# endif /* LOOPA */
1809# endif /* SPARC */
1810# endif /* SUNOS4 */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001811
1812 return 0;
1813}
1814
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001815# endif /* !defined LINUX */
Roland McGrathd81f1d92003-01-09 06:53:34 +00001816
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001817#endif /* !USE_PROCFS */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001818
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001819
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001820#ifdef SUNOS4
1821
1822static int
Denys Vlasenko12014262011-05-30 14:00:14 +02001823getex(struct tcb *tcp, struct exec *hdr)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001824{
1825 int n;
1826
1827 for (n = 0; n < sizeof *hdr; n += 4) {
1828 long res;
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001829 if (upeek(tcp, uoff(u_exdata) + n, &res) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001830 return -1;
1831 memcpy(((char *) hdr) + n, &res, 4);
1832 }
1833 if (debug) {
1834 fprintf(stderr, "[struct exec: magic: %o version %u Mach %o\n",
1835 hdr->a_magic, hdr->a_toolversion, hdr->a_machtype);
1836 fprintf(stderr, "Text %lu Data %lu Bss %lu Syms %lu Entry %#lx]\n",
1837 hdr->a_text, hdr->a_data, hdr->a_bss, hdr->a_syms, hdr->a_entry);
1838 }
1839 return 0;
1840}
1841
1842int
Denys Vlasenko12014262011-05-30 14:00:14 +02001843fixvfork(struct tcb *tcp)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001844{
1845 int pid = tcp->pid;
1846 /*
1847 * Change `vfork' in a freshly exec'ed dynamically linked
1848 * executable's (internal) symbol table to plain old `fork'
1849 */
1850
1851 struct exec hdr;
1852 struct link_dynamic dyn;
1853 struct link_dynamic_2 ld;
1854 char *strtab, *cp;
1855
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001856 if (getex(tcp, &hdr) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001857 return -1;
1858 if (!hdr.a_dynamic)
1859 return -1;
1860
1861 if (umove(tcp, (int) N_DATADDR(hdr), &dyn) < 0) {
1862 fprintf(stderr, "Cannot read DYNAMIC\n");
1863 return -1;
1864 }
1865 if (umove(tcp, (int) dyn.ld_un.ld_2, &ld) < 0) {
1866 fprintf(stderr, "Cannot read link_dynamic_2\n");
1867 return -1;
1868 }
Denys Vlasenko5d645812011-08-20 12:48:18 +02001869 strtab = malloc((unsigned)ld.ld_symb_size);
Denys Vlasenko1d46ba52011-08-31 14:00:02 +02001870 if (!strtab)
1871 die_out_of_memory();
Roland McGratheb9e2e82009-06-02 16:49:22 -07001872 if (umoven(tcp, (int)ld.ld_symbols+(int)N_TXTADDR(hdr),
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001873 (int)ld.ld_symb_size, strtab) < 0)
1874 goto err;
1875
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001876 for (cp = strtab; cp < strtab + ld.ld_symb_size; ) {
1877 if (strcmp(cp, "_vfork") == 0) {
1878 if (debug)
1879 fprintf(stderr, "fixvfork: FOUND _vfork\n");
1880 strcpy(cp, "_fork");
1881 break;
1882 }
1883 cp += strlen(cp)+1;
1884 }
1885 if (cp < strtab + ld.ld_symb_size)
1886 /*
1887 * Write entire symbol table back to avoid
1888 * memory alignment bugs in ptrace
1889 */
Roland McGratheb9e2e82009-06-02 16:49:22 -07001890 if (tload(pid, (int)ld.ld_symbols+(int)N_TXTADDR(hdr),
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001891 (int)ld.ld_symb_size, strtab) < 0)
1892 goto err;
1893
1894 free(strtab);
1895 return 0;
1896
1897err:
1898 free(strtab);
1899 return -1;
1900}
1901
1902#endif /* SUNOS4 */