blob: 2a73db78808e0c3d074e0387816dc48c1e31eae2 [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 flags &= ~xlat->val;
329 found = 1;
330 }
331 }
332 if (flags) {
333 if (found)
Denys Vlasenko52845572011-08-31 12:07:38 +0200334 *outptr++ = '|';
335 outptr += sprintf(outptr, "%#x", flags);
Roland McGratha6c0d8c2007-11-01 21:46:22 +0000336 }
337
338 return outstr;
339}
340
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000341int
Dmitry V. Levin30145dd2010-09-06 22:08:24 +0000342printflags(const struct xlat *xlat, int flags, const char *dflt)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000343{
344 int n;
Dmitry V. Levin30145dd2010-09-06 22:08:24 +0000345 const char *sep;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000346
347 if (flags == 0 && xlat->val == 0) {
Denys Vlasenko5940e652011-09-01 09:55:05 +0200348 tprints(xlat->str);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000349 return 1;
350 }
351
352 sep = "";
353 for (n = 0; xlat->str; xlat++) {
354 if (xlat->val && (flags & xlat->val) == xlat->val) {
355 tprintf("%s%s", sep, xlat->str);
356 flags &= ~xlat->val;
357 sep = "|";
358 n++;
359 }
360 }
Roland McGrathb2dee132005-06-01 19:02:36 +0000361
362 if (n) {
363 if (flags) {
364 tprintf("%s%#x", sep, flags);
365 n++;
366 }
367 } else {
368 if (flags) {
369 tprintf("%#x", flags);
370 if (dflt)
371 tprintf(" /* %s */", dflt);
372 } else {
373 if (dflt)
Denys Vlasenko60fe8c12011-09-01 10:00:28 +0200374 tprints("0");
Roland McGrathb2dee132005-06-01 19:02:36 +0000375 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000376 }
Roland McGrathb2dee132005-06-01 19:02:36 +0000377
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000378 return n;
379}
380
381void
Dmitry V. Levin30145dd2010-09-06 22:08:24 +0000382printnum(struct tcb *tcp, long addr, const char *fmt)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000383{
Roland McGratheb285352003-01-14 09:59:00 +0000384 long num;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000385
386 if (!addr) {
Denys Vlasenko60fe8c12011-09-01 10:00:28 +0200387 tprints("NULL");
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000388 return;
389 }
390 if (umove(tcp, addr, &num) < 0) {
391 tprintf("%#lx", addr);
392 return;
393 }
Denys Vlasenko60fe8c12011-09-01 10:00:28 +0200394 tprints("[");
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000395 tprintf(fmt, num);
Denys Vlasenko60fe8c12011-09-01 10:00:28 +0200396 tprints("]");
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000397}
398
Roland McGrath6bc12202003-11-13 22:32:27 +0000399void
Dmitry V. Levin30145dd2010-09-06 22:08:24 +0000400printnum_int(struct tcb *tcp, long addr, const char *fmt)
Roland McGrath9814a942005-07-04 23:28:10 +0000401{
402 int num;
403
404 if (!addr) {
Denys Vlasenko60fe8c12011-09-01 10:00:28 +0200405 tprints("NULL");
Roland McGrath9814a942005-07-04 23:28:10 +0000406 return;
407 }
408 if (umove(tcp, addr, &num) < 0) {
409 tprintf("%#lx", addr);
410 return;
411 }
Denys Vlasenko60fe8c12011-09-01 10:00:28 +0200412 tprints("[");
Roland McGrath9814a942005-07-04 23:28:10 +0000413 tprintf(fmt, num);
Denys Vlasenko60fe8c12011-09-01 10:00:28 +0200414 tprints("]");
Roland McGrath9814a942005-07-04 23:28:10 +0000415}
416
417void
Dmitry V. Levin31382132011-03-04 05:08:02 +0300418printfd(struct tcb *tcp, int fd)
419{
Grant Edwards8a082772011-04-07 20:25:40 +0000420 const char *p;
421
422 if (show_fd_path && (p = getfdpath(tcp, fd)))
423 tprintf("%d<%s>", fd, p);
424 else
425 tprintf("%d", fd);
Dmitry V. Levin31382132011-03-04 05:08:02 +0300426}
427
428void
Denys Vlasenko12014262011-05-30 14:00:14 +0200429printuid(const char *text, unsigned long uid)
Roland McGrath6bc12202003-11-13 22:32:27 +0000430{
Denys Vlasenko5940e652011-09-01 09:55:05 +0200431 tprintf((uid == -1) ? "%s%ld" : "%s%lu", text, uid);
Roland McGrath6bc12202003-11-13 22:32:27 +0000432}
433
Dmitry V. Levina501f142008-11-10 23:19:13 +0000434/*
435 * Quote string `instr' of length `size'
436 * Write up to (3 + `size' * 4) bytes to `outstr' buffer.
437 * If `len' < 0, treat `instr' as a NUL-terminated string
438 * and quote at most (`size' - 1) bytes.
Denys Vlasenko6cecba52012-01-20 11:56:00 +0100439 *
440 * Returns 0 if len < 0 and NUL was seen, 1 otherwise.
441 * Note that if len >= 0, always returns 1.
Dmitry V. Levina501f142008-11-10 23:19:13 +0000442 */
Roland McGrath6d970322007-11-01 23:53:59 +0000443static int
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000444string_quote(const char *instr, char *outstr, int len, int size)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000445{
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000446 const unsigned char *ustr = (const unsigned char *) instr;
447 char *s = outstr;
Denys Vlasenko8778bff2011-08-31 12:22:56 +0200448 int usehex, c, i, eol;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000449
Denys Vlasenko8778bff2011-08-31 12:22:56 +0200450 eol = 0x100; /* this can never match a char */
451 if (len < 0) {
452 size--;
453 eol = '\0';
454 }
455
456 usehex = 0;
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000457 if (xflag > 1)
458 usehex = 1;
459 else if (xflag) {
Dmitry V. Levina501f142008-11-10 23:19:13 +0000460 /* Check for presence of symbol which require
461 to hex-quote the whole string. */
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000462 for (i = 0; i < size; ++i) {
463 c = ustr[i];
Dmitry V. Levina501f142008-11-10 23:19:13 +0000464 /* Check for NUL-terminated string. */
Denys Vlasenko8778bff2011-08-31 12:22:56 +0200465 if (c == eol)
466 break;
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000467 if (!isprint(c) && !isspace(c)) {
468 usehex = 1;
469 break;
470 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000471 }
472 }
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000473
474 *s++ = '\"';
475
476 if (usehex) {
Dmitry V. Levina501f142008-11-10 23:19:13 +0000477 /* Hex-quote the whole string. */
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000478 for (i = 0; i < size; ++i) {
479 c = ustr[i];
Dmitry V. Levina501f142008-11-10 23:19:13 +0000480 /* Check for NUL-terminated string. */
Denys Vlasenko8778bff2011-08-31 12:22:56 +0200481 if (c == eol)
482 goto asciz_ended;
483 *s++ = '\\';
484 *s++ = 'x';
485 *s++ = "0123456789abcdef"[c >> 4];
486 *s++ = "0123456789abcdef"[c & 0xf];
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000487 }
488 } else {
489 for (i = 0; i < size; ++i) {
490 c = ustr[i];
Dmitry V. Levina501f142008-11-10 23:19:13 +0000491 /* Check for NUL-terminated string. */
Denys Vlasenko8778bff2011-08-31 12:22:56 +0200492 if (c == eol)
493 goto asciz_ended;
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000494 switch (c) {
495 case '\"': case '\\':
496 *s++ = '\\';
497 *s++ = c;
498 break;
499 case '\f':
500 *s++ = '\\';
501 *s++ = 'f';
502 break;
503 case '\n':
504 *s++ = '\\';
505 *s++ = 'n';
506 break;
507 case '\r':
508 *s++ = '\\';
509 *s++ = 'r';
510 break;
511 case '\t':
512 *s++ = '\\';
513 *s++ = 't';
514 break;
515 case '\v':
516 *s++ = '\\';
517 *s++ = 'v';
518 break;
519 default:
520 if (isprint(c))
521 *s++ = c;
Denys Vlasenko8778bff2011-08-31 12:22:56 +0200522 else {
523 /* Print \octal */
524 *s++ = '\\';
525 if (i + 1 < size
526 && ustr[i + 1] >= '0'
527 && ustr[i + 1] <= '9'
528 ) {
529 /* Print \ooo */
530 *s++ = '0' + (c >> 6);
531 *s++ = '0' + ((c >> 3) & 0x7);
532 } else {
533 /* Print \[[o]o]o */
534 if ((c >> 3) != 0) {
535 if ((c >> 6) != 0)
536 *s++ = '0' + (c >> 6);
537 *s++ = '0' + ((c >> 3) & 0x7);
538 }
539 }
540 *s++ = '0' + (c & 0x7);
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000541 }
542 break;
543 }
544 }
545 }
546
547 *s++ = '\"';
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000548 *s = '\0';
Roland McGrath6d970322007-11-01 23:53:59 +0000549
Denys Vlasenko8778bff2011-08-31 12:22:56 +0200550 /* Return zero if we printed entire ASCIZ string (didn't truncate it) */
551 if (len < 0 && ustr[i] == '\0') {
552 /* We didn't see NUL yet (otherwise we'd jump to 'asciz_ended')
553 * but next char is NUL.
554 */
555 return 0;
556 }
557
558 return 1;
559
560 asciz_ended:
561 *s++ = '\"';
562 *s = '\0';
563 /* Return zero: we printed entire ASCIZ string (didn't truncate it) */
564 return 0;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000565}
566
Dmitry V. Levina501f142008-11-10 23:19:13 +0000567/*
568 * Print path string specified by address `addr' and length `n'.
569 * If path length exceeds `n', append `...' to the output.
570 */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000571void
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000572printpathn(struct tcb *tcp, long addr, int n)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000573{
Denys Vlasenkob3c52cf2012-01-19 17:20:23 +0100574 char path[MAXPATHLEN + 1];
Denys Vlasenko6cecba52012-01-20 11:56:00 +0100575 int nul_seen;
Denys Vlasenkob3c52cf2012-01-19 17:20:23 +0100576
Dmitry V. Levina501f142008-11-10 23:19:13 +0000577 if (!addr) {
Denys Vlasenko60fe8c12011-09-01 10:00:28 +0200578 tprints("NULL");
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000579 return;
580 }
581
Denys Vlasenko6cecba52012-01-20 11:56:00 +0100582 /* Cap path length to the path buffer size */
Dmitry V. Levina501f142008-11-10 23:19:13 +0000583 if (n > sizeof path - 1)
584 n = sizeof path - 1;
Dmitry V. Levina501f142008-11-10 23:19:13 +0000585
586 /* Fetch one byte more to find out whether path length > n. */
Denys Vlasenko6cecba52012-01-20 11:56:00 +0100587 nul_seen = umovestr(tcp, addr, n + 1, path);
588 if (nul_seen < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000589 tprintf("%#lx", addr);
590 else {
Denys Vlasenkob3c52cf2012-01-19 17:20:23 +0100591 char *outstr;
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000592
Denys Vlasenko6cecba52012-01-20 11:56:00 +0100593 path[n] = '\0';
Denys Vlasenkob3c52cf2012-01-19 17:20:23 +0100594 n++;
Denys Vlasenko6cecba52012-01-20 11:56:00 +0100595 outstr = alloca(4 * n); /* 4*(n-1) + 3 for quotes and NUL */
Denys Vlasenkob3c52cf2012-01-19 17:20:23 +0100596 string_quote(path, outstr, -1, n);
597 tprints(outstr);
Denys Vlasenko6cecba52012-01-20 11:56:00 +0100598 if (!nul_seen)
Denys Vlasenkob3c52cf2012-01-19 17:20:23 +0100599 tprints("...");
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000600 }
601}
602
603void
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000604printpath(struct tcb *tcp, long addr)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000605{
Denys Vlasenkob3c52cf2012-01-19 17:20:23 +0100606 /* Size must correspond to char path[] size in printpathn */
607 printpathn(tcp, addr, MAXPATHLEN);
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000608}
609
Dmitry V. Levina501f142008-11-10 23:19:13 +0000610/*
611 * Print string specified by address `addr' and length `len'.
612 * If `len' < 0, treat the string as a NUL-terminated string.
613 * If string length exceeds `max_strlen', append `...' to the output.
614 */
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000615void
616printstr(struct tcb *tcp, long addr, int len)
617{
618 static char *str = NULL;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000619 static char *outstr;
Roland McGrath6d970322007-11-01 23:53:59 +0000620 int size;
Denys Vlasenkob3c52cf2012-01-19 17:20:23 +0100621 int ellipsis;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000622
623 if (!addr) {
Denys Vlasenko60fe8c12011-09-01 10:00:28 +0200624 tprints("NULL");
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000625 return;
626 }
Dmitry V. Levina501f142008-11-10 23:19:13 +0000627 /* Allocate static buffers if they are not allocated yet. */
Denys Vlasenko1d46ba52011-08-31 14:00:02 +0200628 if (!str) {
Dmitry V. Levina501f142008-11-10 23:19:13 +0000629 str = malloc(max_strlen + 1);
Denys Vlasenko1d46ba52011-08-31 14:00:02 +0200630 if (!str)
631 die_out_of_memory();
Denys Vlasenko6cecba52012-01-20 11:56:00 +0100632 outstr = malloc(4 * max_strlen + /*for quotes and NUL:*/ 3);
Denys Vlasenko1d46ba52011-08-31 14:00:02 +0200633 if (!outstr)
634 die_out_of_memory();
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000635 }
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000636
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000637 if (len < 0) {
Dmitry V. Levina501f142008-11-10 23:19:13 +0000638 /*
639 * Treat as a NUL-terminated string: fetch one byte more
640 * because string_quote() quotes one byte less.
641 */
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000642 size = max_strlen + 1;
643 if (umovestr(tcp, addr, size, str) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000644 tprintf("%#lx", addr);
645 return;
646 }
647 }
648 else {
Dmitry V. Levina501f142008-11-10 23:19:13 +0000649 size = MIN(len, max_strlen);
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000650 if (umoven(tcp, addr, size, str) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000651 tprintf("%#lx", addr);
652 return;
653 }
654 }
655
Denys Vlasenko6cecba52012-01-20 11:56:00 +0100656 /* If string_quote didn't see NUL and (it was supposed to be ASCIZ str
657 * or we were requested to print more than -s NUM chars)...
658 */
Denys Vlasenkob3c52cf2012-01-19 17:20:23 +0100659 ellipsis = (string_quote(str, outstr, len, size) &&
660 (len < 0 || len > max_strlen));
Roland McGratha503dcf2007-08-02 02:06:26 +0000661
Denys Vlasenkob3c52cf2012-01-19 17:20:23 +0100662 tprints(outstr);
663 if (ellipsis)
664 tprints("...");
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000665}
666
John Hughes1d08dcf2001-07-10 13:48:44 +0000667#if HAVE_SYS_UIO_H
668void
Denys Vlasenko12014262011-05-30 14:00:14 +0200669dumpiov(struct tcb *tcp, int len, long addr)
John Hughes1d08dcf2001-07-10 13:48:44 +0000670{
Dmitry V. Levin4ebb4e32006-12-13 17:08:08 +0000671#if defined(LINUX) && SUPPORTED_PERSONALITIES > 1
672 union {
673 struct { u_int32_t base; u_int32_t len; } *iov32;
674 struct { u_int64_t base; u_int64_t len; } *iov64;
675 } iovu;
676#define iov iovu.iov64
677#define sizeof_iov \
678 (personality_wordsize[current_personality] == 4 \
679 ? sizeof(*iovu.iov32) : sizeof(*iovu.iov64))
680#define iov_iov_base(i) \
681 (personality_wordsize[current_personality] == 4 \
682 ? (u_int64_t) iovu.iov32[i].base : iovu.iov64[i].base)
683#define iov_iov_len(i) \
684 (personality_wordsize[current_personality] == 4 \
685 ? (u_int64_t) iovu.iov32[i].len : iovu.iov64[i].len)
686#else
John Hughes1d08dcf2001-07-10 13:48:44 +0000687 struct iovec *iov;
Dmitry V. Levin4ebb4e32006-12-13 17:08:08 +0000688#define sizeof_iov sizeof(*iov)
689#define iov_iov_base(i) iov[i].iov_base
690#define iov_iov_len(i) iov[i].iov_len
691#endif
John Hughes1d08dcf2001-07-10 13:48:44 +0000692 int i;
Denys Vlasenko79a79ea2011-09-01 16:35:44 +0200693 unsigned size;
John Hughes1d08dcf2001-07-10 13:48:44 +0000694
Denys Vlasenko79a79ea2011-09-01 16:35:44 +0200695 size = sizeof_iov * len;
696 /* Assuming no sane program has millions of iovs */
697 if ((unsigned)len > 1024*1024 /* insane or negative size? */
Dmitry V. Levin4ebb4e32006-12-13 17:08:08 +0000698 || (iov = malloc(size)) == NULL) {
Denys Vlasenko79a79ea2011-09-01 16:35:44 +0200699 fprintf(stderr, "Out of memory\n");
700 return;
John Hughes1d08dcf2001-07-10 13:48:44 +0000701 }
Roland McGrathaa524c82005-06-01 19:22:06 +0000702 if (umoven(tcp, addr, size, (char *) iov) >= 0) {
John Hughes1d08dcf2001-07-10 13:48:44 +0000703 for (i = 0; i < len; i++) {
Denys Vlasenkoadedb512008-12-30 18:47:55 +0000704 /* include the buffer number to make it easy to
705 * match up the trace with the source */
706 tprintf(" * %lu bytes in buffer %d\n",
707 (unsigned long)iov_iov_len(i), i);
708 dumpstr(tcp, (long) iov_iov_base(i),
709 iov_iov_len(i));
710 }
John Hughes1d08dcf2001-07-10 13:48:44 +0000711 }
Denys Vlasenko79a79ea2011-09-01 16:35:44 +0200712 free(iov);
Dmitry V. Levin4ebb4e32006-12-13 17:08:08 +0000713#undef sizeof_iov
714#undef iov_iov_base
715#undef iov_iov_len
716#undef iov
John Hughes1d08dcf2001-07-10 13:48:44 +0000717}
718#endif
719
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000720void
Denys Vlasenko12014262011-05-30 14:00:14 +0200721dumpstr(struct tcb *tcp, long addr, int len)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000722{
723 static int strsize = -1;
724 static unsigned char *str;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000725 char *s;
726 int i, j;
727
728 if (strsize < len) {
Denys Vlasenko5d645812011-08-20 12:48:18 +0200729 free(str);
730 str = malloc(len);
Denys Vlasenko79a79ea2011-09-01 16:35:44 +0200731 if (!str) {
732 strsize = -1;
733 fprintf(stderr, "Out of memory\n");
734 return;
735 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000736 strsize = len;
737 }
738
739 if (umoven(tcp, addr, len, (char *) str) < 0)
740 return;
741
742 for (i = 0; i < len; i += 16) {
Denys Vlasenko1d46ba52011-08-31 14:00:02 +0200743 char outstr[80];
744
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000745 s = outstr;
746 sprintf(s, " | %05x ", i);
747 s += 9;
748 for (j = 0; j < 16; j++) {
749 if (j == 8)
750 *s++ = ' ';
751 if (i + j < len) {
752 sprintf(s, " %02x", str[i + j]);
753 s += 3;
754 }
755 else {
756 *s++ = ' '; *s++ = ' '; *s++ = ' ';
757 }
758 }
759 *s++ = ' '; *s++ = ' ';
760 for (j = 0; j < 16; j++) {
761 if (j == 8)
762 *s++ = ' ';
763 if (i + j < len) {
764 if (isprint(str[i + j]))
765 *s++ = str[i + j];
766 else
767 *s++ = '.';
768 }
769 else
770 *s++ = ' ';
771 }
772 tprintf("%s |\n", outstr);
773 }
774}
775
Denys Vlasenko3af224c2012-01-28 01:46:33 +0100776
777/* Need to do this since process_vm_readv() is not yet available in libc.
778 * When libc is be updated, only "static bool process_vm_readv_not_supported"
779 * line should remain.
780 */
781#if !defined(__NR_process_vm_readv)
782# if defined(I386)
783# define __NR_process_vm_readv 347
784# elif defined(X86_64)
785# define __NR_process_vm_readv 310
786# elif defined(POWERPC)
787# define __NR_process_vm_readv 351
788# endif
789#endif
790
791#if defined(__NR_process_vm_readv)
792static bool process_vm_readv_not_supported = 0;
793static ssize_t process_vm_readv(pid_t pid,
794 const struct iovec *lvec,
795 unsigned long liovcnt,
796 const struct iovec *rvec,
797 unsigned long riovcnt,
798 unsigned long flags)
799{
800 return syscall(__NR_process_vm_readv, (long)pid, lvec, liovcnt, rvec, riovcnt, flags);
801}
802#else
803static bool process_vm_readv_not_supported = 1;
804# define process_vm_readv(...) (errno = ENOSYS, -1)
805#endif
806/* end of hack */
807
808
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000809#define PAGMASK (~(PAGSIZ - 1))
810/*
811 * move `len' bytes of data from process `pid'
812 * at address `addr' to our space at `laddr'
813 */
814int
Denys Vlasenkoef2fbf82009-01-06 21:45:06 +0000815umoven(struct tcb *tcp, long addr, int len, char *laddr)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000816{
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000817#ifdef LINUX
Roland McGratheb9e2e82009-06-02 16:49:22 -0700818 int pid = tcp->pid;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000819 int n, m;
Denys Vlasenkoa47e6b92012-01-21 04:01:56 +0100820 int started;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000821 union {
822 long val;
823 char x[sizeof(long)];
824 } u;
825
Denys Vlasenko3af224c2012-01-28 01:46:33 +0100826 if (!process_vm_readv_not_supported) {
827 struct iovec local[1], remote[1];
828 int r;
829
830 local[0].iov_base = laddr;
831 remote[0].iov_base = (void*)addr;
832 local[0].iov_len = remote[0].iov_len = len;
833 r = process_vm_readv(pid,
834 local, 1,
835 remote, 1,
836 /*flags:*/ 0
837 );
838 if (r < 0) {
839 if (errno == ENOSYS)
840 process_vm_readv_not_supported = 1;
Denys Vlasenko29456392012-01-28 02:49:48 +0100841 else if (errno != EINVAL) /* EINVAL is seen if process is gone */
842 /* strange... */
Denys Vlasenko3af224c2012-01-28 01:46:33 +0100843 perror("process_vm_readv");
844 goto vm_readv_didnt_work;
845 }
846 return r;
847 }
848 vm_readv_didnt_work:
849
Dmitry V. Levin856c7ed2011-12-26 20:12:02 +0000850#if SUPPORTED_PERSONALITIES > 1
851 if (personality_wordsize[current_personality] < sizeof(addr))
852 addr &= (1ul << 8 * personality_wordsize[current_personality]) - 1;
853#endif
854
Denys Vlasenkoa47e6b92012-01-21 04:01:56 +0100855 started = 0;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000856 if (addr & (sizeof(long) - 1)) {
857 /* addr not a multiple of sizeof(long) */
858 n = addr - (addr & -sizeof(long)); /* residue */
859 addr &= -sizeof(long); /* residue */
Roland McGratheb9e2e82009-06-02 16:49:22 -0700860 errno = 0;
861 u.val = ptrace(PTRACE_PEEKDATA, pid, (char *) addr, 0);
862 if (errno) {
Roland McGratheb9e2e82009-06-02 16:49:22 -0700863 /* But if not started, we had a bogus address. */
864 if (addr != 0 && errno != EIO && errno != ESRCH)
865 perror("ptrace: umoven");
866 return -1;
867 }
Wichert Akkerman5daa0281999-03-15 19:49:42 +0000868 started = 1;
Denys Vlasenkoa47e6b92012-01-21 04:01:56 +0100869 m = MIN(sizeof(long) - n, len);
870 memcpy(laddr, &u.x[n], m);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000871 addr += sizeof(long), laddr += m, len -= m;
872 }
873 while (len) {
Roland McGratheb9e2e82009-06-02 16:49:22 -0700874 errno = 0;
875 u.val = ptrace(PTRACE_PEEKDATA, pid, (char *) addr, 0);
876 if (errno) {
877 if (started && (errno==EPERM || errno==EIO)) {
878 /* Ran into 'end of memory' - stupid "printpath" */
879 return 0;
880 }
881 if (addr != 0 && errno != EIO && errno != ESRCH)
882 perror("ptrace: umoven");
883 return -1;
884 }
Wichert Akkerman5daa0281999-03-15 19:49:42 +0000885 started = 1;
Denys Vlasenkoa47e6b92012-01-21 04:01:56 +0100886 m = MIN(sizeof(long), len);
887 memcpy(laddr, u.x, m);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000888 addr += sizeof(long), laddr += m, len -= m;
889 }
890#endif /* LINUX */
891
892#ifdef SUNOS4
893 int pid = tcp->pid;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000894 int n;
895
896 while (len) {
897 n = MIN(len, PAGSIZ);
898 n = MIN(n, ((addr + PAGSIZ) & PAGMASK) - addr);
Roland McGratheb9e2e82009-06-02 16:49:22 -0700899 if (ptrace(PTRACE_READDATA, pid,
900 (char *) addr, len, laddr) < 0) {
901 if (errno != ESRCH) {
902 perror("umoven: ptrace(PTRACE_READDATA, ...)");
903 abort();
904 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000905 return -1;
906 }
907 len -= n;
908 addr += n;
909 laddr += n;
910 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000911#endif /* SUNOS4 */
912
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000913#ifdef USE_PROCFS
Wichert Akkermanea78f0f1999-11-29 15:34:02 +0000914#ifdef HAVE_MP_PROCFS
John Hughesaa09c6b2001-05-15 14:53:43 +0000915 int fd = tcp->pfd_as;
Wichert Akkerman9ce1a631999-08-29 23:15:07 +0000916#else
John Hughesaa09c6b2001-05-15 14:53:43 +0000917 int fd = tcp->pfd;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000918#endif
John Hughesaa09c6b2001-05-15 14:53:43 +0000919 lseek(fd, addr, SEEK_SET);
920 if (read(fd, laddr, len) == -1)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000921 return -1;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000922#endif /* USE_PROCFS */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000923
924 return 0;
925}
926
927/*
Denys Vlasenko6cecba52012-01-20 11:56:00 +0100928 * Like `umove' but make the additional effort of looking
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000929 * for a terminating zero byte.
Denys Vlasenko6cecba52012-01-20 11:56:00 +0100930 *
931 * Returns < 0 on error, > 0 if NUL was seen,
932 * (TODO if useful: return count of bytes including NUL),
933 * else 0 if len bytes were read but no NUL byte seen.
934 *
935 * Note: there is no guarantee we won't overwrite some bytes
936 * in laddr[] _after_ terminating NUL (but, of course,
937 * we never write past laddr[len-1]).
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000938 */
939int
Denys Vlasenkoef2fbf82009-01-06 21:45:06 +0000940umovestr(struct tcb *tcp, long addr, int len, char *laddr)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000941{
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000942#ifdef USE_PROCFS
Denys Vlasenkoa47e6b92012-01-21 04:01:56 +0100943# ifdef HAVE_MP_PROCFS
John Hughesaa09c6b2001-05-15 14:53:43 +0000944 int fd = tcp->pfd_as;
Denys Vlasenkoa47e6b92012-01-21 04:01:56 +0100945# else
John Hughesaa09c6b2001-05-15 14:53:43 +0000946 int fd = tcp->pfd;
Denys Vlasenkoa47e6b92012-01-21 04:01:56 +0100947# endif
John Hughesaa09c6b2001-05-15 14:53:43 +0000948 /* Some systems (e.g. FreeBSD) can be upset if we read off the
949 end of valid memory, avoid this by trying to read up
950 to page boundaries. But we don't know what a page is (and
951 getpagesize(2) (if it exists) doesn't necessarily return
952 hardware page size). Assume all pages >= 1024 (a-historical
953 I know) */
954
Denys Vlasenkob63256e2011-06-07 12:13:24 +0200955 int page = 1024; /* How to find this? */
John Hughesaa09c6b2001-05-15 14:53:43 +0000956 int move = page - (addr & (page - 1));
957 int left = len;
958
959 lseek(fd, addr, SEEK_SET);
960
961 while (left) {
Denys Vlasenko5d645812011-08-20 12:48:18 +0200962 if (move > left)
963 move = left;
964 move = read(fd, laddr, move);
965 if (move <= 0)
John Hughesaa09c6b2001-05-15 14:53:43 +0000966 return left != len ? 0 : -1;
Denys Vlasenko5d645812011-08-20 12:48:18 +0200967 if (memchr(laddr, 0, move))
Denys Vlasenko6cecba52012-01-20 11:56:00 +0100968 return 1;
John Hughesaa09c6b2001-05-15 14:53:43 +0000969 left -= move;
970 laddr += move;
971 addr += move;
972 move = page;
973 }
Denys Vlasenkoa47e6b92012-01-21 04:01:56 +0100974 return 0;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000975#else /* !USE_PROCFS */
Denys Vlasenkoa47e6b92012-01-21 04:01:56 +0100976 int started;
Roland McGratheb9e2e82009-06-02 16:49:22 -0700977 int pid = tcp->pid;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000978 int i, n, m;
979 union {
980 long val;
981 char x[sizeof(long)];
982 } u;
983
Dmitry V. Levin856c7ed2011-12-26 20:12:02 +0000984#if SUPPORTED_PERSONALITIES > 1
985 if (personality_wordsize[current_personality] < sizeof(addr))
986 addr &= (1ul << 8 * personality_wordsize[current_personality]) - 1;
987#endif
988
Denys Vlasenko3af224c2012-01-28 01:46:33 +0100989 if (!process_vm_readv_not_supported) {
990 struct iovec local[1], remote[1];
991
992 local[0].iov_base = laddr;
993 remote[0].iov_base = (void*)addr;
994
995 while (len > 0) {
996 int end_in_page;
997 int r;
998 int chunk_len;
999
1000 /* Don't read kilobytes: most strings are short */
1001 chunk_len = len;
1002 if (chunk_len > 256)
1003 chunk_len = 256;
1004 /* Don't cross pages. I guess otherwise we can get EFAULT
1005 * and fail to notice that terminating NUL lies
1006 * in the existing (first) page.
1007 * (I hope there aren't arches with pages < 4K)
1008 */
1009 end_in_page = ((addr + chunk_len) & 4095);
1010 r = chunk_len - end_in_page;
1011 if (r > 0) /* if chunk_len > end_in_page */
1012 chunk_len = r; /* chunk_len -= end_in_page */
1013
1014 local[0].iov_len = remote[0].iov_len = chunk_len;
1015 r = process_vm_readv(pid,
1016 local, 1,
1017 remote, 1,
1018 /*flags:*/ 0
1019 );
1020 if (r < 0) {
1021 if (errno == ENOSYS)
1022 process_vm_readv_not_supported = 1;
Denys Vlasenko29456392012-01-28 02:49:48 +01001023 else if (errno != EINVAL) /* EINVAL is seen if process is gone */
1024 /* strange... */
Denys Vlasenko3af224c2012-01-28 01:46:33 +01001025 perror("process_vm_readv");
1026 goto vm_readv_didnt_work;
1027 }
1028 if (memchr(local[0].iov_base, '\0', r))
1029 return 1;
1030 local[0].iov_base += r;
1031 remote[0].iov_base += r;
1032 len -= r;
1033 }
1034 return 0;
1035 }
1036 vm_readv_didnt_work:
1037
Denys Vlasenkoa47e6b92012-01-21 04:01:56 +01001038 started = 0;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001039 if (addr & (sizeof(long) - 1)) {
1040 /* addr not a multiple of sizeof(long) */
1041 n = addr - (addr & -sizeof(long)); /* residue */
1042 addr &= -sizeof(long); /* residue */
Roland McGratheb9e2e82009-06-02 16:49:22 -07001043 errno = 0;
1044 u.val = ptrace(PTRACE_PEEKDATA, pid, (char *)addr, 0);
1045 if (errno) {
Roland McGratheb9e2e82009-06-02 16:49:22 -07001046 if (addr != 0 && errno != EIO && errno != ESRCH)
1047 perror("umovestr");
1048 return -1;
1049 }
Wichert Akkerman5daa0281999-03-15 19:49:42 +00001050 started = 1;
Denys Vlasenkoa47e6b92012-01-21 04:01:56 +01001051 m = MIN(sizeof(long) - n, len);
1052 memcpy(laddr, &u.x[n], m);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001053 while (n & (sizeof(long) - 1))
1054 if (u.x[n++] == '\0')
Denys Vlasenko6cecba52012-01-20 11:56:00 +01001055 return 1;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001056 addr += sizeof(long), laddr += m, len -= m;
1057 }
1058 while (len) {
Roland McGratheb9e2e82009-06-02 16:49:22 -07001059 errno = 0;
1060 u.val = ptrace(PTRACE_PEEKDATA, pid, (char *)addr, 0);
1061 if (errno) {
1062 if (started && (errno==EPERM || errno==EIO)) {
1063 /* Ran into 'end of memory' - stupid "printpath" */
1064 return 0;
1065 }
1066 if (addr != 0 && errno != EIO && errno != ESRCH)
1067 perror("umovestr");
1068 return -1;
1069 }
Wichert Akkerman5daa0281999-03-15 19:49:42 +00001070 started = 1;
Denys Vlasenkoa47e6b92012-01-21 04:01:56 +01001071 m = MIN(sizeof(long), len);
1072 memcpy(laddr, u.x, m);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001073 for (i = 0; i < sizeof(long); i++)
1074 if (u.x[i] == '\0')
Denys Vlasenko6cecba52012-01-20 11:56:00 +01001075 return 1;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001076 addr += sizeof(long), laddr += m, len -= m;
1077 }
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001078#endif /* !USE_PROCFS */
John Hughesaa09c6b2001-05-15 14:53:43 +00001079 return 0;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001080}
1081
1082#ifdef LINUX
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001083# if !defined (SPARC) && !defined(SPARC64)
1084# define PTRACE_WRITETEXT 101
1085# define PTRACE_WRITEDATA 102
1086# endif /* !SPARC && !SPARC64 */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001087#endif /* LINUX */
1088
1089#ifdef SUNOS4
1090
1091static int
Denys Vlasenko12014262011-05-30 14:00:14 +02001092uload(int cmd, int pid, long addr, int len, char *laddr)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001093{
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001094 int peek, poke;
1095 int n, m;
1096 union {
1097 long val;
1098 char x[sizeof(long)];
1099 } u;
1100
1101 if (cmd == PTRACE_WRITETEXT) {
1102 peek = PTRACE_PEEKTEXT;
1103 poke = PTRACE_POKETEXT;
1104 }
1105 else {
1106 peek = PTRACE_PEEKDATA;
1107 poke = PTRACE_POKEDATA;
1108 }
1109 if (addr & (sizeof(long) - 1)) {
1110 /* addr not a multiple of sizeof(long) */
1111 n = addr - (addr & -sizeof(long)); /* residue */
1112 addr &= -sizeof(long);
Roland McGratheb9e2e82009-06-02 16:49:22 -07001113 errno = 0;
1114 u.val = ptrace(peek, pid, (char *) addr, 0);
1115 if (errno) {
1116 perror("uload: POKE");
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001117 return -1;
1118 }
Denys Vlasenkoa47e6b92012-01-21 04:01:56 +01001119 m = MIN(sizeof(long) - n, len);
1120 memcpy(&u.x[n], laddr, m);
Roland McGratheb9e2e82009-06-02 16:49:22 -07001121 if (ptrace(poke, pid, (char *)addr, u.val) < 0) {
1122 perror("uload: POKE");
1123 return -1;
1124 }
1125 addr += sizeof(long), laddr += m, len -= m;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001126 }
1127 while (len) {
1128 if (len < sizeof(long))
Roland McGratheb9e2e82009-06-02 16:49:22 -07001129 u.val = ptrace(peek, pid, (char *) addr, 0);
Denys Vlasenkoa47e6b92012-01-21 04:01:56 +01001130 m = MIN(sizeof(long), len);
1131 memcpy(u.x, laddr, m);
Roland McGratheb9e2e82009-06-02 16:49:22 -07001132 if (ptrace(poke, pid, (char *) addr, u.val) < 0) {
1133 perror("uload: POKE");
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001134 return -1;
1135 }
Roland McGratheb9e2e82009-06-02 16:49:22 -07001136 addr += sizeof(long), laddr += m, len -= m;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001137 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001138 return 0;
1139}
1140
Roland McGratheb9e2e82009-06-02 16:49:22 -07001141int
Denys Vlasenko12014262011-05-30 14:00:14 +02001142tload(int pid, int addr, int len, char *laddr)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001143{
Roland McGratheb9e2e82009-06-02 16:49:22 -07001144 return uload(PTRACE_WRITETEXT, pid, addr, len, laddr);
1145}
1146
1147int
Denys Vlasenko12014262011-05-30 14:00:14 +02001148dload(int pid, int addr, int len, char *laddr)
Roland McGratheb9e2e82009-06-02 16:49:22 -07001149{
1150 return uload(PTRACE_WRITEDATA, pid, addr, len, laddr);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001151}
1152
1153#endif /* SUNOS4 */
1154
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001155#ifndef USE_PROCFS
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001156
1157int
Denys Vlasenko12014262011-05-30 14:00:14 +02001158upeek(struct tcb *tcp, long off, long *res)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001159{
1160 long val;
1161
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001162# ifdef SUNOS4_KERNEL_ARCH_KLUDGE
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001163 {
1164 static int is_sun4m = -1;
1165 struct utsname name;
1166
1167 /* Round up the usual suspects. */
1168 if (is_sun4m == -1) {
1169 if (uname(&name) < 0) {
1170 perror("upeek: uname?");
1171 exit(1);
1172 }
1173 is_sun4m = strcmp(name.machine, "sun4m") == 0;
1174 if (is_sun4m) {
Roland McGrathd9f816f2004-09-04 03:39:20 +00001175 const struct xlat *x;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001176
1177 for (x = struct_user_offsets; x->str; x++)
1178 x->val += 1024;
1179 }
1180 }
1181 if (is_sun4m)
1182 off += 1024;
1183 }
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001184# endif /* SUNOS4_KERNEL_ARCH_KLUDGE */
Roland McGratheb9e2e82009-06-02 16:49:22 -07001185 errno = 0;
Denys Vlasenko732d1bf2008-12-17 19:21:59 +00001186 val = do_ptrace(PTRACE_PEEKUSER, tcp, (char *) off, 0);
Roland McGratheb9e2e82009-06-02 16:49:22 -07001187 if (val == -1 && errno) {
1188 if (errno != ESRCH) {
1189 char buf[60];
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001190 sprintf(buf, "upeek: ptrace(PTRACE_PEEKUSER,%d,%lu,0)", tcp->pid, off);
Roland McGratheb9e2e82009-06-02 16:49:22 -07001191 perror(buf);
1192 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001193 return -1;
Roland McGratheb9e2e82009-06-02 16:49:22 -07001194 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001195 *res = val;
1196 return 0;
1197}
1198
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001199#endif /* !USE_PROCFS */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001200
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001201void
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001202printcall(struct tcb *tcp)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001203{
Roland McGrath7a918832005-02-02 20:55:23 +00001204#define PRINTBADPC tprintf(sizeof(long) == 4 ? "[????????] " : \
1205 sizeof(long) == 8 ? "[????????????????] " : \
1206 NULL /* crash */)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001207
1208#ifdef LINUX
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001209# ifdef I386
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001210 long eip;
1211
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001212 if (upeek(tcp, 4*EIP, &eip) < 0) {
Roland McGrath7a918832005-02-02 20:55:23 +00001213 PRINTBADPC;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001214 return;
1215 }
1216 tprintf("[%08lx] ", eip);
Roland McGratheac26fc2005-02-02 02:48:53 +00001217
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001218# elif defined(S390) || defined(S390X)
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001219 long psw;
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001220 if (upeek(tcp, PT_PSWADDR, &psw) < 0) {
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001221 PRINTBADPC;
1222 return;
1223 }
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001224# ifdef S390
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001225 tprintf("[%08lx] ", psw);
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001226# elif S390X
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001227 tprintf("[%16lx] ", psw);
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001228# endif
Roland McGratheac26fc2005-02-02 02:48:53 +00001229
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001230# elif defined(X86_64)
Michal Ludvig0e035502002-09-23 15:41:01 +00001231 long rip;
1232
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001233 if (upeek(tcp, 8*RIP, &rip) < 0) {
Roland McGrath7a918832005-02-02 20:55:23 +00001234 PRINTBADPC;
Michal Ludvig0e035502002-09-23 15:41:01 +00001235 return;
1236 }
1237 tprintf("[%16lx] ", rip);
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001238# elif defined(IA64)
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00001239 long ip;
1240
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001241 if (upeek(tcp, PT_B0, &ip) < 0) {
Roland McGrath7a918832005-02-02 20:55:23 +00001242 PRINTBADPC;
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00001243 return;
1244 }
1245 tprintf("[%08lx] ", ip);
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001246# elif defined(POWERPC)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001247 long pc;
1248
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001249 if (upeek(tcp, sizeof(unsigned long)*PT_NIP, &pc) < 0) {
Andreas Schwabd69fa492010-07-12 21:39:57 +02001250 PRINTBADPC;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001251 return;
1252 }
Andreas Schwabd69fa492010-07-12 21:39:57 +02001253# ifdef POWERPC64
1254 tprintf("[%016lx] ", pc);
1255# else
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001256 tprintf("[%08lx] ", pc);
Andreas Schwabd69fa492010-07-12 21:39:57 +02001257# endif
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001258# elif defined(M68K)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001259 long pc;
1260
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001261 if (upeek(tcp, 4*PT_PC, &pc) < 0) {
Denys Vlasenko60fe8c12011-09-01 10:00:28 +02001262 tprints("[????????] ");
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001263 return;
1264 }
1265 tprintf("[%08lx] ", pc);
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001266# elif defined(ALPHA)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001267 long pc;
1268
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001269 if (upeek(tcp, REG_PC, &pc) < 0) {
Denys Vlasenko60fe8c12011-09-01 10:00:28 +02001270 tprints("[????????????????] ");
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001271 return;
1272 }
1273 tprintf("[%08lx] ", pc);
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001274# elif defined(SPARC) || defined(SPARC64)
Mike Frysinger8566c502009-10-12 11:05:14 -04001275 struct pt_regs regs;
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001276 if (ptrace(PTRACE_GETREGS, tcp->pid, (char *)&regs, 0) < 0) {
Roland McGrath7a918832005-02-02 20:55:23 +00001277 PRINTBADPC;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001278 return;
1279 }
Mike Frysinger8566c502009-10-12 11:05:14 -04001280# if defined(SPARC64)
1281 tprintf("[%08lx] ", regs.tpc);
1282# else
1283 tprintf("[%08lx] ", regs.pc);
1284# endif
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001285# elif defined(HPPA)
Wichert Akkermanc1652e22001-03-27 12:17:16 +00001286 long pc;
1287
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001288 if (upeek(tcp, PT_IAOQ0, &pc) < 0) {
Denys Vlasenko60fe8c12011-09-01 10:00:28 +02001289 tprints("[????????] ");
Wichert Akkermanc1652e22001-03-27 12:17:16 +00001290 return;
1291 }
1292 tprintf("[%08lx] ", pc);
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001293# elif defined(MIPS)
Wichert Akkerman75c422b2001-04-10 10:22:50 +00001294 long pc;
1295
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001296 if (upeek(tcp, REG_EPC, &pc) < 0) {
Denys Vlasenko60fe8c12011-09-01 10:00:28 +02001297 tprints("[????????] ");
Wichert Akkerman75c422b2001-04-10 10:22:50 +00001298 return;
1299 }
1300 tprintf("[%08lx] ", pc);
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001301# elif defined(SH)
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001302 long pc;
Wichert Akkermanccef6372002-05-01 16:39:22 +00001303
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001304 if (upeek(tcp, 4*REG_PC, &pc) < 0) {
Denys Vlasenko60fe8c12011-09-01 10:00:28 +02001305 tprints("[????????] ");
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001306 return;
1307 }
1308 tprintf("[%08lx] ", pc);
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001309# elif defined(SH64)
Roland McGrathe1e584b2003-06-02 19:18:58 +00001310 long pc;
1311
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001312 if (upeek(tcp, REG_PC, &pc) < 0) {
Denys Vlasenko60fe8c12011-09-01 10:00:28 +02001313 tprints("[????????????????] ");
Roland McGrathe1e584b2003-06-02 19:18:58 +00001314 return;
1315 }
1316 tprintf("[%08lx] ", pc);
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001317# elif defined(ARM)
Roland McGrathef388682003-06-03 23:28:59 +00001318 long pc;
Roland McGrathe1e584b2003-06-02 19:18:58 +00001319
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001320 if (upeek(tcp, 4*15, &pc) < 0) {
Roland McGrath7a918832005-02-02 20:55:23 +00001321 PRINTBADPC;
Roland McGrathef388682003-06-03 23:28:59 +00001322 return;
1323 }
1324 tprintf("[%08lx] ", pc);
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00001325# elif defined(AVR32)
1326 long pc;
1327
1328 if (upeek(tcp, REG_PC, &pc) < 0) {
Denys Vlasenko60fe8c12011-09-01 10:00:28 +02001329 tprints("[????????] ");
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00001330 return;
1331 }
1332 tprintf("[%08lx] ", pc);
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001333# elif defined(BFIN)
Dmitry V. Levin87ea1f42008-11-10 22:21:41 +00001334 long pc;
1335
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001336 if (upeek(tcp, PT_PC, &pc) < 0) {
Dmitry V. Levin87ea1f42008-11-10 22:21:41 +00001337 PRINTBADPC;
1338 return;
1339 }
1340 tprintf("[%08lx] ", pc);
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001341#elif defined(CRISV10)
1342 long pc;
1343
Edgar E. Iglesiaseeb9ce32009-10-05 14:41:02 +00001344 if (upeek(tcp, 4*PT_IRP, &pc) < 0) {
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001345 PRINTBADPC;
1346 return;
1347 }
1348 tprintf("[%08lx] ", pc);
1349#elif defined(CRISV32)
1350 long pc;
1351
Edgar E. Iglesiaseeb9ce32009-10-05 14:41:02 +00001352 if (upeek(tcp, 4*PT_ERP, &pc) < 0) {
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001353 PRINTBADPC;
1354 return;
1355 }
1356 tprintf("[%08lx] ", pc);
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001357# endif /* architecture */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001358#endif /* LINUX */
1359
1360#ifdef SUNOS4
1361 struct regs regs;
1362
Roland McGratheb9e2e82009-06-02 16:49:22 -07001363 if (ptrace(PTRACE_GETREGS, tcp->pid, (char *) &regs, 0) < 0) {
1364 perror("printcall: ptrace(PTRACE_GETREGS, ...)");
Roland McGrath7a918832005-02-02 20:55:23 +00001365 PRINTBADPC;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001366 return;
1367 }
1368 tprintf("[%08x] ", regs.r_o7);
1369#endif /* SUNOS4 */
1370
1371#ifdef SVR4
1372 /* XXX */
Roland McGrath7a918832005-02-02 20:55:23 +00001373 PRINTBADPC;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001374#endif
1375
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001376#ifdef FREEBSD
1377 struct reg regs;
1378 pread(tcp->pfd_reg, &regs, sizeof(regs), 0);
1379 tprintf("[%08x] ", regs.r_eip);
1380#endif /* FREEBSD */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001381}
1382
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001383
1384/*
1385 * These #if's are huge, please indent them correctly.
1386 * It's easy to get confused otherwise.
1387 */
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001388#ifndef USE_PROCFS
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001389
Denys Vlasenkoe7c90242011-06-22 00:09:25 +02001390# ifdef LINUX
Roland McGrathd81f1d92003-01-09 06:53:34 +00001391
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001392# include "syscall.h"
Roland McGrath3291ef22008-05-20 00:34:34 +00001393
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001394# include <sys/syscall.h>
1395# ifndef CLONE_PTRACE
1396# define CLONE_PTRACE 0x00002000
1397# endif
1398# ifndef CLONE_VFORK
1399# define CLONE_VFORK 0x00004000
1400# endif
1401# ifndef CLONE_VM
1402# define CLONE_VM 0x00000100
1403# endif
1404# ifndef CLONE_STOPPED
1405# define CLONE_STOPPED 0x02000000
1406# endif
Roland McGrathd81f1d92003-01-09 06:53:34 +00001407
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001408# ifdef IA64
Roland McGrathd81f1d92003-01-09 06:53:34 +00001409
Roland McGrath08267b82004-02-20 22:56:43 +00001410/* We don't have fork()/vfork() syscalls on ia64 itself, but the ia32
1411 subsystem has them for x86... */
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001412# define SYS_fork 2
1413# define SYS_vfork 190
Roland McGrath08267b82004-02-20 22:56:43 +00001414
Roland McGrathd81f1d92003-01-09 06:53:34 +00001415typedef unsigned long *arg_setup_state;
1416
1417static int
1418arg_setup(struct tcb *tcp, arg_setup_state *state)
1419{
Jan Kratochvil1f942712008-08-06 21:38:52 +00001420 unsigned long cfm, sof, sol;
1421 long bsp;
Roland McGrathd81f1d92003-01-09 06:53:34 +00001422
Jan Kratochvil1f942712008-08-06 21:38:52 +00001423 if (ia32) {
1424 /* Satisfy a false GCC warning. */
1425 *state = NULL;
Roland McGrath08267b82004-02-20 22:56:43 +00001426 return 0;
Jan Kratochvil1f942712008-08-06 21:38:52 +00001427 }
Roland McGrath08267b82004-02-20 22:56:43 +00001428
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001429 if (upeek(tcp, PT_AR_BSP, &bsp) < 0)
Roland McGrathd81f1d92003-01-09 06:53:34 +00001430 return -1;
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001431 if (upeek(tcp, PT_CFM, (long *) &cfm) < 0)
Roland McGrathd81f1d92003-01-09 06:53:34 +00001432 return -1;
1433
1434 sof = (cfm >> 0) & 0x7f;
1435 sol = (cfm >> 7) & 0x7f;
Jan Kratochvil1f942712008-08-06 21:38:52 +00001436 bsp = (long) ia64_rse_skip_regs((unsigned long *) bsp, -sof + sol);
Roland McGrathd81f1d92003-01-09 06:53:34 +00001437
Jan Kratochvil1f942712008-08-06 21:38:52 +00001438 *state = (unsigned long *) bsp;
Roland McGrathd81f1d92003-01-09 06:53:34 +00001439 return 0;
1440}
1441
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001442# define arg_finish_change(tcp, state) 0
Roland McGrathd81f1d92003-01-09 06:53:34 +00001443
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001444# ifdef SYS_fork
Roland McGrathd81f1d92003-01-09 06:53:34 +00001445static int
Denys Vlasenko12014262011-05-30 14:00:14 +02001446get_arg0(struct tcb *tcp, arg_setup_state *state, long *valp)
Roland McGrathd81f1d92003-01-09 06:53:34 +00001447{
Roland McGrath08267b82004-02-20 22:56:43 +00001448 int ret;
1449
1450 if (ia32)
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001451 ret = upeek(tcp, PT_R11, valp);
Roland McGrath08267b82004-02-20 22:56:43 +00001452 else
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001453 ret = umoven(tcp,
Roland McGrath08267b82004-02-20 22:56:43 +00001454 (unsigned long) ia64_rse_skip_regs(*state, 0),
1455 sizeof(long), (void *) valp);
1456 return ret;
Roland McGrathd81f1d92003-01-09 06:53:34 +00001457}
1458
1459static int
Denys Vlasenko12014262011-05-30 14:00:14 +02001460get_arg1(struct tcb *tcp, arg_setup_state *state, long *valp)
Roland McGrathd81f1d92003-01-09 06:53:34 +00001461{
Roland McGrath08267b82004-02-20 22:56:43 +00001462 int ret;
1463
1464 if (ia32)
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001465 ret = upeek(tcp, PT_R9, valp);
Roland McGrath08267b82004-02-20 22:56:43 +00001466 else
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001467 ret = umoven(tcp,
Roland McGrath08267b82004-02-20 22:56:43 +00001468 (unsigned long) ia64_rse_skip_regs(*state, 1),
1469 sizeof(long), (void *) valp);
1470 return ret;
Roland McGrathd81f1d92003-01-09 06:53:34 +00001471}
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001472# endif
Roland McGrathd81f1d92003-01-09 06:53:34 +00001473
1474static int
Denys Vlasenko12014262011-05-30 14:00:14 +02001475set_arg0(struct tcb *tcp, arg_setup_state *state, long val)
Roland McGrathd81f1d92003-01-09 06:53:34 +00001476{
Roland McGrath08267b82004-02-20 22:56:43 +00001477 int req = PTRACE_POKEDATA;
1478 void *ap;
1479
1480 if (ia32) {
1481 ap = (void *) (intptr_t) PT_R11; /* r11 == EBX */
1482 req = PTRACE_POKEUSER;
1483 } else
1484 ap = ia64_rse_skip_regs(*state, 0);
Roland McGratheb9e2e82009-06-02 16:49:22 -07001485 errno = 0;
1486 ptrace(req, tcp->pid, ap, val);
1487 return errno ? -1 : 0;
Roland McGrathd81f1d92003-01-09 06:53:34 +00001488}
1489
1490static int
Denys Vlasenko12014262011-05-30 14:00:14 +02001491set_arg1(struct tcb *tcp, arg_setup_state *state, long val)
Roland McGrathd81f1d92003-01-09 06:53:34 +00001492{
Roland McGrath08267b82004-02-20 22:56:43 +00001493 int req = PTRACE_POKEDATA;
1494 void *ap;
1495
1496 if (ia32) {
1497 ap = (void *) (intptr_t) PT_R9; /* r9 == ECX */
1498 req = PTRACE_POKEUSER;
1499 } else
1500 ap = ia64_rse_skip_regs(*state, 1);
Roland McGratheb9e2e82009-06-02 16:49:22 -07001501 errno = 0;
1502 ptrace(req, tcp->pid, ap, val);
1503 return errno ? -1 : 0;
Roland McGrathd81f1d92003-01-09 06:53:34 +00001504}
1505
Roland McGrathb659f872008-07-18 01:19:36 +00001506/* ia64 does not return the input arguments from functions (and syscalls)
1507 according to ia64 RSE (Register Stack Engine) behavior. */
1508
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001509# define restore_arg0(tcp, state, val) ((void) (state), 0)
1510# define restore_arg1(tcp, state, val) ((void) (state), 0)
Roland McGrathb659f872008-07-18 01:19:36 +00001511
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001512# elif defined (SPARC) || defined (SPARC64)
Roland McGrathd81f1d92003-01-09 06:53:34 +00001513
Mike Frysinger8566c502009-10-12 11:05:14 -04001514typedef struct pt_regs arg_setup_state;
Roland McGrathd81f1d92003-01-09 06:53:34 +00001515
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001516# define arg_setup(tcp, state) \
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001517 (ptrace(PTRACE_GETREGS, tcp->pid, (char *) (state), 0))
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001518# define arg_finish_change(tcp, state) \
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001519 (ptrace(PTRACE_SETREGS, tcp->pid, (char *) (state), 0))
Roland McGrathd81f1d92003-01-09 06:53:34 +00001520
Mike Frysinger8566c502009-10-12 11:05:14 -04001521# define get_arg0(tcp, state, valp) (*(valp) = (state)->u_regs[U_REG_O0], 0)
1522# define get_arg1(tcp, state, valp) (*(valp) = (state)->u_regs[U_REG_O1], 0)
1523# define set_arg0(tcp, state, val) ((state)->u_regs[U_REG_O0] = (val), 0)
1524# define set_arg1(tcp, state, val) ((state)->u_regs[U_REG_O1] = (val), 0)
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001525# define restore_arg0(tcp, state, val) 0
Roland McGrathd81f1d92003-01-09 06:53:34 +00001526
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001527# else /* other architectures */
Roland McGrathd81f1d92003-01-09 06:53:34 +00001528
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001529# if defined S390 || defined S390X
Roland McGrath7b308222003-01-20 09:04:36 +00001530/* Note: this is only true for the `clone' system call, which handles
1531 arguments specially. We could as well say that its first two arguments
1532 are swapped relative to other architectures, but that would just be
1533 another #ifdef in the calls. */
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001534# define arg0_offset PT_GPR3
1535# define arg1_offset PT_ORIGGPR2
1536# define restore_arg0(tcp, state, val) ((void) (state), 0)
1537# define restore_arg1(tcp, state, val) ((void) (state), 0)
1538# define arg0_index 1
1539# define arg1_index 0
1540# elif defined (ALPHA) || defined (MIPS)
1541# define arg0_offset REG_A0
1542# define arg1_offset (REG_A0+1)
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00001543# elif defined (AVR32)
1544# define arg0_offset (REG_R12)
1545# define arg1_offset (REG_R11)
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001546# elif defined (POWERPC)
1547# define arg0_offset (sizeof(unsigned long)*PT_R3)
1548# define arg1_offset (sizeof(unsigned long)*PT_R4)
1549# define restore_arg0(tcp, state, val) ((void) (state), 0)
1550# elif defined (HPPA)
1551# define arg0_offset PT_GR26
1552# define arg1_offset (PT_GR26-4)
1553# elif defined (X86_64)
1554# define arg0_offset ((long)(8*(current_personality ? RBX : RDI)))
1555# define arg1_offset ((long)(8*(current_personality ? RCX : RSI)))
1556# elif defined (SH)
1557# define arg0_offset (4*(REG_REG0+4))
1558# define arg1_offset (4*(REG_REG0+5))
1559# elif defined (SH64)
1560 /* ABI defines arg0 & 1 in r2 & r3 */
1561# define arg0_offset (REG_OFFSET+16)
1562# define arg1_offset (REG_OFFSET+24)
1563# define restore_arg0(tcp, state, val) 0
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001564# elif defined CRISV10 || defined CRISV32
1565# define arg0_offset (4*PT_R11)
1566# define arg1_offset (4*PT_ORIG_R10)
1567# define restore_arg0(tcp, state, val) 0
1568# define restore_arg1(tcp, state, val) 0
1569# define arg0_index 1
1570# define arg1_index 0
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001571# else
1572# define arg0_offset 0
1573# define arg1_offset 4
1574# if defined ARM
1575# define restore_arg0(tcp, state, val) 0
1576# endif
1577# endif
Roland McGrathd81f1d92003-01-09 06:53:34 +00001578
1579typedef int arg_setup_state;
1580
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001581# define arg_setup(tcp, state) (0)
1582# define arg_finish_change(tcp, state) 0
1583# define get_arg0(tcp, cookie, valp) \
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001584 (upeek((tcp), arg0_offset, (valp)))
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001585# define get_arg1(tcp, cookie, valp) \
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001586 (upeek((tcp), arg1_offset, (valp)))
Roland McGrathd81f1d92003-01-09 06:53:34 +00001587
1588static int
Denys Vlasenko12014262011-05-30 14:00:14 +02001589set_arg0(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*)arg0_offset, val);
Roland McGrathd81f1d92003-01-09 06:53:34 +00001592}
1593
1594static int
Denys Vlasenko12014262011-05-30 14:00:14 +02001595set_arg1(struct tcb *tcp, void *cookie, long val)
Roland McGrathd81f1d92003-01-09 06:53:34 +00001596{
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001597 return ptrace(PTRACE_POKEUSER, tcp->pid, (char*)arg1_offset, val);
Roland McGrathd81f1d92003-01-09 06:53:34 +00001598}
1599
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001600# endif /* architectures */
Roland McGrathd81f1d92003-01-09 06:53:34 +00001601
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001602# ifndef restore_arg0
1603# define restore_arg0(tcp, state, val) set_arg0((tcp), (state), (val))
1604# endif
1605# ifndef restore_arg1
1606# define restore_arg1(tcp, state, val) set_arg1((tcp), (state), (val))
1607# endif
Roland McGrathd81f1d92003-01-09 06:53:34 +00001608
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001609# ifndef arg0_index
1610# define arg0_index 0
1611# define arg1_index 1
1612# endif
Roland McGrath90d0afd2004-03-01 21:05:16 +00001613
Roland McGrathd81f1d92003-01-09 06:53:34 +00001614int
Denys Vlasenko418d66a2009-01-17 01:52:54 +00001615setbpt(struct tcb *tcp)
Roland McGrathd81f1d92003-01-09 06:53:34 +00001616{
Roland McGrath3291ef22008-05-20 00:34:34 +00001617 static int clone_scno[SUPPORTED_PERSONALITIES] = { SYS_clone };
Roland McGrathd81f1d92003-01-09 06:53:34 +00001618 arg_setup_state state;
1619
1620 if (tcp->flags & TCB_BPTSET) {
1621 fprintf(stderr, "PANIC: TCB already set in pid %u\n", tcp->pid);
1622 return -1;
1623 }
1624
Roland McGrath3291ef22008-05-20 00:34:34 +00001625 /*
1626 * It's a silly kludge to initialize this with a search at runtime.
1627 * But it's better than maintaining another magic thing in the
1628 * godforsaken tables.
1629 */
1630 if (clone_scno[current_personality] == 0) {
1631 int i;
1632 for (i = 0; i < nsyscalls; ++i)
1633 if (sysent[i].sys_func == sys_clone) {
1634 clone_scno[current_personality] = i;
1635 break;
1636 }
1637 }
1638
Roland McGrath76989d72005-06-07 23:21:31 +00001639 switch (known_scno(tcp)) {
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001640# ifdef SYS_vfork
Roland McGrath9383c6c2003-01-18 00:19:31 +00001641 case SYS_vfork:
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001642# endif
1643# ifdef SYS_fork
Roland McGrathd81f1d92003-01-09 06:53:34 +00001644 case SYS_fork:
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001645# endif
1646# if defined SYS_fork || defined SYS_vfork
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001647 if (arg_setup(tcp, &state) < 0
1648 || get_arg0(tcp, &state, &tcp->inst[0]) < 0
1649 || get_arg1(tcp, &state, &tcp->inst[1]) < 0
Roland McGrath3291ef22008-05-20 00:34:34 +00001650 || change_syscall(tcp, clone_scno[current_personality]) < 0
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001651 || set_arg0(tcp, &state, CLONE_PTRACE|SIGCHLD) < 0
1652 || set_arg1(tcp, &state, 0) < 0
1653 || arg_finish_change(tcp, &state) < 0)
Roland McGrathd81f1d92003-01-09 06:53:34 +00001654 return -1;
Roland McGrathc9dc3c12004-03-01 20:57:09 +00001655 tcp->u_arg[arg0_index] = CLONE_PTRACE|SIGCHLD;
1656 tcp->u_arg[arg1_index] = 0;
Roland McGrathd81f1d92003-01-09 06:53:34 +00001657 tcp->flags |= TCB_BPTSET;
1658 return 0;
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001659# endif
Roland McGrathd81f1d92003-01-09 06:53:34 +00001660
Denys Vlasenkoc133bf02011-06-23 21:57:54 +02001661 case SYS_clone: ;
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001662# ifdef SYS_clone2
Denys Vlasenkoc133bf02011-06-23 21:57:54 +02001663 case SYS_clone2: ;
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001664# endif
Jan Kratochvil8fc95752008-08-06 21:43:35 +00001665 /* ia64 calls directly `clone (CLONE_VFORK | CLONE_VM)'
1666 contrary to x86 SYS_vfork above. Even on x86 we turn the
1667 vfork semantics into plain fork - each application must not
1668 depend on the vfork specifics according to POSIX. We would
1669 hang waiting for the parent resume otherwise. We need to
1670 clear also CLONE_VM but only in the CLONE_VFORK case as
1671 otherwise we would break pthread_create. */
1672
Denys Vlasenkoc133bf02011-06-23 21:57:54 +02001673 long new_arg0 = (tcp->u_arg[arg0_index] | CLONE_PTRACE);
1674 if (new_arg0 & CLONE_VFORK)
1675 new_arg0 &= ~(unsigned long)(CLONE_VFORK | CLONE_VM);
1676 if (arg_setup(tcp, &state) < 0
1677 || set_arg0(tcp, &state, new_arg0) < 0
1678 || arg_finish_change(tcp, &state) < 0)
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00001679 return -1;
Roland McGrathd81f1d92003-01-09 06:53:34 +00001680 tcp->flags |= TCB_BPTSET;
Roland McGrathc9dc3c12004-03-01 20:57:09 +00001681 tcp->inst[0] = tcp->u_arg[arg0_index];
1682 tcp->inst[1] = tcp->u_arg[arg1_index];
Roland McGrathd81f1d92003-01-09 06:53:34 +00001683 return 0;
1684
1685 default:
1686 fprintf(stderr, "PANIC: setbpt for syscall %ld on %u???\n",
1687 tcp->scno, tcp->pid);
1688 break;
1689 }
1690
1691 return -1;
1692}
1693
1694int
Denys Vlasenko12014262011-05-30 14:00:14 +02001695clearbpt(struct tcb *tcp)
Roland McGrathd81f1d92003-01-09 06:53:34 +00001696{
1697 arg_setup_state state;
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001698 if (arg_setup(tcp, &state) < 0
1699 || restore_arg0(tcp, &state, tcp->inst[0]) < 0
1700 || restore_arg1(tcp, &state, tcp->inst[1]) < 0
1701 || arg_finish_change(tcp, &state))
Denys Vlasenkoc133bf02011-06-23 21:57:54 +02001702 if (errno != ESRCH)
1703 return -1;
Roland McGrathd81f1d92003-01-09 06:53:34 +00001704 tcp->flags &= ~TCB_BPTSET;
1705 return 0;
1706}
1707
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001708# else /* !defined LINUX */
Roland McGrathd81f1d92003-01-09 06:53:34 +00001709
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001710int
Denys Vlasenko12014262011-05-30 14:00:14 +02001711setbpt(struct tcb *tcp)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001712{
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001713# ifdef SUNOS4
1714# ifdef SPARC /* This code is slightly sparc specific */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001715
Wichert Akkermane6f876c1999-06-22 15:28:30 +00001716 struct regs regs;
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001717# define BPT 0x91d02001 /* ta 1 */
1718# define LOOP 0x10800000 /* ba 0 */
1719# define LOOPA 0x30800000 /* ba,a 0 */
1720# define NOP 0x01000000
1721# if LOOPA
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001722 static int loopdeloop[1] = {LOOPA};
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001723# else
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001724 static int loopdeloop[2] = {LOOP, NOP};
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001725# endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001726
1727 if (tcp->flags & TCB_BPTSET) {
1728 fprintf(stderr, "PANIC: TCB already set in pid %u\n", tcp->pid);
1729 return -1;
1730 }
Roland McGratheb9e2e82009-06-02 16:49:22 -07001731 if (ptrace(PTRACE_GETREGS, tcp->pid, (char *)&regs, 0) < 0) {
1732 perror("setbpt: ptrace(PTRACE_GETREGS, ...)");
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001733 return -1;
1734 }
1735 tcp->baddr = regs.r_o7 + 8;
Roland McGratheb9e2e82009-06-02 16:49:22 -07001736 if (ptrace(PTRACE_READTEXT, tcp->pid, (char *)tcp->baddr,
1737 sizeof tcp->inst, (char *)tcp->inst) < 0) {
1738 perror("setbpt: ptrace(PTRACE_READTEXT, ...)");
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001739 return -1;
1740 }
1741
1742 /*
1743 * XXX - BRUTAL MODE ON
1744 * We cannot set a real BPT in the child, since it will not be
1745 * traced at the moment it will reach the trap and would probably
1746 * die with a core dump.
1747 * Thus, we are force our way in by taking out two instructions
1748 * and insert an eternal loop in stead, in expectance of the SIGSTOP
1749 * generated by out PTRACE_ATTACH.
1750 * Of cause, if we evaporate ourselves in the middle of all this...
1751 */
Roland McGratheb9e2e82009-06-02 16:49:22 -07001752 if (ptrace(PTRACE_WRITETEXT, tcp->pid, (char *) tcp->baddr,
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001753 sizeof loopdeloop, (char *) loopdeloop) < 0) {
Roland McGratheb9e2e82009-06-02 16:49:22 -07001754 perror("setbpt: ptrace(PTRACE_WRITETEXT, ...)");
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001755 return -1;
1756 }
1757 tcp->flags |= TCB_BPTSET;
1758
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001759# endif /* SPARC */
1760# endif /* SUNOS4 */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001761
1762 return 0;
1763}
1764
1765int
Denys Vlasenko12014262011-05-30 14:00:14 +02001766clearbpt(struct tcb *tcp)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001767{
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001768# ifdef SUNOS4
1769# ifdef SPARC
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001770
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001771# if !LOOPA
Wichert Akkermane6f876c1999-06-22 15:28:30 +00001772 struct regs regs;
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001773# endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001774
1775 if (!(tcp->flags & TCB_BPTSET)) {
1776 fprintf(stderr, "PANIC: TCB not set in pid %u\n", tcp->pid);
1777 return -1;
1778 }
Roland McGratheb9e2e82009-06-02 16:49:22 -07001779 if (ptrace(PTRACE_WRITETEXT, tcp->pid, (char *) tcp->baddr,
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001780 sizeof tcp->inst, (char *) tcp->inst) < 0) {
Roland McGratheb9e2e82009-06-02 16:49:22 -07001781 perror("clearbtp: ptrace(PTRACE_WRITETEXT, ...)");
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001782 return -1;
1783 }
1784 tcp->flags &= ~TCB_BPTSET;
1785
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001786# if !LOOPA
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001787 /*
1788 * Since we don't have a single instruction breakpoint, we may have
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001789 * to adjust the program counter after removing our `breakpoint'.
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001790 */
Roland McGratheb9e2e82009-06-02 16:49:22 -07001791 if (ptrace(PTRACE_GETREGS, tcp->pid, (char *)&regs, 0) < 0) {
1792 perror("clearbpt: ptrace(PTRACE_GETREGS, ...)");
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001793 return -1;
1794 }
Roland McGratheb9e2e82009-06-02 16:49:22 -07001795 if ((regs.r_pc < tcp->baddr) ||
1796 (regs.r_pc > tcp->baddr + 4)) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001797 /* The breakpoint has not been reached yet */
1798 if (debug)
1799 fprintf(stderr,
1800 "NOTE: PC not at bpt (pc %#x baddr %#x)\n",
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001801 regs.r_pc, tcp->baddr);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001802 return 0;
1803 }
1804 if (regs.r_pc != tcp->baddr)
1805 if (debug)
1806 fprintf(stderr, "NOTE: PC adjusted (%#x -> %#x\n",
1807 regs.r_pc, tcp->baddr);
1808
1809 regs.r_pc = tcp->baddr;
Roland McGratheb9e2e82009-06-02 16:49:22 -07001810 if (ptrace(PTRACE_SETREGS, tcp->pid, (char *)&regs, 0) < 0) {
1811 perror("clearbpt: ptrace(PTRACE_SETREGS, ...)");
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001812 return -1;
1813 }
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001814# endif /* LOOPA */
1815# endif /* SPARC */
1816# endif /* SUNOS4 */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001817
1818 return 0;
1819}
1820
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001821# endif /* !defined LINUX */
Roland McGrathd81f1d92003-01-09 06:53:34 +00001822
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001823#endif /* !USE_PROCFS */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001824
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001825
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001826#ifdef SUNOS4
1827
1828static int
Denys Vlasenko12014262011-05-30 14:00:14 +02001829getex(struct tcb *tcp, struct exec *hdr)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001830{
1831 int n;
1832
1833 for (n = 0; n < sizeof *hdr; n += 4) {
1834 long res;
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001835 if (upeek(tcp, uoff(u_exdata) + n, &res) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001836 return -1;
1837 memcpy(((char *) hdr) + n, &res, 4);
1838 }
1839 if (debug) {
1840 fprintf(stderr, "[struct exec: magic: %o version %u Mach %o\n",
1841 hdr->a_magic, hdr->a_toolversion, hdr->a_machtype);
1842 fprintf(stderr, "Text %lu Data %lu Bss %lu Syms %lu Entry %#lx]\n",
1843 hdr->a_text, hdr->a_data, hdr->a_bss, hdr->a_syms, hdr->a_entry);
1844 }
1845 return 0;
1846}
1847
1848int
Denys Vlasenko12014262011-05-30 14:00:14 +02001849fixvfork(struct tcb *tcp)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001850{
1851 int pid = tcp->pid;
1852 /*
1853 * Change `vfork' in a freshly exec'ed dynamically linked
1854 * executable's (internal) symbol table to plain old `fork'
1855 */
1856
1857 struct exec hdr;
1858 struct link_dynamic dyn;
1859 struct link_dynamic_2 ld;
1860 char *strtab, *cp;
1861
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001862 if (getex(tcp, &hdr) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001863 return -1;
1864 if (!hdr.a_dynamic)
1865 return -1;
1866
1867 if (umove(tcp, (int) N_DATADDR(hdr), &dyn) < 0) {
1868 fprintf(stderr, "Cannot read DYNAMIC\n");
1869 return -1;
1870 }
1871 if (umove(tcp, (int) dyn.ld_un.ld_2, &ld) < 0) {
1872 fprintf(stderr, "Cannot read link_dynamic_2\n");
1873 return -1;
1874 }
Denys Vlasenko5d645812011-08-20 12:48:18 +02001875 strtab = malloc((unsigned)ld.ld_symb_size);
Denys Vlasenko1d46ba52011-08-31 14:00:02 +02001876 if (!strtab)
1877 die_out_of_memory();
Roland McGratheb9e2e82009-06-02 16:49:22 -07001878 if (umoven(tcp, (int)ld.ld_symbols+(int)N_TXTADDR(hdr),
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001879 (int)ld.ld_symb_size, strtab) < 0)
1880 goto err;
1881
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001882 for (cp = strtab; cp < strtab + ld.ld_symb_size; ) {
1883 if (strcmp(cp, "_vfork") == 0) {
1884 if (debug)
1885 fprintf(stderr, "fixvfork: FOUND _vfork\n");
1886 strcpy(cp, "_fork");
1887 break;
1888 }
1889 cp += strlen(cp)+1;
1890 }
1891 if (cp < strtab + ld.ld_symb_size)
1892 /*
1893 * Write entire symbol table back to avoid
1894 * memory alignment bugs in ptrace
1895 */
Roland McGratheb9e2e82009-06-02 16:49:22 -07001896 if (tload(pid, (int)ld.ld_symbols+(int)N_TXTADDR(hdr),
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001897 (int)ld.ld_symb_size, strtab) < 0)
1898 goto err;
1899
1900 free(strtab);
1901 return 0;
1902
1903err:
1904 free(strtab);
1905 return -1;
1906}
1907
1908#endif /* SUNOS4 */