blob: b6cdf9a5d211965ace2b9a7772b0c368d050fd05 [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 Vlasenko31fa8a22012-01-29 02:01:44 +0100227#ifdef PTRACE_LISTEN
228 if (op == PTRACE_LISTEN)
229 msg = "LISTEN";
230#endif
Denys Vlasenko014ca3a2011-09-02 16:19:30 +0200231 perror_msg("ptrace(PTRACE_%s,1,%d)", msg, sig);
Denys Vlasenko732d1bf2008-12-17 19:21:59 +0000232 return -1;
233}
234
235/*
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000236 * Print entry in struct xlat table, if there.
237 */
238void
Dmitry V. Levinab9008b2007-01-11 22:05:04 +0000239printxval(const struct xlat *xlat, int val, const char *dflt)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000240{
Dmitry V. Levinab9008b2007-01-11 22:05:04 +0000241 const char *str = xlookup(xlat, val);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000242
243 if (str)
Denys Vlasenko5940e652011-09-01 09:55:05 +0200244 tprints(str);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000245 else
246 tprintf("%#x /* %s */", val, dflt);
247}
248
Andreas Schwabb5600fc2009-11-04 17:08:34 +0100249#if HAVE_LONG_LONG
250/*
251 * Print 64bit argument at position llarg and return the index of the next
252 * argument.
253 */
254int
255printllval(struct tcb *tcp, const char *format, int llarg)
256{
257# if defined(FREEBSD) \
Andreas Schwabd69fa492010-07-12 21:39:57 +0200258 || (defined(LINUX) && defined(POWERPC) && !defined(POWERPC64)) \
Dmitry V. Levin7a5b08f2011-05-28 20:47:43 +0000259 || defined(LINUX_MIPSO32) \
260 || defined(__ARM_EABI__)
Andreas Schwabb5600fc2009-11-04 17:08:34 +0100261 /* Align 64bit argument to 64bit boundary. */
Denys Vlasenko4b08df42011-08-19 15:58:24 +0200262 llarg = (llarg + 1) & 0x1e;
Andreas Schwabb5600fc2009-11-04 17:08:34 +0100263# endif
Andreas Schwabd69fa492010-07-12 21:39:57 +0200264# if defined LINUX && (defined X86_64 || defined POWERPC64)
Andreas Schwabb5600fc2009-11-04 17:08:34 +0100265 if (current_personality == 0) {
266 tprintf(format, tcp->u_arg[llarg]);
267 llarg++;
268 } else {
Andreas Schwabd69fa492010-07-12 21:39:57 +0200269# ifdef POWERPC64
270 /* Align 64bit argument to 64bit boundary. */
Denys Vlasenko4b08df42011-08-19 15:58:24 +0200271 llarg = (llarg + 1) & 0x1e;
Andreas Schwabd69fa492010-07-12 21:39:57 +0200272# endif
Andreas Schwabb5600fc2009-11-04 17:08:34 +0100273 tprintf(format, LONG_LONG(tcp->u_arg[llarg], tcp->u_arg[llarg + 1]));
274 llarg += 2;
275 }
Andreas Schwabd69fa492010-07-12 21:39:57 +0200276# elif defined IA64 || defined ALPHA
Andreas Schwabb5600fc2009-11-04 17:08:34 +0100277 tprintf(format, tcp->u_arg[llarg]);
278 llarg++;
279# elif defined LINUX_MIPSN32
280 tprintf(format, tcp->ext_arg[llarg]);
281 llarg++;
282# else
283 tprintf(format, LONG_LONG(tcp->u_arg[llarg], tcp->u_arg[llarg + 1]));
284 llarg += 2;
285# endif
286 return llarg;
287}
288#endif
289
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000290/*
291 * Interpret `xlat' as an array of flags
292 * print the entries whose bits are on in `flags'
293 * return # of flags printed.
294 */
Denys Vlasenko4924dbd2011-08-19 18:06:46 +0200295void
Denys Vlasenko12014262011-05-30 14:00:14 +0200296addflags(const struct xlat *xlat, int flags)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000297{
Denys Vlasenko4924dbd2011-08-19 18:06:46 +0200298 for (; xlat->str; xlat++) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000299 if (xlat->val && (flags & xlat->val) == xlat->val) {
300 tprintf("|%s", xlat->str);
301 flags &= ~xlat->val;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000302 }
303 }
304 if (flags) {
305 tprintf("|%#x", flags);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000306 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000307}
308
Roland McGratha6c0d8c2007-11-01 21:46:22 +0000309/*
Denys Vlasenko4924dbd2011-08-19 18:06:46 +0200310 * Interpret `xlat' as an array of flags.
Roland McGratha6c0d8c2007-11-01 21:46:22 +0000311 * Print to static string the entries whose bits are on in `flags'
312 * Return static string.
313 */
314const char *
315sprintflags(const char *prefix, const struct xlat *xlat, int flags)
316{
317 static char outstr[1024];
Denys Vlasenko52845572011-08-31 12:07:38 +0200318 char *outptr;
Roland McGratha6c0d8c2007-11-01 21:46:22 +0000319 int found = 0;
320
Denys Vlasenko52845572011-08-31 12:07:38 +0200321 outptr = stpcpy(outstr, prefix);
Roland McGratha6c0d8c2007-11-01 21:46:22 +0000322
323 for (; xlat->str; xlat++) {
324 if ((flags & xlat->val) == xlat->val) {
325 if (found)
Denys Vlasenko52845572011-08-31 12:07:38 +0200326 *outptr++ = '|';
327 outptr = stpcpy(outptr, xlat->str);
Roland McGratha6c0d8c2007-11-01 21:46:22 +0000328 found = 1;
Denys Vlasenko4f3df072012-01-29 22:38:35 +0100329 flags &= ~xlat->val;
330 if (!flags)
331 break;
Roland McGratha6c0d8c2007-11-01 21:46:22 +0000332 }
333 }
334 if (flags) {
335 if (found)
Denys Vlasenko52845572011-08-31 12:07:38 +0200336 *outptr++ = '|';
337 outptr += sprintf(outptr, "%#x", flags);
Roland McGratha6c0d8c2007-11-01 21:46:22 +0000338 }
339
340 return outstr;
341}
342
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000343int
Dmitry V. Levin30145dd2010-09-06 22:08:24 +0000344printflags(const struct xlat *xlat, int flags, const char *dflt)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000345{
346 int n;
Dmitry V. Levin30145dd2010-09-06 22:08:24 +0000347 const char *sep;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000348
349 if (flags == 0 && xlat->val == 0) {
Denys Vlasenko5940e652011-09-01 09:55:05 +0200350 tprints(xlat->str);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000351 return 1;
352 }
353
354 sep = "";
355 for (n = 0; xlat->str; xlat++) {
356 if (xlat->val && (flags & xlat->val) == xlat->val) {
357 tprintf("%s%s", sep, xlat->str);
358 flags &= ~xlat->val;
359 sep = "|";
360 n++;
361 }
362 }
Roland McGrathb2dee132005-06-01 19:02:36 +0000363
364 if (n) {
365 if (flags) {
366 tprintf("%s%#x", sep, flags);
367 n++;
368 }
369 } else {
370 if (flags) {
371 tprintf("%#x", flags);
372 if (dflt)
373 tprintf(" /* %s */", dflt);
374 } else {
375 if (dflt)
Denys Vlasenko60fe8c12011-09-01 10:00:28 +0200376 tprints("0");
Roland McGrathb2dee132005-06-01 19:02:36 +0000377 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000378 }
Roland McGrathb2dee132005-06-01 19:02:36 +0000379
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000380 return n;
381}
382
383void
Dmitry V. Levin30145dd2010-09-06 22:08:24 +0000384printnum(struct tcb *tcp, long addr, const char *fmt)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000385{
Roland McGratheb285352003-01-14 09:59:00 +0000386 long num;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000387
388 if (!addr) {
Denys Vlasenko60fe8c12011-09-01 10:00:28 +0200389 tprints("NULL");
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000390 return;
391 }
392 if (umove(tcp, addr, &num) < 0) {
393 tprintf("%#lx", addr);
394 return;
395 }
Denys Vlasenko60fe8c12011-09-01 10:00:28 +0200396 tprints("[");
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000397 tprintf(fmt, num);
Denys Vlasenko60fe8c12011-09-01 10:00:28 +0200398 tprints("]");
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000399}
400
Roland McGrath6bc12202003-11-13 22:32:27 +0000401void
Dmitry V. Levin30145dd2010-09-06 22:08:24 +0000402printnum_int(struct tcb *tcp, long addr, const char *fmt)
Roland McGrath9814a942005-07-04 23:28:10 +0000403{
404 int num;
405
406 if (!addr) {
Denys Vlasenko60fe8c12011-09-01 10:00:28 +0200407 tprints("NULL");
Roland McGrath9814a942005-07-04 23:28:10 +0000408 return;
409 }
410 if (umove(tcp, addr, &num) < 0) {
411 tprintf("%#lx", addr);
412 return;
413 }
Denys Vlasenko60fe8c12011-09-01 10:00:28 +0200414 tprints("[");
Roland McGrath9814a942005-07-04 23:28:10 +0000415 tprintf(fmt, num);
Denys Vlasenko60fe8c12011-09-01 10:00:28 +0200416 tprints("]");
Roland McGrath9814a942005-07-04 23:28:10 +0000417}
418
419void
Dmitry V. Levin31382132011-03-04 05:08:02 +0300420printfd(struct tcb *tcp, int fd)
421{
Grant Edwards8a082772011-04-07 20:25:40 +0000422 const char *p;
423
424 if (show_fd_path && (p = getfdpath(tcp, fd)))
425 tprintf("%d<%s>", fd, p);
426 else
427 tprintf("%d", fd);
Dmitry V. Levin31382132011-03-04 05:08:02 +0300428}
429
430void
Denys Vlasenko12014262011-05-30 14:00:14 +0200431printuid(const char *text, unsigned long uid)
Roland McGrath6bc12202003-11-13 22:32:27 +0000432{
Denys Vlasenko5940e652011-09-01 09:55:05 +0200433 tprintf((uid == -1) ? "%s%ld" : "%s%lu", text, uid);
Roland McGrath6bc12202003-11-13 22:32:27 +0000434}
435
Dmitry V. Levina501f142008-11-10 23:19:13 +0000436/*
437 * Quote string `instr' of length `size'
438 * Write up to (3 + `size' * 4) bytes to `outstr' buffer.
439 * If `len' < 0, treat `instr' as a NUL-terminated string
440 * and quote at most (`size' - 1) bytes.
Denys Vlasenko6cecba52012-01-20 11:56:00 +0100441 *
442 * Returns 0 if len < 0 and NUL was seen, 1 otherwise.
443 * Note that if len >= 0, always returns 1.
Dmitry V. Levina501f142008-11-10 23:19:13 +0000444 */
Roland McGrath6d970322007-11-01 23:53:59 +0000445static int
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000446string_quote(const char *instr, char *outstr, int len, int size)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000447{
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000448 const unsigned char *ustr = (const unsigned char *) instr;
449 char *s = outstr;
Denys Vlasenko8778bff2011-08-31 12:22:56 +0200450 int usehex, c, i, eol;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000451
Denys Vlasenko8778bff2011-08-31 12:22:56 +0200452 eol = 0x100; /* this can never match a char */
453 if (len < 0) {
454 size--;
455 eol = '\0';
456 }
457
458 usehex = 0;
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000459 if (xflag > 1)
460 usehex = 1;
461 else if (xflag) {
Dmitry V. Levina501f142008-11-10 23:19:13 +0000462 /* Check for presence of symbol which require
463 to hex-quote the whole string. */
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000464 for (i = 0; i < size; ++i) {
465 c = ustr[i];
Dmitry V. Levina501f142008-11-10 23:19:13 +0000466 /* Check for NUL-terminated string. */
Denys Vlasenko8778bff2011-08-31 12:22:56 +0200467 if (c == eol)
468 break;
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000469 if (!isprint(c) && !isspace(c)) {
470 usehex = 1;
471 break;
472 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000473 }
474 }
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000475
476 *s++ = '\"';
477
478 if (usehex) {
Dmitry V. Levina501f142008-11-10 23:19:13 +0000479 /* Hex-quote the whole string. */
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000480 for (i = 0; i < size; ++i) {
481 c = ustr[i];
Dmitry V. Levina501f142008-11-10 23:19:13 +0000482 /* Check for NUL-terminated string. */
Denys Vlasenko8778bff2011-08-31 12:22:56 +0200483 if (c == eol)
484 goto asciz_ended;
485 *s++ = '\\';
486 *s++ = 'x';
487 *s++ = "0123456789abcdef"[c >> 4];
488 *s++ = "0123456789abcdef"[c & 0xf];
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000489 }
490 } else {
491 for (i = 0; i < size; ++i) {
492 c = ustr[i];
Dmitry V. Levina501f142008-11-10 23:19:13 +0000493 /* Check for NUL-terminated string. */
Denys Vlasenko8778bff2011-08-31 12:22:56 +0200494 if (c == eol)
495 goto asciz_ended;
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000496 switch (c) {
497 case '\"': case '\\':
498 *s++ = '\\';
499 *s++ = c;
500 break;
501 case '\f':
502 *s++ = '\\';
503 *s++ = 'f';
504 break;
505 case '\n':
506 *s++ = '\\';
507 *s++ = 'n';
508 break;
509 case '\r':
510 *s++ = '\\';
511 *s++ = 'r';
512 break;
513 case '\t':
514 *s++ = '\\';
515 *s++ = 't';
516 break;
517 case '\v':
518 *s++ = '\\';
519 *s++ = 'v';
520 break;
521 default:
522 if (isprint(c))
523 *s++ = c;
Denys Vlasenko8778bff2011-08-31 12:22:56 +0200524 else {
525 /* Print \octal */
526 *s++ = '\\';
527 if (i + 1 < size
528 && ustr[i + 1] >= '0'
529 && ustr[i + 1] <= '9'
530 ) {
531 /* Print \ooo */
532 *s++ = '0' + (c >> 6);
533 *s++ = '0' + ((c >> 3) & 0x7);
534 } else {
535 /* Print \[[o]o]o */
536 if ((c >> 3) != 0) {
537 if ((c >> 6) != 0)
538 *s++ = '0' + (c >> 6);
539 *s++ = '0' + ((c >> 3) & 0x7);
540 }
541 }
542 *s++ = '0' + (c & 0x7);
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000543 }
544 break;
545 }
546 }
547 }
548
549 *s++ = '\"';
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000550 *s = '\0';
Roland McGrath6d970322007-11-01 23:53:59 +0000551
Denys Vlasenko8778bff2011-08-31 12:22:56 +0200552 /* Return zero if we printed entire ASCIZ string (didn't truncate it) */
553 if (len < 0 && ustr[i] == '\0') {
554 /* We didn't see NUL yet (otherwise we'd jump to 'asciz_ended')
555 * but next char is NUL.
556 */
557 return 0;
558 }
559
560 return 1;
561
562 asciz_ended:
563 *s++ = '\"';
564 *s = '\0';
565 /* Return zero: we printed entire ASCIZ string (didn't truncate it) */
566 return 0;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000567}
568
Dmitry V. Levina501f142008-11-10 23:19:13 +0000569/*
570 * Print path string specified by address `addr' and length `n'.
571 * If path length exceeds `n', append `...' to the output.
572 */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000573void
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000574printpathn(struct tcb *tcp, long addr, int n)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000575{
Denys Vlasenkob3c52cf2012-01-19 17:20:23 +0100576 char path[MAXPATHLEN + 1];
Denys Vlasenko6cecba52012-01-20 11:56:00 +0100577 int nul_seen;
Denys Vlasenkob3c52cf2012-01-19 17:20:23 +0100578
Dmitry V. Levina501f142008-11-10 23:19:13 +0000579 if (!addr) {
Denys Vlasenko60fe8c12011-09-01 10:00:28 +0200580 tprints("NULL");
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000581 return;
582 }
583
Denys Vlasenko6cecba52012-01-20 11:56:00 +0100584 /* Cap path length to the path buffer size */
Dmitry V. Levina501f142008-11-10 23:19:13 +0000585 if (n > sizeof path - 1)
586 n = sizeof path - 1;
Dmitry V. Levina501f142008-11-10 23:19:13 +0000587
588 /* Fetch one byte more to find out whether path length > n. */
Denys Vlasenko6cecba52012-01-20 11:56:00 +0100589 nul_seen = umovestr(tcp, addr, n + 1, path);
590 if (nul_seen < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000591 tprintf("%#lx", addr);
592 else {
Denys Vlasenkob3c52cf2012-01-19 17:20:23 +0100593 char *outstr;
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000594
Denys Vlasenko6cecba52012-01-20 11:56:00 +0100595 path[n] = '\0';
Denys Vlasenkob3c52cf2012-01-19 17:20:23 +0100596 n++;
Denys Vlasenko6cecba52012-01-20 11:56:00 +0100597 outstr = alloca(4 * n); /* 4*(n-1) + 3 for quotes and NUL */
Denys Vlasenkob3c52cf2012-01-19 17:20:23 +0100598 string_quote(path, outstr, -1, n);
599 tprints(outstr);
Denys Vlasenko6cecba52012-01-20 11:56:00 +0100600 if (!nul_seen)
Denys Vlasenkob3c52cf2012-01-19 17:20:23 +0100601 tprints("...");
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000602 }
603}
604
605void
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000606printpath(struct tcb *tcp, long addr)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000607{
Denys Vlasenkob3c52cf2012-01-19 17:20:23 +0100608 /* Size must correspond to char path[] size in printpathn */
609 printpathn(tcp, addr, MAXPATHLEN);
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000610}
611
Dmitry V. Levina501f142008-11-10 23:19:13 +0000612/*
613 * Print string specified by address `addr' and length `len'.
614 * If `len' < 0, treat the string as a NUL-terminated string.
615 * If string length exceeds `max_strlen', append `...' to the output.
616 */
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000617void
618printstr(struct tcb *tcp, long addr, int len)
619{
620 static char *str = NULL;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000621 static char *outstr;
Roland McGrath6d970322007-11-01 23:53:59 +0000622 int size;
Denys Vlasenkob3c52cf2012-01-19 17:20:23 +0100623 int ellipsis;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000624
625 if (!addr) {
Denys Vlasenko60fe8c12011-09-01 10:00:28 +0200626 tprints("NULL");
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000627 return;
628 }
Dmitry V. Levina501f142008-11-10 23:19:13 +0000629 /* Allocate static buffers if they are not allocated yet. */
Denys Vlasenko1d46ba52011-08-31 14:00:02 +0200630 if (!str) {
Dmitry V. Levina501f142008-11-10 23:19:13 +0000631 str = malloc(max_strlen + 1);
Denys Vlasenko1d46ba52011-08-31 14:00:02 +0200632 if (!str)
633 die_out_of_memory();
Denys Vlasenko6cecba52012-01-20 11:56:00 +0100634 outstr = malloc(4 * max_strlen + /*for quotes and NUL:*/ 3);
Denys Vlasenko1d46ba52011-08-31 14:00:02 +0200635 if (!outstr)
636 die_out_of_memory();
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000637 }
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000638
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000639 if (len < 0) {
Dmitry V. Levina501f142008-11-10 23:19:13 +0000640 /*
641 * Treat as a NUL-terminated string: fetch one byte more
642 * because string_quote() quotes one byte less.
643 */
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000644 size = max_strlen + 1;
645 if (umovestr(tcp, addr, size, str) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000646 tprintf("%#lx", addr);
647 return;
648 }
649 }
650 else {
Dmitry V. Levina501f142008-11-10 23:19:13 +0000651 size = MIN(len, max_strlen);
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000652 if (umoven(tcp, addr, size, str) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000653 tprintf("%#lx", addr);
654 return;
655 }
656 }
657
Denys Vlasenko6cecba52012-01-20 11:56:00 +0100658 /* If string_quote didn't see NUL and (it was supposed to be ASCIZ str
659 * or we were requested to print more than -s NUM chars)...
660 */
Denys Vlasenkob3c52cf2012-01-19 17:20:23 +0100661 ellipsis = (string_quote(str, outstr, len, size) &&
662 (len < 0 || len > max_strlen));
Roland McGratha503dcf2007-08-02 02:06:26 +0000663
Denys Vlasenkob3c52cf2012-01-19 17:20:23 +0100664 tprints(outstr);
665 if (ellipsis)
666 tprints("...");
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000667}
668
John Hughes1d08dcf2001-07-10 13:48:44 +0000669#if HAVE_SYS_UIO_H
670void
Denys Vlasenko12014262011-05-30 14:00:14 +0200671dumpiov(struct tcb *tcp, int len, long addr)
John Hughes1d08dcf2001-07-10 13:48:44 +0000672{
Dmitry V. Levin4ebb4e32006-12-13 17:08:08 +0000673#if defined(LINUX) && SUPPORTED_PERSONALITIES > 1
674 union {
675 struct { u_int32_t base; u_int32_t len; } *iov32;
676 struct { u_int64_t base; u_int64_t len; } *iov64;
677 } iovu;
678#define iov iovu.iov64
679#define sizeof_iov \
680 (personality_wordsize[current_personality] == 4 \
681 ? sizeof(*iovu.iov32) : sizeof(*iovu.iov64))
682#define iov_iov_base(i) \
683 (personality_wordsize[current_personality] == 4 \
684 ? (u_int64_t) iovu.iov32[i].base : iovu.iov64[i].base)
685#define iov_iov_len(i) \
686 (personality_wordsize[current_personality] == 4 \
687 ? (u_int64_t) iovu.iov32[i].len : iovu.iov64[i].len)
688#else
John Hughes1d08dcf2001-07-10 13:48:44 +0000689 struct iovec *iov;
Dmitry V. Levin4ebb4e32006-12-13 17:08:08 +0000690#define sizeof_iov sizeof(*iov)
691#define iov_iov_base(i) iov[i].iov_base
692#define iov_iov_len(i) iov[i].iov_len
693#endif
John Hughes1d08dcf2001-07-10 13:48:44 +0000694 int i;
Denys Vlasenko79a79ea2011-09-01 16:35:44 +0200695 unsigned size;
John Hughes1d08dcf2001-07-10 13:48:44 +0000696
Denys Vlasenko79a79ea2011-09-01 16:35:44 +0200697 size = sizeof_iov * len;
698 /* Assuming no sane program has millions of iovs */
699 if ((unsigned)len > 1024*1024 /* insane or negative size? */
Dmitry V. Levin4ebb4e32006-12-13 17:08:08 +0000700 || (iov = malloc(size)) == NULL) {
Denys Vlasenko79a79ea2011-09-01 16:35:44 +0200701 fprintf(stderr, "Out of memory\n");
702 return;
John Hughes1d08dcf2001-07-10 13:48:44 +0000703 }
Roland McGrathaa524c82005-06-01 19:22:06 +0000704 if (umoven(tcp, addr, size, (char *) iov) >= 0) {
John Hughes1d08dcf2001-07-10 13:48:44 +0000705 for (i = 0; i < len; i++) {
Denys Vlasenkoadedb512008-12-30 18:47:55 +0000706 /* include the buffer number to make it easy to
707 * match up the trace with the source */
708 tprintf(" * %lu bytes in buffer %d\n",
709 (unsigned long)iov_iov_len(i), i);
710 dumpstr(tcp, (long) iov_iov_base(i),
711 iov_iov_len(i));
712 }
John Hughes1d08dcf2001-07-10 13:48:44 +0000713 }
Denys Vlasenko79a79ea2011-09-01 16:35:44 +0200714 free(iov);
Dmitry V. Levin4ebb4e32006-12-13 17:08:08 +0000715#undef sizeof_iov
716#undef iov_iov_base
717#undef iov_iov_len
718#undef iov
John Hughes1d08dcf2001-07-10 13:48:44 +0000719}
720#endif
721
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000722void
Denys Vlasenko12014262011-05-30 14:00:14 +0200723dumpstr(struct tcb *tcp, long addr, int len)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000724{
725 static int strsize = -1;
726 static unsigned char *str;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000727 char *s;
728 int i, j;
729
730 if (strsize < len) {
Denys Vlasenko5d645812011-08-20 12:48:18 +0200731 free(str);
732 str = malloc(len);
Denys Vlasenko79a79ea2011-09-01 16:35:44 +0200733 if (!str) {
734 strsize = -1;
735 fprintf(stderr, "Out of memory\n");
736 return;
737 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000738 strsize = len;
739 }
740
741 if (umoven(tcp, addr, len, (char *) str) < 0)
742 return;
743
744 for (i = 0; i < len; i += 16) {
Denys Vlasenko1d46ba52011-08-31 14:00:02 +0200745 char outstr[80];
746
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000747 s = outstr;
748 sprintf(s, " | %05x ", i);
749 s += 9;
750 for (j = 0; j < 16; j++) {
751 if (j == 8)
752 *s++ = ' ';
753 if (i + j < len) {
754 sprintf(s, " %02x", str[i + j]);
755 s += 3;
756 }
757 else {
758 *s++ = ' '; *s++ = ' '; *s++ = ' ';
759 }
760 }
761 *s++ = ' '; *s++ = ' ';
762 for (j = 0; j < 16; j++) {
763 if (j == 8)
764 *s++ = ' ';
765 if (i + j < len) {
766 if (isprint(str[i + j]))
767 *s++ = str[i + j];
768 else
769 *s++ = '.';
770 }
771 else
772 *s++ = ' ';
773 }
774 tprintf("%s |\n", outstr);
775 }
776}
777
Denys Vlasenko3af224c2012-01-28 01:46:33 +0100778
779/* Need to do this since process_vm_readv() is not yet available in libc.
780 * When libc is be updated, only "static bool process_vm_readv_not_supported"
781 * line should remain.
782 */
783#if !defined(__NR_process_vm_readv)
784# if defined(I386)
785# define __NR_process_vm_readv 347
786# elif defined(X86_64)
787# define __NR_process_vm_readv 310
788# elif defined(POWERPC)
789# define __NR_process_vm_readv 351
790# endif
791#endif
792
793#if defined(__NR_process_vm_readv)
794static bool process_vm_readv_not_supported = 0;
795static ssize_t process_vm_readv(pid_t pid,
796 const struct iovec *lvec,
797 unsigned long liovcnt,
798 const struct iovec *rvec,
799 unsigned long riovcnt,
800 unsigned long flags)
801{
802 return syscall(__NR_process_vm_readv, (long)pid, lvec, liovcnt, rvec, riovcnt, flags);
803}
804#else
805static bool process_vm_readv_not_supported = 1;
806# define process_vm_readv(...) (errno = ENOSYS, -1)
807#endif
808/* end of hack */
809
810
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000811#define PAGMASK (~(PAGSIZ - 1))
812/*
813 * move `len' bytes of data from process `pid'
814 * at address `addr' to our space at `laddr'
815 */
816int
Denys Vlasenkoef2fbf82009-01-06 21:45:06 +0000817umoven(struct tcb *tcp, long addr, int len, char *laddr)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000818{
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000819#ifdef LINUX
Roland McGratheb9e2e82009-06-02 16:49:22 -0700820 int pid = tcp->pid;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000821 int n, m;
Denys Vlasenkoa47e6b92012-01-21 04:01:56 +0100822 int started;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000823 union {
824 long val;
825 char x[sizeof(long)];
826 } u;
827
Denys Vlasenko3af224c2012-01-28 01:46:33 +0100828 if (!process_vm_readv_not_supported) {
829 struct iovec local[1], remote[1];
830 int r;
831
832 local[0].iov_base = laddr;
833 remote[0].iov_base = (void*)addr;
834 local[0].iov_len = remote[0].iov_len = len;
835 r = process_vm_readv(pid,
836 local, 1,
837 remote, 1,
838 /*flags:*/ 0
839 );
840 if (r < 0) {
841 if (errno == ENOSYS)
842 process_vm_readv_not_supported = 1;
Denys Vlasenko29456392012-01-28 02:49:48 +0100843 else if (errno != EINVAL) /* EINVAL is seen if process is gone */
844 /* strange... */
Denys Vlasenko3af224c2012-01-28 01:46:33 +0100845 perror("process_vm_readv");
846 goto vm_readv_didnt_work;
847 }
848 return r;
849 }
850 vm_readv_didnt_work:
851
Dmitry V. Levin856c7ed2011-12-26 20:12:02 +0000852#if SUPPORTED_PERSONALITIES > 1
853 if (personality_wordsize[current_personality] < sizeof(addr))
854 addr &= (1ul << 8 * personality_wordsize[current_personality]) - 1;
855#endif
856
Denys Vlasenkoa47e6b92012-01-21 04:01:56 +0100857 started = 0;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000858 if (addr & (sizeof(long) - 1)) {
859 /* addr not a multiple of sizeof(long) */
860 n = addr - (addr & -sizeof(long)); /* residue */
861 addr &= -sizeof(long); /* residue */
Roland McGratheb9e2e82009-06-02 16:49:22 -0700862 errno = 0;
863 u.val = ptrace(PTRACE_PEEKDATA, pid, (char *) addr, 0);
864 if (errno) {
Roland McGratheb9e2e82009-06-02 16:49:22 -0700865 /* But if not started, we had a bogus address. */
866 if (addr != 0 && errno != EIO && errno != ESRCH)
867 perror("ptrace: umoven");
868 return -1;
869 }
Wichert Akkerman5daa0281999-03-15 19:49:42 +0000870 started = 1;
Denys Vlasenkoa47e6b92012-01-21 04:01:56 +0100871 m = MIN(sizeof(long) - n, len);
872 memcpy(laddr, &u.x[n], m);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000873 addr += sizeof(long), laddr += m, len -= m;
874 }
875 while (len) {
Roland McGratheb9e2e82009-06-02 16:49:22 -0700876 errno = 0;
877 u.val = ptrace(PTRACE_PEEKDATA, pid, (char *) addr, 0);
878 if (errno) {
879 if (started && (errno==EPERM || errno==EIO)) {
880 /* Ran into 'end of memory' - stupid "printpath" */
881 return 0;
882 }
883 if (addr != 0 && errno != EIO && errno != ESRCH)
884 perror("ptrace: umoven");
885 return -1;
886 }
Wichert Akkerman5daa0281999-03-15 19:49:42 +0000887 started = 1;
Denys Vlasenkoa47e6b92012-01-21 04:01:56 +0100888 m = MIN(sizeof(long), len);
889 memcpy(laddr, u.x, m);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000890 addr += sizeof(long), laddr += m, len -= m;
891 }
892#endif /* LINUX */
893
894#ifdef SUNOS4
895 int pid = tcp->pid;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000896 int n;
897
898 while (len) {
899 n = MIN(len, PAGSIZ);
900 n = MIN(n, ((addr + PAGSIZ) & PAGMASK) - addr);
Roland McGratheb9e2e82009-06-02 16:49:22 -0700901 if (ptrace(PTRACE_READDATA, pid,
902 (char *) addr, len, laddr) < 0) {
903 if (errno != ESRCH) {
904 perror("umoven: ptrace(PTRACE_READDATA, ...)");
905 abort();
906 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000907 return -1;
908 }
909 len -= n;
910 addr += n;
911 laddr += n;
912 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000913#endif /* SUNOS4 */
914
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000915#ifdef USE_PROCFS
Wichert Akkermanea78f0f1999-11-29 15:34:02 +0000916#ifdef HAVE_MP_PROCFS
John Hughesaa09c6b2001-05-15 14:53:43 +0000917 int fd = tcp->pfd_as;
Wichert Akkerman9ce1a631999-08-29 23:15:07 +0000918#else
John Hughesaa09c6b2001-05-15 14:53:43 +0000919 int fd = tcp->pfd;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000920#endif
John Hughesaa09c6b2001-05-15 14:53:43 +0000921 lseek(fd, addr, SEEK_SET);
922 if (read(fd, laddr, len) == -1)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000923 return -1;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000924#endif /* USE_PROCFS */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000925
926 return 0;
927}
928
929/*
Denys Vlasenko6cecba52012-01-20 11:56:00 +0100930 * Like `umove' but make the additional effort of looking
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000931 * for a terminating zero byte.
Denys Vlasenko6cecba52012-01-20 11:56:00 +0100932 *
933 * Returns < 0 on error, > 0 if NUL was seen,
934 * (TODO if useful: return count of bytes including NUL),
935 * else 0 if len bytes were read but no NUL byte seen.
936 *
937 * Note: there is no guarantee we won't overwrite some bytes
938 * in laddr[] _after_ terminating NUL (but, of course,
939 * we never write past laddr[len-1]).
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000940 */
941int
Denys Vlasenkoef2fbf82009-01-06 21:45:06 +0000942umovestr(struct tcb *tcp, long addr, int len, char *laddr)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000943{
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000944#ifdef USE_PROCFS
Denys Vlasenkoa47e6b92012-01-21 04:01:56 +0100945# ifdef HAVE_MP_PROCFS
John Hughesaa09c6b2001-05-15 14:53:43 +0000946 int fd = tcp->pfd_as;
Denys Vlasenkoa47e6b92012-01-21 04:01:56 +0100947# else
John Hughesaa09c6b2001-05-15 14:53:43 +0000948 int fd = tcp->pfd;
Denys Vlasenkoa47e6b92012-01-21 04:01:56 +0100949# endif
John Hughesaa09c6b2001-05-15 14:53:43 +0000950 /* Some systems (e.g. FreeBSD) can be upset if we read off the
951 end of valid memory, avoid this by trying to read up
952 to page boundaries. But we don't know what a page is (and
953 getpagesize(2) (if it exists) doesn't necessarily return
954 hardware page size). Assume all pages >= 1024 (a-historical
955 I know) */
956
Denys Vlasenkob63256e2011-06-07 12:13:24 +0200957 int page = 1024; /* How to find this? */
John Hughesaa09c6b2001-05-15 14:53:43 +0000958 int move = page - (addr & (page - 1));
959 int left = len;
960
961 lseek(fd, addr, SEEK_SET);
962
963 while (left) {
Denys Vlasenko5d645812011-08-20 12:48:18 +0200964 if (move > left)
965 move = left;
966 move = read(fd, laddr, move);
967 if (move <= 0)
John Hughesaa09c6b2001-05-15 14:53:43 +0000968 return left != len ? 0 : -1;
Denys Vlasenko5d645812011-08-20 12:48:18 +0200969 if (memchr(laddr, 0, move))
Denys Vlasenko6cecba52012-01-20 11:56:00 +0100970 return 1;
John Hughesaa09c6b2001-05-15 14:53:43 +0000971 left -= move;
972 laddr += move;
973 addr += move;
974 move = page;
975 }
Denys Vlasenkoa47e6b92012-01-21 04:01:56 +0100976 return 0;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000977#else /* !USE_PROCFS */
Denys Vlasenkoa47e6b92012-01-21 04:01:56 +0100978 int started;
Roland McGratheb9e2e82009-06-02 16:49:22 -0700979 int pid = tcp->pid;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000980 int i, n, m;
981 union {
982 long val;
983 char x[sizeof(long)];
984 } u;
985
Dmitry V. Levin856c7ed2011-12-26 20:12:02 +0000986#if SUPPORTED_PERSONALITIES > 1
987 if (personality_wordsize[current_personality] < sizeof(addr))
988 addr &= (1ul << 8 * personality_wordsize[current_personality]) - 1;
989#endif
990
Denys Vlasenko3af224c2012-01-28 01:46:33 +0100991 if (!process_vm_readv_not_supported) {
992 struct iovec local[1], remote[1];
993
994 local[0].iov_base = laddr;
995 remote[0].iov_base = (void*)addr;
996
997 while (len > 0) {
998 int end_in_page;
999 int r;
1000 int chunk_len;
1001
1002 /* Don't read kilobytes: most strings are short */
1003 chunk_len = len;
1004 if (chunk_len > 256)
1005 chunk_len = 256;
1006 /* Don't cross pages. I guess otherwise we can get EFAULT
1007 * and fail to notice that terminating NUL lies
1008 * in the existing (first) page.
1009 * (I hope there aren't arches with pages < 4K)
1010 */
1011 end_in_page = ((addr + chunk_len) & 4095);
1012 r = chunk_len - end_in_page;
1013 if (r > 0) /* if chunk_len > end_in_page */
1014 chunk_len = r; /* chunk_len -= end_in_page */
1015
1016 local[0].iov_len = remote[0].iov_len = chunk_len;
1017 r = process_vm_readv(pid,
1018 local, 1,
1019 remote, 1,
1020 /*flags:*/ 0
1021 );
1022 if (r < 0) {
1023 if (errno == ENOSYS)
1024 process_vm_readv_not_supported = 1;
Denys Vlasenko29456392012-01-28 02:49:48 +01001025 else if (errno != EINVAL) /* EINVAL is seen if process is gone */
1026 /* strange... */
Denys Vlasenko3af224c2012-01-28 01:46:33 +01001027 perror("process_vm_readv");
1028 goto vm_readv_didnt_work;
1029 }
1030 if (memchr(local[0].iov_base, '\0', r))
1031 return 1;
1032 local[0].iov_base += r;
1033 remote[0].iov_base += r;
1034 len -= r;
1035 }
1036 return 0;
1037 }
1038 vm_readv_didnt_work:
1039
Denys Vlasenkoa47e6b92012-01-21 04:01:56 +01001040 started = 0;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001041 if (addr & (sizeof(long) - 1)) {
1042 /* addr not a multiple of sizeof(long) */
1043 n = addr - (addr & -sizeof(long)); /* residue */
1044 addr &= -sizeof(long); /* residue */
Roland McGratheb9e2e82009-06-02 16:49:22 -07001045 errno = 0;
1046 u.val = ptrace(PTRACE_PEEKDATA, pid, (char *)addr, 0);
1047 if (errno) {
Roland McGratheb9e2e82009-06-02 16:49:22 -07001048 if (addr != 0 && errno != EIO && errno != ESRCH)
1049 perror("umovestr");
1050 return -1;
1051 }
Wichert Akkerman5daa0281999-03-15 19:49:42 +00001052 started = 1;
Denys Vlasenkoa47e6b92012-01-21 04:01:56 +01001053 m = MIN(sizeof(long) - n, len);
1054 memcpy(laddr, &u.x[n], m);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001055 while (n & (sizeof(long) - 1))
1056 if (u.x[n++] == '\0')
Denys Vlasenko6cecba52012-01-20 11:56:00 +01001057 return 1;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001058 addr += sizeof(long), laddr += m, len -= m;
1059 }
1060 while (len) {
Roland McGratheb9e2e82009-06-02 16:49:22 -07001061 errno = 0;
1062 u.val = ptrace(PTRACE_PEEKDATA, pid, (char *)addr, 0);
1063 if (errno) {
1064 if (started && (errno==EPERM || errno==EIO)) {
1065 /* Ran into 'end of memory' - stupid "printpath" */
1066 return 0;
1067 }
1068 if (addr != 0 && errno != EIO && errno != ESRCH)
1069 perror("umovestr");
1070 return -1;
1071 }
Wichert Akkerman5daa0281999-03-15 19:49:42 +00001072 started = 1;
Denys Vlasenkoa47e6b92012-01-21 04:01:56 +01001073 m = MIN(sizeof(long), len);
1074 memcpy(laddr, u.x, m);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001075 for (i = 0; i < sizeof(long); i++)
1076 if (u.x[i] == '\0')
Denys Vlasenko6cecba52012-01-20 11:56:00 +01001077 return 1;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001078 addr += sizeof(long), laddr += m, len -= m;
1079 }
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001080#endif /* !USE_PROCFS */
John Hughesaa09c6b2001-05-15 14:53:43 +00001081 return 0;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001082}
1083
1084#ifdef LINUX
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001085# if !defined (SPARC) && !defined(SPARC64)
1086# define PTRACE_WRITETEXT 101
1087# define PTRACE_WRITEDATA 102
1088# endif /* !SPARC && !SPARC64 */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001089#endif /* LINUX */
1090
1091#ifdef SUNOS4
1092
1093static int
Denys Vlasenko12014262011-05-30 14:00:14 +02001094uload(int cmd, int pid, long addr, int len, char *laddr)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001095{
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001096 int peek, poke;
1097 int n, m;
1098 union {
1099 long val;
1100 char x[sizeof(long)];
1101 } u;
1102
1103 if (cmd == PTRACE_WRITETEXT) {
1104 peek = PTRACE_PEEKTEXT;
1105 poke = PTRACE_POKETEXT;
1106 }
1107 else {
1108 peek = PTRACE_PEEKDATA;
1109 poke = PTRACE_POKEDATA;
1110 }
1111 if (addr & (sizeof(long) - 1)) {
1112 /* addr not a multiple of sizeof(long) */
1113 n = addr - (addr & -sizeof(long)); /* residue */
1114 addr &= -sizeof(long);
Roland McGratheb9e2e82009-06-02 16:49:22 -07001115 errno = 0;
1116 u.val = ptrace(peek, pid, (char *) addr, 0);
1117 if (errno) {
1118 perror("uload: POKE");
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001119 return -1;
1120 }
Denys Vlasenkoa47e6b92012-01-21 04:01:56 +01001121 m = MIN(sizeof(long) - n, len);
1122 memcpy(&u.x[n], laddr, m);
Roland McGratheb9e2e82009-06-02 16:49:22 -07001123 if (ptrace(poke, pid, (char *)addr, u.val) < 0) {
1124 perror("uload: POKE");
1125 return -1;
1126 }
1127 addr += sizeof(long), laddr += m, len -= m;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001128 }
1129 while (len) {
1130 if (len < sizeof(long))
Roland McGratheb9e2e82009-06-02 16:49:22 -07001131 u.val = ptrace(peek, pid, (char *) addr, 0);
Denys Vlasenkoa47e6b92012-01-21 04:01:56 +01001132 m = MIN(sizeof(long), len);
1133 memcpy(u.x, laddr, m);
Roland McGratheb9e2e82009-06-02 16:49:22 -07001134 if (ptrace(poke, pid, (char *) addr, u.val) < 0) {
1135 perror("uload: POKE");
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001136 return -1;
1137 }
Roland McGratheb9e2e82009-06-02 16:49:22 -07001138 addr += sizeof(long), laddr += m, len -= m;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001139 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001140 return 0;
1141}
1142
Roland McGratheb9e2e82009-06-02 16:49:22 -07001143int
Denys Vlasenko12014262011-05-30 14:00:14 +02001144tload(int pid, int addr, int len, char *laddr)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001145{
Roland McGratheb9e2e82009-06-02 16:49:22 -07001146 return uload(PTRACE_WRITETEXT, pid, addr, len, laddr);
1147}
1148
1149int
Denys Vlasenko12014262011-05-30 14:00:14 +02001150dload(int pid, int addr, int len, char *laddr)
Roland McGratheb9e2e82009-06-02 16:49:22 -07001151{
1152 return uload(PTRACE_WRITEDATA, pid, addr, len, laddr);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001153}
1154
1155#endif /* SUNOS4 */
1156
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001157#ifndef USE_PROCFS
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001158
1159int
Denys Vlasenko12014262011-05-30 14:00:14 +02001160upeek(struct tcb *tcp, long off, long *res)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001161{
1162 long val;
1163
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001164# ifdef SUNOS4_KERNEL_ARCH_KLUDGE
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001165 {
1166 static int is_sun4m = -1;
1167 struct utsname name;
1168
1169 /* Round up the usual suspects. */
1170 if (is_sun4m == -1) {
1171 if (uname(&name) < 0) {
1172 perror("upeek: uname?");
1173 exit(1);
1174 }
1175 is_sun4m = strcmp(name.machine, "sun4m") == 0;
1176 if (is_sun4m) {
Roland McGrathd9f816f2004-09-04 03:39:20 +00001177 const struct xlat *x;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001178
1179 for (x = struct_user_offsets; x->str; x++)
1180 x->val += 1024;
1181 }
1182 }
1183 if (is_sun4m)
1184 off += 1024;
1185 }
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001186# endif /* SUNOS4_KERNEL_ARCH_KLUDGE */
Roland McGratheb9e2e82009-06-02 16:49:22 -07001187 errno = 0;
Denys Vlasenko732d1bf2008-12-17 19:21:59 +00001188 val = do_ptrace(PTRACE_PEEKUSER, tcp, (char *) off, 0);
Roland McGratheb9e2e82009-06-02 16:49:22 -07001189 if (val == -1 && errno) {
1190 if (errno != ESRCH) {
1191 char buf[60];
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001192 sprintf(buf, "upeek: ptrace(PTRACE_PEEKUSER,%d,%lu,0)", tcp->pid, off);
Roland McGratheb9e2e82009-06-02 16:49:22 -07001193 perror(buf);
1194 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001195 return -1;
Roland McGratheb9e2e82009-06-02 16:49:22 -07001196 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001197 *res = val;
1198 return 0;
1199}
1200
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001201#endif /* !USE_PROCFS */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001202
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001203void
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001204printcall(struct tcb *tcp)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001205{
Roland McGrath7a918832005-02-02 20:55:23 +00001206#define PRINTBADPC tprintf(sizeof(long) == 4 ? "[????????] " : \
1207 sizeof(long) == 8 ? "[????????????????] " : \
1208 NULL /* crash */)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001209
1210#ifdef LINUX
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001211# ifdef I386
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001212 long eip;
1213
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001214 if (upeek(tcp, 4*EIP, &eip) < 0) {
Roland McGrath7a918832005-02-02 20:55:23 +00001215 PRINTBADPC;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001216 return;
1217 }
1218 tprintf("[%08lx] ", eip);
Roland McGratheac26fc2005-02-02 02:48:53 +00001219
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001220# elif defined(S390) || defined(S390X)
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001221 long psw;
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001222 if (upeek(tcp, PT_PSWADDR, &psw) < 0) {
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001223 PRINTBADPC;
1224 return;
1225 }
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001226# ifdef S390
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001227 tprintf("[%08lx] ", psw);
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001228# elif S390X
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001229 tprintf("[%16lx] ", psw);
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001230# endif
Roland McGratheac26fc2005-02-02 02:48:53 +00001231
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001232# elif defined(X86_64)
Michal Ludvig0e035502002-09-23 15:41:01 +00001233 long rip;
1234
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001235 if (upeek(tcp, 8*RIP, &rip) < 0) {
Roland McGrath7a918832005-02-02 20:55:23 +00001236 PRINTBADPC;
Michal Ludvig0e035502002-09-23 15:41:01 +00001237 return;
1238 }
1239 tprintf("[%16lx] ", rip);
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001240# elif defined(IA64)
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00001241 long ip;
1242
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001243 if (upeek(tcp, PT_B0, &ip) < 0) {
Roland McGrath7a918832005-02-02 20:55:23 +00001244 PRINTBADPC;
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00001245 return;
1246 }
1247 tprintf("[%08lx] ", ip);
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001248# elif defined(POWERPC)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001249 long pc;
1250
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001251 if (upeek(tcp, sizeof(unsigned long)*PT_NIP, &pc) < 0) {
Andreas Schwabd69fa492010-07-12 21:39:57 +02001252 PRINTBADPC;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001253 return;
1254 }
Andreas Schwabd69fa492010-07-12 21:39:57 +02001255# ifdef POWERPC64
1256 tprintf("[%016lx] ", pc);
1257# else
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001258 tprintf("[%08lx] ", pc);
Andreas Schwabd69fa492010-07-12 21:39:57 +02001259# endif
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001260# elif defined(M68K)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001261 long pc;
1262
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001263 if (upeek(tcp, 4*PT_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(ALPHA)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001269 long pc;
1270
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001271 if (upeek(tcp, REG_PC, &pc) < 0) {
Denys Vlasenko60fe8c12011-09-01 10:00:28 +02001272 tprints("[????????????????] ");
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001273 return;
1274 }
1275 tprintf("[%08lx] ", pc);
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001276# elif defined(SPARC) || defined(SPARC64)
Mike Frysinger8566c502009-10-12 11:05:14 -04001277 struct pt_regs regs;
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001278 if (ptrace(PTRACE_GETREGS, tcp->pid, (char *)&regs, 0) < 0) {
Roland McGrath7a918832005-02-02 20:55:23 +00001279 PRINTBADPC;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001280 return;
1281 }
Mike Frysinger8566c502009-10-12 11:05:14 -04001282# if defined(SPARC64)
1283 tprintf("[%08lx] ", regs.tpc);
1284# else
1285 tprintf("[%08lx] ", regs.pc);
1286# endif
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001287# elif defined(HPPA)
Wichert Akkermanc1652e22001-03-27 12:17:16 +00001288 long pc;
1289
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001290 if (upeek(tcp, PT_IAOQ0, &pc) < 0) {
Denys Vlasenko60fe8c12011-09-01 10:00:28 +02001291 tprints("[????????] ");
Wichert Akkermanc1652e22001-03-27 12:17:16 +00001292 return;
1293 }
1294 tprintf("[%08lx] ", pc);
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001295# elif defined(MIPS)
Wichert Akkerman75c422b2001-04-10 10:22:50 +00001296 long pc;
1297
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001298 if (upeek(tcp, REG_EPC, &pc) < 0) {
Denys Vlasenko60fe8c12011-09-01 10:00:28 +02001299 tprints("[????????] ");
Wichert Akkerman75c422b2001-04-10 10:22:50 +00001300 return;
1301 }
1302 tprintf("[%08lx] ", pc);
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001303# elif defined(SH)
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001304 long pc;
Wichert Akkermanccef6372002-05-01 16:39:22 +00001305
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001306 if (upeek(tcp, 4*REG_PC, &pc) < 0) {
Denys Vlasenko60fe8c12011-09-01 10:00:28 +02001307 tprints("[????????] ");
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001308 return;
1309 }
1310 tprintf("[%08lx] ", pc);
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001311# elif defined(SH64)
Roland McGrathe1e584b2003-06-02 19:18:58 +00001312 long pc;
1313
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001314 if (upeek(tcp, REG_PC, &pc) < 0) {
Denys Vlasenko60fe8c12011-09-01 10:00:28 +02001315 tprints("[????????????????] ");
Roland McGrathe1e584b2003-06-02 19:18:58 +00001316 return;
1317 }
1318 tprintf("[%08lx] ", pc);
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001319# elif defined(ARM)
Roland McGrathef388682003-06-03 23:28:59 +00001320 long pc;
Roland McGrathe1e584b2003-06-02 19:18:58 +00001321
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001322 if (upeek(tcp, 4*15, &pc) < 0) {
Roland McGrath7a918832005-02-02 20:55:23 +00001323 PRINTBADPC;
Roland McGrathef388682003-06-03 23:28:59 +00001324 return;
1325 }
1326 tprintf("[%08lx] ", pc);
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00001327# elif defined(AVR32)
1328 long pc;
1329
1330 if (upeek(tcp, REG_PC, &pc) < 0) {
Denys Vlasenko60fe8c12011-09-01 10:00:28 +02001331 tprints("[????????] ");
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00001332 return;
1333 }
1334 tprintf("[%08lx] ", pc);
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001335# elif defined(BFIN)
Dmitry V. Levin87ea1f42008-11-10 22:21:41 +00001336 long pc;
1337
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001338 if (upeek(tcp, PT_PC, &pc) < 0) {
Dmitry V. Levin87ea1f42008-11-10 22:21:41 +00001339 PRINTBADPC;
1340 return;
1341 }
1342 tprintf("[%08lx] ", pc);
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001343#elif defined(CRISV10)
1344 long pc;
1345
Edgar E. Iglesiaseeb9ce32009-10-05 14:41:02 +00001346 if (upeek(tcp, 4*PT_IRP, &pc) < 0) {
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001347 PRINTBADPC;
1348 return;
1349 }
1350 tprintf("[%08lx] ", pc);
1351#elif defined(CRISV32)
1352 long pc;
1353
Edgar E. Iglesiaseeb9ce32009-10-05 14:41:02 +00001354 if (upeek(tcp, 4*PT_ERP, &pc) < 0) {
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001355 PRINTBADPC;
1356 return;
1357 }
1358 tprintf("[%08lx] ", pc);
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001359# endif /* architecture */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001360#endif /* LINUX */
1361
1362#ifdef SUNOS4
1363 struct regs regs;
1364
Roland McGratheb9e2e82009-06-02 16:49:22 -07001365 if (ptrace(PTRACE_GETREGS, tcp->pid, (char *) &regs, 0) < 0) {
1366 perror("printcall: ptrace(PTRACE_GETREGS, ...)");
Roland McGrath7a918832005-02-02 20:55:23 +00001367 PRINTBADPC;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001368 return;
1369 }
1370 tprintf("[%08x] ", regs.r_o7);
1371#endif /* SUNOS4 */
1372
1373#ifdef SVR4
1374 /* XXX */
Roland McGrath7a918832005-02-02 20:55:23 +00001375 PRINTBADPC;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001376#endif
1377
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001378#ifdef FREEBSD
1379 struct reg regs;
1380 pread(tcp->pfd_reg, &regs, sizeof(regs), 0);
1381 tprintf("[%08x] ", regs.r_eip);
1382#endif /* FREEBSD */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001383}
1384
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001385
1386/*
1387 * These #if's are huge, please indent them correctly.
1388 * It's easy to get confused otherwise.
1389 */
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001390#ifndef USE_PROCFS
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001391
Denys Vlasenkoe7c90242011-06-22 00:09:25 +02001392# ifdef LINUX
Roland McGrathd81f1d92003-01-09 06:53:34 +00001393
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001394# include "syscall.h"
Roland McGrath3291ef22008-05-20 00:34:34 +00001395
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001396# include <sys/syscall.h>
1397# ifndef CLONE_PTRACE
1398# define CLONE_PTRACE 0x00002000
1399# endif
1400# ifndef CLONE_VFORK
1401# define CLONE_VFORK 0x00004000
1402# endif
1403# ifndef CLONE_VM
1404# define CLONE_VM 0x00000100
1405# endif
1406# ifndef CLONE_STOPPED
1407# define CLONE_STOPPED 0x02000000
1408# endif
Roland McGrathd81f1d92003-01-09 06:53:34 +00001409
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001410# ifdef IA64
Roland McGrathd81f1d92003-01-09 06:53:34 +00001411
Roland McGrath08267b82004-02-20 22:56:43 +00001412/* We don't have fork()/vfork() syscalls on ia64 itself, but the ia32
1413 subsystem has them for x86... */
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001414# define SYS_fork 2
1415# define SYS_vfork 190
Roland McGrath08267b82004-02-20 22:56:43 +00001416
Roland McGrathd81f1d92003-01-09 06:53:34 +00001417typedef unsigned long *arg_setup_state;
1418
1419static int
1420arg_setup(struct tcb *tcp, arg_setup_state *state)
1421{
Jan Kratochvil1f942712008-08-06 21:38:52 +00001422 unsigned long cfm, sof, sol;
1423 long bsp;
Roland McGrathd81f1d92003-01-09 06:53:34 +00001424
Jan Kratochvil1f942712008-08-06 21:38:52 +00001425 if (ia32) {
1426 /* Satisfy a false GCC warning. */
1427 *state = NULL;
Roland McGrath08267b82004-02-20 22:56:43 +00001428 return 0;
Jan Kratochvil1f942712008-08-06 21:38:52 +00001429 }
Roland McGrath08267b82004-02-20 22:56:43 +00001430
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001431 if (upeek(tcp, PT_AR_BSP, &bsp) < 0)
Roland McGrathd81f1d92003-01-09 06:53:34 +00001432 return -1;
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001433 if (upeek(tcp, PT_CFM, (long *) &cfm) < 0)
Roland McGrathd81f1d92003-01-09 06:53:34 +00001434 return -1;
1435
1436 sof = (cfm >> 0) & 0x7f;
1437 sol = (cfm >> 7) & 0x7f;
Jan Kratochvil1f942712008-08-06 21:38:52 +00001438 bsp = (long) ia64_rse_skip_regs((unsigned long *) bsp, -sof + sol);
Roland McGrathd81f1d92003-01-09 06:53:34 +00001439
Jan Kratochvil1f942712008-08-06 21:38:52 +00001440 *state = (unsigned long *) bsp;
Roland McGrathd81f1d92003-01-09 06:53:34 +00001441 return 0;
1442}
1443
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001444# define arg_finish_change(tcp, state) 0
Roland McGrathd81f1d92003-01-09 06:53:34 +00001445
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001446# ifdef SYS_fork
Roland McGrathd81f1d92003-01-09 06:53:34 +00001447static int
Denys Vlasenko12014262011-05-30 14:00:14 +02001448get_arg0(struct tcb *tcp, arg_setup_state *state, long *valp)
Roland McGrathd81f1d92003-01-09 06:53:34 +00001449{
Roland McGrath08267b82004-02-20 22:56:43 +00001450 int ret;
1451
1452 if (ia32)
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001453 ret = upeek(tcp, PT_R11, valp);
Roland McGrath08267b82004-02-20 22:56:43 +00001454 else
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001455 ret = umoven(tcp,
Roland McGrath08267b82004-02-20 22:56:43 +00001456 (unsigned long) ia64_rse_skip_regs(*state, 0),
1457 sizeof(long), (void *) valp);
1458 return ret;
Roland McGrathd81f1d92003-01-09 06:53:34 +00001459}
1460
1461static int
Denys Vlasenko12014262011-05-30 14:00:14 +02001462get_arg1(struct tcb *tcp, arg_setup_state *state, long *valp)
Roland McGrathd81f1d92003-01-09 06:53:34 +00001463{
Roland McGrath08267b82004-02-20 22:56:43 +00001464 int ret;
1465
1466 if (ia32)
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001467 ret = upeek(tcp, PT_R9, valp);
Roland McGrath08267b82004-02-20 22:56:43 +00001468 else
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001469 ret = umoven(tcp,
Roland McGrath08267b82004-02-20 22:56:43 +00001470 (unsigned long) ia64_rse_skip_regs(*state, 1),
1471 sizeof(long), (void *) valp);
1472 return ret;
Roland McGrathd81f1d92003-01-09 06:53:34 +00001473}
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001474# endif
Roland McGrathd81f1d92003-01-09 06:53:34 +00001475
1476static int
Denys Vlasenko12014262011-05-30 14:00:14 +02001477set_arg0(struct tcb *tcp, arg_setup_state *state, long val)
Roland McGrathd81f1d92003-01-09 06:53:34 +00001478{
Roland McGrath08267b82004-02-20 22:56:43 +00001479 int req = PTRACE_POKEDATA;
1480 void *ap;
1481
1482 if (ia32) {
1483 ap = (void *) (intptr_t) PT_R11; /* r11 == EBX */
1484 req = PTRACE_POKEUSER;
1485 } else
1486 ap = ia64_rse_skip_regs(*state, 0);
Roland McGratheb9e2e82009-06-02 16:49:22 -07001487 errno = 0;
1488 ptrace(req, tcp->pid, ap, val);
1489 return errno ? -1 : 0;
Roland McGrathd81f1d92003-01-09 06:53:34 +00001490}
1491
1492static int
Denys Vlasenko12014262011-05-30 14:00:14 +02001493set_arg1(struct tcb *tcp, arg_setup_state *state, long val)
Roland McGrathd81f1d92003-01-09 06:53:34 +00001494{
Roland McGrath08267b82004-02-20 22:56:43 +00001495 int req = PTRACE_POKEDATA;
1496 void *ap;
1497
1498 if (ia32) {
1499 ap = (void *) (intptr_t) PT_R9; /* r9 == ECX */
1500 req = PTRACE_POKEUSER;
1501 } else
1502 ap = ia64_rse_skip_regs(*state, 1);
Roland McGratheb9e2e82009-06-02 16:49:22 -07001503 errno = 0;
1504 ptrace(req, tcp->pid, ap, val);
1505 return errno ? -1 : 0;
Roland McGrathd81f1d92003-01-09 06:53:34 +00001506}
1507
Roland McGrathb659f872008-07-18 01:19:36 +00001508/* ia64 does not return the input arguments from functions (and syscalls)
1509 according to ia64 RSE (Register Stack Engine) behavior. */
1510
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001511# define restore_arg0(tcp, state, val) ((void) (state), 0)
1512# define restore_arg1(tcp, state, val) ((void) (state), 0)
Roland McGrathb659f872008-07-18 01:19:36 +00001513
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001514# elif defined (SPARC) || defined (SPARC64)
Roland McGrathd81f1d92003-01-09 06:53:34 +00001515
Mike Frysinger8566c502009-10-12 11:05:14 -04001516typedef struct pt_regs arg_setup_state;
Roland McGrathd81f1d92003-01-09 06:53:34 +00001517
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001518# define arg_setup(tcp, state) \
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001519 (ptrace(PTRACE_GETREGS, tcp->pid, (char *) (state), 0))
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001520# define arg_finish_change(tcp, state) \
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001521 (ptrace(PTRACE_SETREGS, tcp->pid, (char *) (state), 0))
Roland McGrathd81f1d92003-01-09 06:53:34 +00001522
Mike Frysinger8566c502009-10-12 11:05:14 -04001523# define get_arg0(tcp, state, valp) (*(valp) = (state)->u_regs[U_REG_O0], 0)
1524# define get_arg1(tcp, state, valp) (*(valp) = (state)->u_regs[U_REG_O1], 0)
1525# define set_arg0(tcp, state, val) ((state)->u_regs[U_REG_O0] = (val), 0)
1526# define set_arg1(tcp, state, val) ((state)->u_regs[U_REG_O1] = (val), 0)
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001527# define restore_arg0(tcp, state, val) 0
Roland McGrathd81f1d92003-01-09 06:53:34 +00001528
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001529# else /* other architectures */
Roland McGrathd81f1d92003-01-09 06:53:34 +00001530
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001531# if defined S390 || defined S390X
Roland McGrath7b308222003-01-20 09:04:36 +00001532/* Note: this is only true for the `clone' system call, which handles
1533 arguments specially. We could as well say that its first two arguments
1534 are swapped relative to other architectures, but that would just be
1535 another #ifdef in the calls. */
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001536# define arg0_offset PT_GPR3
1537# define arg1_offset PT_ORIGGPR2
1538# define restore_arg0(tcp, state, val) ((void) (state), 0)
1539# define restore_arg1(tcp, state, val) ((void) (state), 0)
1540# define arg0_index 1
1541# define arg1_index 0
1542# elif defined (ALPHA) || defined (MIPS)
1543# define arg0_offset REG_A0
1544# define arg1_offset (REG_A0+1)
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00001545# elif defined (AVR32)
1546# define arg0_offset (REG_R12)
1547# define arg1_offset (REG_R11)
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001548# elif defined (POWERPC)
1549# define arg0_offset (sizeof(unsigned long)*PT_R3)
1550# define arg1_offset (sizeof(unsigned long)*PT_R4)
1551# define restore_arg0(tcp, state, val) ((void) (state), 0)
1552# elif defined (HPPA)
1553# define arg0_offset PT_GR26
1554# define arg1_offset (PT_GR26-4)
1555# elif defined (X86_64)
1556# define arg0_offset ((long)(8*(current_personality ? RBX : RDI)))
1557# define arg1_offset ((long)(8*(current_personality ? RCX : RSI)))
1558# elif defined (SH)
1559# define arg0_offset (4*(REG_REG0+4))
1560# define arg1_offset (4*(REG_REG0+5))
1561# elif defined (SH64)
1562 /* ABI defines arg0 & 1 in r2 & r3 */
1563# define arg0_offset (REG_OFFSET+16)
1564# define arg1_offset (REG_OFFSET+24)
1565# define restore_arg0(tcp, state, val) 0
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001566# elif defined CRISV10 || defined CRISV32
1567# define arg0_offset (4*PT_R11)
1568# define arg1_offset (4*PT_ORIG_R10)
1569# define restore_arg0(tcp, state, val) 0
1570# define restore_arg1(tcp, state, val) 0
1571# define arg0_index 1
1572# define arg1_index 0
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001573# else
1574# define arg0_offset 0
1575# define arg1_offset 4
1576# if defined ARM
1577# define restore_arg0(tcp, state, val) 0
1578# endif
1579# endif
Roland McGrathd81f1d92003-01-09 06:53:34 +00001580
1581typedef int arg_setup_state;
1582
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001583# define arg_setup(tcp, state) (0)
1584# define arg_finish_change(tcp, state) 0
1585# define get_arg0(tcp, cookie, valp) \
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001586 (upeek((tcp), arg0_offset, (valp)))
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001587# define get_arg1(tcp, cookie, valp) \
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001588 (upeek((tcp), arg1_offset, (valp)))
Roland McGrathd81f1d92003-01-09 06:53:34 +00001589
1590static int
Denys Vlasenko12014262011-05-30 14:00:14 +02001591set_arg0(struct tcb *tcp, void *cookie, long val)
Roland McGrathd81f1d92003-01-09 06:53:34 +00001592{
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001593 return ptrace(PTRACE_POKEUSER, tcp->pid, (char*)arg0_offset, val);
Roland McGrathd81f1d92003-01-09 06:53:34 +00001594}
1595
1596static int
Denys Vlasenko12014262011-05-30 14:00:14 +02001597set_arg1(struct tcb *tcp, void *cookie, long val)
Roland McGrathd81f1d92003-01-09 06:53:34 +00001598{
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001599 return ptrace(PTRACE_POKEUSER, tcp->pid, (char*)arg1_offset, val);
Roland McGrathd81f1d92003-01-09 06:53:34 +00001600}
1601
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001602# endif /* architectures */
Roland McGrathd81f1d92003-01-09 06:53:34 +00001603
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001604# ifndef restore_arg0
1605# define restore_arg0(tcp, state, val) set_arg0((tcp), (state), (val))
1606# endif
1607# ifndef restore_arg1
1608# define restore_arg1(tcp, state, val) set_arg1((tcp), (state), (val))
1609# endif
Roland McGrathd81f1d92003-01-09 06:53:34 +00001610
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001611# ifndef arg0_index
1612# define arg0_index 0
1613# define arg1_index 1
1614# endif
Roland McGrath90d0afd2004-03-01 21:05:16 +00001615
Roland McGrathd81f1d92003-01-09 06:53:34 +00001616int
Denys Vlasenko418d66a2009-01-17 01:52:54 +00001617setbpt(struct tcb *tcp)
Roland McGrathd81f1d92003-01-09 06:53:34 +00001618{
Roland McGrath3291ef22008-05-20 00:34:34 +00001619 static int clone_scno[SUPPORTED_PERSONALITIES] = { SYS_clone };
Roland McGrathd81f1d92003-01-09 06:53:34 +00001620 arg_setup_state state;
1621
1622 if (tcp->flags & TCB_BPTSET) {
1623 fprintf(stderr, "PANIC: TCB already set in pid %u\n", tcp->pid);
1624 return -1;
1625 }
1626
Roland McGrath3291ef22008-05-20 00:34:34 +00001627 /*
1628 * It's a silly kludge to initialize this with a search at runtime.
1629 * But it's better than maintaining another magic thing in the
1630 * godforsaken tables.
1631 */
1632 if (clone_scno[current_personality] == 0) {
1633 int i;
1634 for (i = 0; i < nsyscalls; ++i)
1635 if (sysent[i].sys_func == sys_clone) {
1636 clone_scno[current_personality] = i;
1637 break;
1638 }
1639 }
1640
Roland McGrath76989d72005-06-07 23:21:31 +00001641 switch (known_scno(tcp)) {
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001642# ifdef SYS_vfork
Roland McGrath9383c6c2003-01-18 00:19:31 +00001643 case SYS_vfork:
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001644# endif
1645# ifdef SYS_fork
Roland McGrathd81f1d92003-01-09 06:53:34 +00001646 case SYS_fork:
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001647# endif
1648# if defined SYS_fork || defined SYS_vfork
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001649 if (arg_setup(tcp, &state) < 0
1650 || get_arg0(tcp, &state, &tcp->inst[0]) < 0
1651 || get_arg1(tcp, &state, &tcp->inst[1]) < 0
Roland McGrath3291ef22008-05-20 00:34:34 +00001652 || change_syscall(tcp, clone_scno[current_personality]) < 0
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001653 || set_arg0(tcp, &state, CLONE_PTRACE|SIGCHLD) < 0
1654 || set_arg1(tcp, &state, 0) < 0
1655 || arg_finish_change(tcp, &state) < 0)
Roland McGrathd81f1d92003-01-09 06:53:34 +00001656 return -1;
Roland McGrathc9dc3c12004-03-01 20:57:09 +00001657 tcp->u_arg[arg0_index] = CLONE_PTRACE|SIGCHLD;
1658 tcp->u_arg[arg1_index] = 0;
Roland McGrathd81f1d92003-01-09 06:53:34 +00001659 tcp->flags |= TCB_BPTSET;
1660 return 0;
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001661# endif
Roland McGrathd81f1d92003-01-09 06:53:34 +00001662
Denys Vlasenkoc133bf02011-06-23 21:57:54 +02001663 case SYS_clone: ;
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001664# ifdef SYS_clone2
Denys Vlasenkoc133bf02011-06-23 21:57:54 +02001665 case SYS_clone2: ;
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001666# endif
Jan Kratochvil8fc95752008-08-06 21:43:35 +00001667 /* ia64 calls directly `clone (CLONE_VFORK | CLONE_VM)'
1668 contrary to x86 SYS_vfork above. Even on x86 we turn the
1669 vfork semantics into plain fork - each application must not
1670 depend on the vfork specifics according to POSIX. We would
1671 hang waiting for the parent resume otherwise. We need to
1672 clear also CLONE_VM but only in the CLONE_VFORK case as
1673 otherwise we would break pthread_create. */
1674
Denys Vlasenkoc133bf02011-06-23 21:57:54 +02001675 long new_arg0 = (tcp->u_arg[arg0_index] | CLONE_PTRACE);
1676 if (new_arg0 & CLONE_VFORK)
1677 new_arg0 &= ~(unsigned long)(CLONE_VFORK | CLONE_VM);
1678 if (arg_setup(tcp, &state) < 0
1679 || set_arg0(tcp, &state, new_arg0) < 0
1680 || arg_finish_change(tcp, &state) < 0)
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00001681 return -1;
Roland McGrathd81f1d92003-01-09 06:53:34 +00001682 tcp->flags |= TCB_BPTSET;
Roland McGrathc9dc3c12004-03-01 20:57:09 +00001683 tcp->inst[0] = tcp->u_arg[arg0_index];
1684 tcp->inst[1] = tcp->u_arg[arg1_index];
Roland McGrathd81f1d92003-01-09 06:53:34 +00001685 return 0;
1686
1687 default:
1688 fprintf(stderr, "PANIC: setbpt for syscall %ld on %u???\n",
1689 tcp->scno, tcp->pid);
1690 break;
1691 }
1692
1693 return -1;
1694}
1695
1696int
Denys Vlasenko12014262011-05-30 14:00:14 +02001697clearbpt(struct tcb *tcp)
Roland McGrathd81f1d92003-01-09 06:53:34 +00001698{
1699 arg_setup_state state;
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001700 if (arg_setup(tcp, &state) < 0
1701 || restore_arg0(tcp, &state, tcp->inst[0]) < 0
1702 || restore_arg1(tcp, &state, tcp->inst[1]) < 0
1703 || arg_finish_change(tcp, &state))
Denys Vlasenkoc133bf02011-06-23 21:57:54 +02001704 if (errno != ESRCH)
1705 return -1;
Roland McGrathd81f1d92003-01-09 06:53:34 +00001706 tcp->flags &= ~TCB_BPTSET;
1707 return 0;
1708}
1709
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001710# else /* !defined LINUX */
Roland McGrathd81f1d92003-01-09 06:53:34 +00001711
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001712int
Denys Vlasenko12014262011-05-30 14:00:14 +02001713setbpt(struct tcb *tcp)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001714{
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001715# ifdef SUNOS4
1716# ifdef SPARC /* This code is slightly sparc specific */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001717
Wichert Akkermane6f876c1999-06-22 15:28:30 +00001718 struct regs regs;
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001719# define BPT 0x91d02001 /* ta 1 */
1720# define LOOP 0x10800000 /* ba 0 */
1721# define LOOPA 0x30800000 /* ba,a 0 */
1722# define NOP 0x01000000
1723# if LOOPA
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001724 static int loopdeloop[1] = {LOOPA};
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001725# else
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001726 static int loopdeloop[2] = {LOOP, NOP};
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001727# endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001728
1729 if (tcp->flags & TCB_BPTSET) {
1730 fprintf(stderr, "PANIC: TCB already set in pid %u\n", tcp->pid);
1731 return -1;
1732 }
Roland McGratheb9e2e82009-06-02 16:49:22 -07001733 if (ptrace(PTRACE_GETREGS, tcp->pid, (char *)&regs, 0) < 0) {
1734 perror("setbpt: ptrace(PTRACE_GETREGS, ...)");
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001735 return -1;
1736 }
1737 tcp->baddr = regs.r_o7 + 8;
Roland McGratheb9e2e82009-06-02 16:49:22 -07001738 if (ptrace(PTRACE_READTEXT, tcp->pid, (char *)tcp->baddr,
1739 sizeof tcp->inst, (char *)tcp->inst) < 0) {
1740 perror("setbpt: ptrace(PTRACE_READTEXT, ...)");
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001741 return -1;
1742 }
1743
1744 /*
1745 * XXX - BRUTAL MODE ON
1746 * We cannot set a real BPT in the child, since it will not be
1747 * traced at the moment it will reach the trap and would probably
1748 * die with a core dump.
1749 * Thus, we are force our way in by taking out two instructions
1750 * and insert an eternal loop in stead, in expectance of the SIGSTOP
1751 * generated by out PTRACE_ATTACH.
1752 * Of cause, if we evaporate ourselves in the middle of all this...
1753 */
Roland McGratheb9e2e82009-06-02 16:49:22 -07001754 if (ptrace(PTRACE_WRITETEXT, tcp->pid, (char *) tcp->baddr,
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001755 sizeof loopdeloop, (char *) loopdeloop) < 0) {
Roland McGratheb9e2e82009-06-02 16:49:22 -07001756 perror("setbpt: ptrace(PTRACE_WRITETEXT, ...)");
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001757 return -1;
1758 }
1759 tcp->flags |= TCB_BPTSET;
1760
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001761# endif /* SPARC */
1762# endif /* SUNOS4 */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001763
1764 return 0;
1765}
1766
1767int
Denys Vlasenko12014262011-05-30 14:00:14 +02001768clearbpt(struct tcb *tcp)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001769{
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001770# ifdef SUNOS4
1771# ifdef SPARC
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001772
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001773# if !LOOPA
Wichert Akkermane6f876c1999-06-22 15:28:30 +00001774 struct regs regs;
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001775# endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001776
1777 if (!(tcp->flags & TCB_BPTSET)) {
1778 fprintf(stderr, "PANIC: TCB not set in pid %u\n", tcp->pid);
1779 return -1;
1780 }
Roland McGratheb9e2e82009-06-02 16:49:22 -07001781 if (ptrace(PTRACE_WRITETEXT, tcp->pid, (char *) tcp->baddr,
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001782 sizeof tcp->inst, (char *) tcp->inst) < 0) {
Roland McGratheb9e2e82009-06-02 16:49:22 -07001783 perror("clearbtp: ptrace(PTRACE_WRITETEXT, ...)");
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001784 return -1;
1785 }
1786 tcp->flags &= ~TCB_BPTSET;
1787
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001788# if !LOOPA
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001789 /*
1790 * Since we don't have a single instruction breakpoint, we may have
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001791 * to adjust the program counter after removing our `breakpoint'.
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001792 */
Roland McGratheb9e2e82009-06-02 16:49:22 -07001793 if (ptrace(PTRACE_GETREGS, tcp->pid, (char *)&regs, 0) < 0) {
1794 perror("clearbpt: ptrace(PTRACE_GETREGS, ...)");
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001795 return -1;
1796 }
Roland McGratheb9e2e82009-06-02 16:49:22 -07001797 if ((regs.r_pc < tcp->baddr) ||
1798 (regs.r_pc > tcp->baddr + 4)) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001799 /* The breakpoint has not been reached yet */
1800 if (debug)
1801 fprintf(stderr,
1802 "NOTE: PC not at bpt (pc %#x baddr %#x)\n",
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001803 regs.r_pc, tcp->baddr);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001804 return 0;
1805 }
1806 if (regs.r_pc != tcp->baddr)
1807 if (debug)
1808 fprintf(stderr, "NOTE: PC adjusted (%#x -> %#x\n",
1809 regs.r_pc, tcp->baddr);
1810
1811 regs.r_pc = tcp->baddr;
Roland McGratheb9e2e82009-06-02 16:49:22 -07001812 if (ptrace(PTRACE_SETREGS, tcp->pid, (char *)&regs, 0) < 0) {
1813 perror("clearbpt: ptrace(PTRACE_SETREGS, ...)");
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001814 return -1;
1815 }
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001816# endif /* LOOPA */
1817# endif /* SPARC */
1818# endif /* SUNOS4 */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001819
1820 return 0;
1821}
1822
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001823# endif /* !defined LINUX */
Roland McGrathd81f1d92003-01-09 06:53:34 +00001824
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001825#endif /* !USE_PROCFS */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001826
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001827
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001828#ifdef SUNOS4
1829
1830static int
Denys Vlasenko12014262011-05-30 14:00:14 +02001831getex(struct tcb *tcp, struct exec *hdr)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001832{
1833 int n;
1834
1835 for (n = 0; n < sizeof *hdr; n += 4) {
1836 long res;
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001837 if (upeek(tcp, uoff(u_exdata) + n, &res) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001838 return -1;
1839 memcpy(((char *) hdr) + n, &res, 4);
1840 }
1841 if (debug) {
1842 fprintf(stderr, "[struct exec: magic: %o version %u Mach %o\n",
1843 hdr->a_magic, hdr->a_toolversion, hdr->a_machtype);
1844 fprintf(stderr, "Text %lu Data %lu Bss %lu Syms %lu Entry %#lx]\n",
1845 hdr->a_text, hdr->a_data, hdr->a_bss, hdr->a_syms, hdr->a_entry);
1846 }
1847 return 0;
1848}
1849
1850int
Denys Vlasenko12014262011-05-30 14:00:14 +02001851fixvfork(struct tcb *tcp)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001852{
1853 int pid = tcp->pid;
1854 /*
1855 * Change `vfork' in a freshly exec'ed dynamically linked
1856 * executable's (internal) symbol table to plain old `fork'
1857 */
1858
1859 struct exec hdr;
1860 struct link_dynamic dyn;
1861 struct link_dynamic_2 ld;
1862 char *strtab, *cp;
1863
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001864 if (getex(tcp, &hdr) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001865 return -1;
1866 if (!hdr.a_dynamic)
1867 return -1;
1868
1869 if (umove(tcp, (int) N_DATADDR(hdr), &dyn) < 0) {
1870 fprintf(stderr, "Cannot read DYNAMIC\n");
1871 return -1;
1872 }
1873 if (umove(tcp, (int) dyn.ld_un.ld_2, &ld) < 0) {
1874 fprintf(stderr, "Cannot read link_dynamic_2\n");
1875 return -1;
1876 }
Denys Vlasenko5d645812011-08-20 12:48:18 +02001877 strtab = malloc((unsigned)ld.ld_symb_size);
Denys Vlasenko1d46ba52011-08-31 14:00:02 +02001878 if (!strtab)
1879 die_out_of_memory();
Roland McGratheb9e2e82009-06-02 16:49:22 -07001880 if (umoven(tcp, (int)ld.ld_symbols+(int)N_TXTADDR(hdr),
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001881 (int)ld.ld_symb_size, strtab) < 0)
1882 goto err;
1883
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001884 for (cp = strtab; cp < strtab + ld.ld_symb_size; ) {
1885 if (strcmp(cp, "_vfork") == 0) {
1886 if (debug)
1887 fprintf(stderr, "fixvfork: FOUND _vfork\n");
1888 strcpy(cp, "_fork");
1889 break;
1890 }
1891 cp += strlen(cp)+1;
1892 }
1893 if (cp < strtab + ld.ld_symb_size)
1894 /*
1895 * Write entire symbol table back to avoid
1896 * memory alignment bugs in ptrace
1897 */
Roland McGratheb9e2e82009-06-02 16:49:22 -07001898 if (tload(pid, (int)ld.ld_symbols+(int)N_TXTADDR(hdr),
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001899 (int)ld.ld_symb_size, strtab) < 0)
1900 goto err;
1901
1902 free(strtab);
1903 return 0;
1904
1905err:
1906 free(strtab);
1907 return -1;
1908}
1909
1910#endif /* SUNOS4 */