blob: c28edf3be538de233a2c21b5c2268f7bb09987fa [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
97tv_nz(a)
98struct timeval *a;
99{
100 return a->tv_sec || a->tv_usec;
101}
102
103int
104tv_cmp(a, b)
105struct timeval *a, *b;
106{
107 if (a->tv_sec < b->tv_sec
108 || (a->tv_sec == b->tv_sec && a->tv_usec < b->tv_usec))
109 return -1;
110 if (a->tv_sec > b->tv_sec
111 || (a->tv_sec == b->tv_sec && a->tv_usec > b->tv_usec))
112 return 1;
113 return 0;
114}
115
116double
117tv_float(tv)
118struct timeval *tv;
119{
120 return tv->tv_sec + tv->tv_usec/1000000.0;
121}
122
123void
124tv_add(tv, a, b)
125struct timeval *tv, *a, *b;
126{
127 tv->tv_sec = a->tv_sec + b->tv_sec;
128 tv->tv_usec = a->tv_usec + b->tv_usec;
Roland McGrath58372f52007-07-24 01:38:22 +0000129 if (tv->tv_usec >= 1000000) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000130 tv->tv_sec++;
131 tv->tv_usec -= 1000000;
132 }
133}
134
135void
136tv_sub(tv, a, b)
137struct timeval *tv, *a, *b;
138{
139 tv->tv_sec = a->tv_sec - b->tv_sec;
140 tv->tv_usec = a->tv_usec - b->tv_usec;
141 if (((long) tv->tv_usec) < 0) {
142 tv->tv_sec--;
143 tv->tv_usec += 1000000;
144 }
145}
146
147void
148tv_div(tv, a, n)
149struct timeval *tv, *a;
150int n;
151{
152 tv->tv_usec = (a->tv_sec % n * 1000000 + a->tv_usec + n / 2) / n;
153 tv->tv_sec = a->tv_sec / n + tv->tv_usec / 1000000;
154 tv->tv_usec %= 1000000;
155}
156
157void
158tv_mul(tv, a, n)
159struct timeval *tv, *a;
160int n;
161{
162 tv->tv_usec = a->tv_usec * n;
Dmitry V. Levinfefdd972007-06-29 21:25:56 +0000163 tv->tv_sec = a->tv_sec * n + tv->tv_usec / 1000000;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000164 tv->tv_usec %= 1000000;
165}
166
Dmitry V. Levinab9008b2007-01-11 22:05:04 +0000167const char *
168xlookup(const struct xlat *xlat, int val)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000169{
170 for (; xlat->str != NULL; xlat++)
171 if (xlat->val == val)
172 return xlat->str;
173 return NULL;
174}
175
176/*
Roland McGratheb9e2e82009-06-02 16:49:22 -0700177 * Generic ptrace wrapper which tracks ESRCH errors
178 * by setting tcp->ptrace_errno to ESRCH.
Denys Vlasenko732d1bf2008-12-17 19:21:59 +0000179 *
180 * We assume that ESRCH indicates likely process death (SIGKILL?),
181 * modulo bugs where process somehow ended up not stopped.
182 * Unfortunately kernel uses ESRCH for that case too. Oh well.
Roland McGratheb9e2e82009-06-02 16:49:22 -0700183 *
184 * Currently used by upeek() only.
185 * TODO: use this in all other ptrace() calls while decoding.
Denys Vlasenko732d1bf2008-12-17 19:21:59 +0000186 */
Denys Vlasenko4dedd562009-02-24 15:17:53 +0000187long
Roland McGratheb9e2e82009-06-02 16:49:22 -0700188do_ptrace(int request, struct tcb *tcp, void *addr, void *data)
Denys Vlasenko4dedd562009-02-24 15:17:53 +0000189{
Denys Vlasenko732d1bf2008-12-17 19:21:59 +0000190 long l;
191
192 errno = 0;
Mike Frysinger09a13c22009-10-07 01:13:39 -0400193 l = ptrace(request, tcp->pid, addr, (long) data);
Roland McGratheb9e2e82009-06-02 16:49:22 -0700194 /* Non-ESRCH errors might be our invalid reg/mem accesses,
195 * we do not record them. */
196 if (errno == ESRCH)
197 tcp->ptrace_errno = ESRCH;
Denys Vlasenko732d1bf2008-12-17 19:21:59 +0000198 return l;
199}
200
201/*
202 * Used when we want to unblock stopped traced process.
203 * Should be only used with PTRACE_CONT, PTRACE_DETACH and PTRACE_SYSCALL.
204 * Returns 0 on success or if error was ESRCH
205 * (presumably process was killed while we talk to it).
206 * Otherwise prints error message and returns -1.
207 */
208int
Roland McGratheb9e2e82009-06-02 16:49:22 -0700209ptrace_restart(int op, struct tcb *tcp, int sig)
Denys Vlasenko732d1bf2008-12-17 19:21:59 +0000210{
211 int err;
Roland McGratheb9e2e82009-06-02 16:49:22 -0700212 const char *msg;
Denys Vlasenko732d1bf2008-12-17 19:21:59 +0000213
214 errno = 0;
Mike Frysinger09a13c22009-10-07 01:13:39 -0400215 ptrace(op, tcp->pid, (void *) 1, (long) sig);
Denys Vlasenko732d1bf2008-12-17 19:21:59 +0000216 err = errno;
217 if (!err || err == ESRCH)
218 return 0;
219
220 tcp->ptrace_errno = err;
Roland McGratheb9e2e82009-06-02 16:49:22 -0700221 msg = "SYSCALL";
222 if (op == PTRACE_CONT)
223 msg = "CONT";
224 if (op == PTRACE_DETACH)
225 msg = "DETACH";
226 fprintf(stderr, "strace: ptrace(PTRACE_%s,1,%d): %s\n",
227 msg, sig, strerror(err));
Denys Vlasenko732d1bf2008-12-17 19:21:59 +0000228 return -1;
229}
230
231/*
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000232 * Print entry in struct xlat table, if there.
233 */
234void
Dmitry V. Levinab9008b2007-01-11 22:05:04 +0000235printxval(const struct xlat *xlat, int val, const char *dflt)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000236{
Dmitry V. Levinab9008b2007-01-11 22:05:04 +0000237 const char *str = xlookup(xlat, val);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000238
239 if (str)
240 tprintf("%s", str);
241 else
242 tprintf("%#x /* %s */", val, dflt);
243}
244
Andreas Schwabb5600fc2009-11-04 17:08:34 +0100245#if HAVE_LONG_LONG
246/*
247 * Print 64bit argument at position llarg and return the index of the next
248 * argument.
249 */
250int
251printllval(struct tcb *tcp, const char *format, int llarg)
252{
253# if defined(FREEBSD) \
Andreas Schwabd69fa492010-07-12 21:39:57 +0200254 || (defined(LINUX) && defined(POWERPC) && !defined(POWERPC64)) \
Andreas Schwabb5600fc2009-11-04 17:08:34 +0100255 || defined (LINUX_MIPSO32)
256 /* Align 64bit argument to 64bit boundary. */
257 if (llarg % 2) llarg++;
258# endif
Andreas Schwabd69fa492010-07-12 21:39:57 +0200259# if defined LINUX && (defined X86_64 || defined POWERPC64)
Andreas Schwabb5600fc2009-11-04 17:08:34 +0100260 if (current_personality == 0) {
261 tprintf(format, tcp->u_arg[llarg]);
262 llarg++;
263 } else {
Andreas Schwabd69fa492010-07-12 21:39:57 +0200264# ifdef POWERPC64
265 /* Align 64bit argument to 64bit boundary. */
266 if (llarg % 2) llarg++;
267# endif
Andreas Schwabb5600fc2009-11-04 17:08:34 +0100268 tprintf(format, LONG_LONG(tcp->u_arg[llarg], tcp->u_arg[llarg + 1]));
269 llarg += 2;
270 }
Andreas Schwabd69fa492010-07-12 21:39:57 +0200271# elif defined IA64 || defined ALPHA
Andreas Schwabb5600fc2009-11-04 17:08:34 +0100272 tprintf(format, tcp->u_arg[llarg]);
273 llarg++;
274# elif defined LINUX_MIPSN32
275 tprintf(format, tcp->ext_arg[llarg]);
276 llarg++;
277# else
278 tprintf(format, LONG_LONG(tcp->u_arg[llarg], tcp->u_arg[llarg + 1]));
279 llarg += 2;
280# endif
281 return llarg;
282}
283#endif
284
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000285/*
286 * Interpret `xlat' as an array of flags
287 * print the entries whose bits are on in `flags'
288 * return # of flags printed.
289 */
290int
291addflags(xlat, flags)
Roland McGrathd9f816f2004-09-04 03:39:20 +0000292const struct xlat *xlat;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000293int flags;
294{
295 int n;
296
297 for (n = 0; xlat->str; xlat++) {
298 if (xlat->val && (flags & xlat->val) == xlat->val) {
299 tprintf("|%s", xlat->str);
300 flags &= ~xlat->val;
301 n++;
302 }
303 }
304 if (flags) {
305 tprintf("|%#x", flags);
306 n++;
307 }
308 return n;
309}
310
Roland McGratha6c0d8c2007-11-01 21:46:22 +0000311/*
312 * Interpret `xlat' as an array of flags/
313 * Print to static string the entries whose bits are on in `flags'
314 * Return static string.
315 */
316const char *
317sprintflags(const char *prefix, const struct xlat *xlat, int flags)
318{
319 static char outstr[1024];
320 int found = 0;
321
322 strcpy(outstr, prefix);
323
324 for (; xlat->str; xlat++) {
325 if ((flags & xlat->val) == xlat->val) {
326 if (found)
327 strcat(outstr, "|");
328 strcat(outstr, xlat->str);
329 flags &= ~xlat->val;
330 found = 1;
331 }
332 }
333 if (flags) {
334 if (found)
335 strcat(outstr, "|");
336 sprintf(outstr + strlen(outstr), "%#x", flags);
337 }
338
339 return outstr;
340}
341
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000342int
Dmitry V. Levin30145dd2010-09-06 22:08:24 +0000343printflags(const struct xlat *xlat, int flags, const char *dflt)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000344{
345 int n;
Dmitry V. Levin30145dd2010-09-06 22:08:24 +0000346 const char *sep;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000347
348 if (flags == 0 && xlat->val == 0) {
349 tprintf("%s", xlat->str);
350 return 1;
351 }
352
353 sep = "";
354 for (n = 0; xlat->str; xlat++) {
355 if (xlat->val && (flags & xlat->val) == xlat->val) {
356 tprintf("%s%s", sep, xlat->str);
357 flags &= ~xlat->val;
358 sep = "|";
359 n++;
360 }
361 }
Roland McGrathb2dee132005-06-01 19:02:36 +0000362
363 if (n) {
364 if (flags) {
365 tprintf("%s%#x", sep, flags);
366 n++;
367 }
368 } else {
369 if (flags) {
370 tprintf("%#x", flags);
371 if (dflt)
372 tprintf(" /* %s */", dflt);
373 } else {
374 if (dflt)
375 tprintf("0");
376 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000377 }
Roland McGrathb2dee132005-06-01 19:02:36 +0000378
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000379 return n;
380}
381
382void
Dmitry V. Levin30145dd2010-09-06 22:08:24 +0000383printnum(struct tcb *tcp, long addr, const char *fmt)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000384{
Roland McGratheb285352003-01-14 09:59:00 +0000385 long num;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000386
387 if (!addr) {
388 tprintf("NULL");
389 return;
390 }
391 if (umove(tcp, addr, &num) < 0) {
392 tprintf("%#lx", addr);
393 return;
394 }
395 tprintf("[");
396 tprintf(fmt, num);
397 tprintf("]");
398}
399
Roland McGrath6bc12202003-11-13 22:32:27 +0000400void
Dmitry V. Levin30145dd2010-09-06 22:08:24 +0000401printnum_int(struct tcb *tcp, long addr, const char *fmt)
Roland McGrath9814a942005-07-04 23:28:10 +0000402{
403 int num;
404
405 if (!addr) {
406 tprintf("NULL");
407 return;
408 }
409 if (umove(tcp, addr, &num) < 0) {
410 tprintf("%#lx", addr);
411 return;
412 }
413 tprintf("[");
414 tprintf(fmt, num);
415 tprintf("]");
416}
417
418void
Roland McGrath6bc12202003-11-13 22:32:27 +0000419printuid(text, uid)
420const char *text;
421unsigned long uid;
422{
423 tprintf("%s", text);
424 tprintf((uid == -1) ? "%ld" : "%lu", uid);
425}
426
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000427static char path[MAXPATHLEN + 1];
428
Dmitry V. Levina501f142008-11-10 23:19:13 +0000429/*
430 * Quote string `instr' of length `size'
431 * Write up to (3 + `size' * 4) bytes to `outstr' buffer.
432 * If `len' < 0, treat `instr' as a NUL-terminated string
433 * and quote at most (`size' - 1) bytes.
434 */
Roland McGrath6d970322007-11-01 23:53:59 +0000435static int
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000436string_quote(const char *instr, char *outstr, int len, int size)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000437{
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000438 const unsigned char *ustr = (const unsigned char *) instr;
439 char *s = outstr;
440 int usehex = 0, c, i;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000441
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000442 if (xflag > 1)
443 usehex = 1;
444 else if (xflag) {
Dmitry V. Levina501f142008-11-10 23:19:13 +0000445 /* Check for presence of symbol which require
446 to hex-quote the whole string. */
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000447 for (i = 0; i < size; ++i) {
448 c = ustr[i];
Dmitry V. Levina501f142008-11-10 23:19:13 +0000449 /* Check for NUL-terminated string. */
450 if (len < 0) {
451 if (c == '\0')
452 break;
453 /* Quote at most size - 1 bytes. */
454 if (i == size - 1)
455 continue;
456 }
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000457 if (!isprint(c) && !isspace(c)) {
458 usehex = 1;
459 break;
460 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000461 }
462 }
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000463
464 *s++ = '\"';
465
466 if (usehex) {
Dmitry V. Levina501f142008-11-10 23:19:13 +0000467 /* Hex-quote the whole string. */
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000468 for (i = 0; i < size; ++i) {
469 c = ustr[i];
Dmitry V. Levina501f142008-11-10 23:19:13 +0000470 /* Check for NUL-terminated string. */
471 if (len < 0) {
472 if (c == '\0')
473 break;
474 /* Quote at most size - 1 bytes. */
475 if (i == size - 1)
476 continue;
477 }
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000478 sprintf(s, "\\x%02x", c);
479 s += 4;
480 }
481 } else {
482 for (i = 0; i < size; ++i) {
483 c = ustr[i];
Dmitry V. Levina501f142008-11-10 23:19:13 +0000484 /* Check for NUL-terminated string. */
485 if (len < 0) {
486 if (c == '\0')
487 break;
488 /* Quote at most size - 1 bytes. */
489 if (i == size - 1)
490 continue;
491 }
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000492 switch (c) {
493 case '\"': case '\\':
494 *s++ = '\\';
495 *s++ = c;
496 break;
497 case '\f':
498 *s++ = '\\';
499 *s++ = 'f';
500 break;
501 case '\n':
502 *s++ = '\\';
503 *s++ = 'n';
504 break;
505 case '\r':
506 *s++ = '\\';
507 *s++ = 'r';
508 break;
509 case '\t':
510 *s++ = '\\';
511 *s++ = 't';
512 break;
513 case '\v':
514 *s++ = '\\';
515 *s++ = 'v';
516 break;
517 default:
518 if (isprint(c))
519 *s++ = c;
520 else if (i + 1 < size
521 && isdigit(ustr[i + 1])) {
522 sprintf(s, "\\%03o", c);
523 s += 4;
524 } else {
525 sprintf(s, "\\%o", c);
526 s += strlen(s);
527 }
528 break;
529 }
530 }
531 }
532
533 *s++ = '\"';
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000534 *s = '\0';
Roland McGrath6d970322007-11-01 23:53:59 +0000535
536 /* Return nonzero if the string was unterminated. */
537 return i == size;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000538}
539
Dmitry V. Levina501f142008-11-10 23:19:13 +0000540/*
541 * Print path string specified by address `addr' and length `n'.
542 * If path length exceeds `n', append `...' to the output.
543 */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000544void
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000545printpathn(struct tcb *tcp, long addr, int n)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000546{
Dmitry V. Levina501f142008-11-10 23:19:13 +0000547 if (!addr) {
Roland McGrath371ed8f2005-02-06 01:55:07 +0000548 tprintf("NULL");
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000549 return;
550 }
551
Dmitry V. Levina501f142008-11-10 23:19:13 +0000552 /* Cap path length to the path buffer size,
553 and NUL-terminate the buffer. */
554 if (n > sizeof path - 1)
555 n = sizeof path - 1;
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000556 path[n] = '\0';
Dmitry V. Levina501f142008-11-10 23:19:13 +0000557
558 /* Fetch one byte more to find out whether path length > n. */
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000559 if (umovestr(tcp, addr, n + 1, path) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000560 tprintf("%#lx", addr);
561 else {
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000562 static char outstr[4*(sizeof path - 1) + sizeof "\"...\""];
563 int trunc = (path[n] != '\0');
564
565 if (trunc)
566 path[n] = '\0';
Dmitry V. Levina501f142008-11-10 23:19:13 +0000567 (void) string_quote(path, outstr, -1, n + 1);
568 if (trunc)
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000569 strcat(outstr, "...");
570 tprintf("%s", outstr);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000571 }
572}
573
574void
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000575printpath(struct tcb *tcp, long addr)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000576{
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000577 printpathn(tcp, addr, sizeof path - 1);
578}
579
Dmitry V. Levina501f142008-11-10 23:19:13 +0000580/*
581 * Print string specified by address `addr' and length `len'.
582 * If `len' < 0, treat the string as a NUL-terminated string.
583 * If string length exceeds `max_strlen', append `...' to the output.
584 */
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000585void
586printstr(struct tcb *tcp, long addr, int len)
587{
588 static char *str = NULL;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000589 static char *outstr;
Roland McGrath6d970322007-11-01 23:53:59 +0000590 int size;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000591
592 if (!addr) {
593 tprintf("NULL");
594 return;
595 }
Dmitry V. Levina501f142008-11-10 23:19:13 +0000596 /* Allocate static buffers if they are not allocated yet. */
597 if (!str)
598 str = malloc(max_strlen + 1);
599 if (!outstr)
600 outstr = malloc(4 * max_strlen + sizeof "\"...\"");
601 if (!str || !outstr) {
602 fprintf(stderr, "out of memory\n");
603 tprintf("%#lx", addr);
604 return;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000605 }
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000606
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000607 if (len < 0) {
Dmitry V. Levina501f142008-11-10 23:19:13 +0000608 /*
609 * Treat as a NUL-terminated string: fetch one byte more
610 * because string_quote() quotes one byte less.
611 */
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000612 size = max_strlen + 1;
Dmitry V. Levina501f142008-11-10 23:19:13 +0000613 str[max_strlen] = '\0';
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000614 if (umovestr(tcp, addr, size, str) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000615 tprintf("%#lx", addr);
616 return;
617 }
618 }
619 else {
Dmitry V. Levina501f142008-11-10 23:19:13 +0000620 size = MIN(len, max_strlen);
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000621 if (umoven(tcp, addr, size, str) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000622 tprintf("%#lx", addr);
623 return;
624 }
625 }
626
Dmitry V. Levina501f142008-11-10 23:19:13 +0000627 if (string_quote(str, outstr, len, size) &&
628 (len < 0 || len > max_strlen))
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000629 strcat(outstr, "...");
Roland McGratha503dcf2007-08-02 02:06:26 +0000630
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000631 tprintf("%s", outstr);
632}
633
John Hughes1d08dcf2001-07-10 13:48:44 +0000634#if HAVE_SYS_UIO_H
635void
636dumpiov(tcp, len, addr)
637struct tcb * tcp;
638int len;
639long addr;
640{
Dmitry V. Levin4ebb4e32006-12-13 17:08:08 +0000641#if defined(LINUX) && SUPPORTED_PERSONALITIES > 1
642 union {
643 struct { u_int32_t base; u_int32_t len; } *iov32;
644 struct { u_int64_t base; u_int64_t len; } *iov64;
645 } iovu;
646#define iov iovu.iov64
647#define sizeof_iov \
648 (personality_wordsize[current_personality] == 4 \
649 ? sizeof(*iovu.iov32) : sizeof(*iovu.iov64))
650#define iov_iov_base(i) \
651 (personality_wordsize[current_personality] == 4 \
652 ? (u_int64_t) iovu.iov32[i].base : iovu.iov64[i].base)
653#define iov_iov_len(i) \
654 (personality_wordsize[current_personality] == 4 \
655 ? (u_int64_t) iovu.iov32[i].len : iovu.iov64[i].len)
656#else
John Hughes1d08dcf2001-07-10 13:48:44 +0000657 struct iovec *iov;
Dmitry V. Levin4ebb4e32006-12-13 17:08:08 +0000658#define sizeof_iov sizeof(*iov)
659#define iov_iov_base(i) iov[i].iov_base
660#define iov_iov_len(i) iov[i].iov_len
661#endif
John Hughes1d08dcf2001-07-10 13:48:44 +0000662 int i;
Roland McGrathaa524c82005-06-01 19:22:06 +0000663 unsigned long size;
John Hughes1d08dcf2001-07-10 13:48:44 +0000664
Dmitry V. Levin4ebb4e32006-12-13 17:08:08 +0000665 size = sizeof_iov * (unsigned long) len;
666 if (size / sizeof_iov != len
667 || (iov = malloc(size)) == NULL) {
Roland McGrathaa524c82005-06-01 19:22:06 +0000668 fprintf(stderr, "out of memory\n");
John Hughes1d08dcf2001-07-10 13:48:44 +0000669 return;
670 }
Roland McGrathaa524c82005-06-01 19:22:06 +0000671 if (umoven(tcp, addr, size, (char *) iov) >= 0) {
John Hughes1d08dcf2001-07-10 13:48:44 +0000672 for (i = 0; i < len; i++) {
Denys Vlasenkoadedb512008-12-30 18:47:55 +0000673 /* include the buffer number to make it easy to
674 * match up the trace with the source */
675 tprintf(" * %lu bytes in buffer %d\n",
676 (unsigned long)iov_iov_len(i), i);
677 dumpstr(tcp, (long) iov_iov_base(i),
678 iov_iov_len(i));
679 }
John Hughes1d08dcf2001-07-10 13:48:44 +0000680 }
681 free((char *) iov);
Dmitry V. Levin4ebb4e32006-12-13 17:08:08 +0000682#undef sizeof_iov
683#undef iov_iov_base
684#undef iov_iov_len
685#undef iov
John Hughes1d08dcf2001-07-10 13:48:44 +0000686}
687#endif
688
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000689void
690dumpstr(tcp, addr, len)
691struct tcb *tcp;
692long addr;
693int len;
694{
695 static int strsize = -1;
696 static unsigned char *str;
697 static char outstr[80];
698 char *s;
699 int i, j;
700
701 if (strsize < len) {
702 if (str)
703 free(str);
704 if ((str = malloc(len)) == NULL) {
Roland McGrath46100d02005-06-01 18:55:42 +0000705 fprintf(stderr, "out of memory\n");
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000706 return;
707 }
708 strsize = len;
709 }
710
711 if (umoven(tcp, addr, len, (char *) str) < 0)
712 return;
713
714 for (i = 0; i < len; i += 16) {
715 s = outstr;
716 sprintf(s, " | %05x ", i);
717 s += 9;
718 for (j = 0; j < 16; j++) {
719 if (j == 8)
720 *s++ = ' ';
721 if (i + j < len) {
722 sprintf(s, " %02x", str[i + j]);
723 s += 3;
724 }
725 else {
726 *s++ = ' '; *s++ = ' '; *s++ = ' ';
727 }
728 }
729 *s++ = ' '; *s++ = ' ';
730 for (j = 0; j < 16; j++) {
731 if (j == 8)
732 *s++ = ' ';
733 if (i + j < len) {
734 if (isprint(str[i + j]))
735 *s++ = str[i + j];
736 else
737 *s++ = '.';
738 }
739 else
740 *s++ = ' ';
741 }
742 tprintf("%s |\n", outstr);
743 }
744}
745
746#define PAGMASK (~(PAGSIZ - 1))
747/*
748 * move `len' bytes of data from process `pid'
749 * at address `addr' to our space at `laddr'
750 */
751int
Denys Vlasenkoef2fbf82009-01-06 21:45:06 +0000752umoven(struct tcb *tcp, long addr, int len, char *laddr)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000753{
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000754#ifdef LINUX
Roland McGratheb9e2e82009-06-02 16:49:22 -0700755 int pid = tcp->pid;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000756 int n, m;
Wichert Akkerman5daa0281999-03-15 19:49:42 +0000757 int started = 0;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000758 union {
759 long val;
760 char x[sizeof(long)];
761 } u;
762
763 if (addr & (sizeof(long) - 1)) {
764 /* addr not a multiple of sizeof(long) */
765 n = addr - (addr & -sizeof(long)); /* residue */
766 addr &= -sizeof(long); /* residue */
Roland McGratheb9e2e82009-06-02 16:49:22 -0700767 errno = 0;
768 u.val = ptrace(PTRACE_PEEKDATA, pid, (char *) addr, 0);
769 if (errno) {
770 if (started && (errno==EPERM || errno==EIO)) {
771 /* Ran into 'end of memory' - stupid "printpath" */
772 return 0;
773 }
774 /* But if not started, we had a bogus address. */
775 if (addr != 0 && errno != EIO && errno != ESRCH)
776 perror("ptrace: umoven");
777 return -1;
778 }
Wichert Akkerman5daa0281999-03-15 19:49:42 +0000779 started = 1;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000780 memcpy(laddr, &u.x[n], m = MIN(sizeof(long) - n, len));
781 addr += sizeof(long), laddr += m, len -= m;
782 }
783 while (len) {
Roland McGratheb9e2e82009-06-02 16:49:22 -0700784 errno = 0;
785 u.val = ptrace(PTRACE_PEEKDATA, pid, (char *) addr, 0);
786 if (errno) {
787 if (started && (errno==EPERM || errno==EIO)) {
788 /* Ran into 'end of memory' - stupid "printpath" */
789 return 0;
790 }
791 if (addr != 0 && errno != EIO && errno != ESRCH)
792 perror("ptrace: umoven");
793 return -1;
794 }
Wichert Akkerman5daa0281999-03-15 19:49:42 +0000795 started = 1;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000796 memcpy(laddr, u.x, m = MIN(sizeof(long), len));
797 addr += sizeof(long), laddr += m, len -= m;
798 }
799#endif /* LINUX */
800
801#ifdef SUNOS4
802 int pid = tcp->pid;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000803 int n;
804
805 while (len) {
806 n = MIN(len, PAGSIZ);
807 n = MIN(n, ((addr + PAGSIZ) & PAGMASK) - addr);
Roland McGratheb9e2e82009-06-02 16:49:22 -0700808 if (ptrace(PTRACE_READDATA, pid,
809 (char *) addr, len, laddr) < 0) {
810 if (errno != ESRCH) {
811 perror("umoven: ptrace(PTRACE_READDATA, ...)");
812 abort();
813 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000814 return -1;
815 }
816 len -= n;
817 addr += n;
818 laddr += n;
819 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000820#endif /* SUNOS4 */
821
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000822#ifdef USE_PROCFS
Wichert Akkermanea78f0f1999-11-29 15:34:02 +0000823#ifdef HAVE_MP_PROCFS
John Hughesaa09c6b2001-05-15 14:53:43 +0000824 int fd = tcp->pfd_as;
Wichert Akkerman9ce1a631999-08-29 23:15:07 +0000825#else
John Hughesaa09c6b2001-05-15 14:53:43 +0000826 int fd = tcp->pfd;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000827#endif
John Hughesaa09c6b2001-05-15 14:53:43 +0000828 lseek(fd, addr, SEEK_SET);
829 if (read(fd, laddr, len) == -1)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000830 return -1;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000831#endif /* USE_PROCFS */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000832
833 return 0;
834}
835
836/*
837 * like `umove' but make the additional effort of looking
838 * for a terminating zero byte.
839 */
840int
Denys Vlasenkoef2fbf82009-01-06 21:45:06 +0000841umovestr(struct tcb *tcp, long addr, int len, char *laddr)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000842{
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000843#ifdef USE_PROCFS
John Hughesaa09c6b2001-05-15 14:53:43 +0000844#ifdef HAVE_MP_PROCFS
845 int fd = tcp->pfd_as;
846#else
847 int fd = tcp->pfd;
848#endif
849 /* Some systems (e.g. FreeBSD) can be upset if we read off the
850 end of valid memory, avoid this by trying to read up
851 to page boundaries. But we don't know what a page is (and
852 getpagesize(2) (if it exists) doesn't necessarily return
853 hardware page size). Assume all pages >= 1024 (a-historical
854 I know) */
855
856 int page = 1024; /* How to find this? */
857 int move = page - (addr & (page - 1));
858 int left = len;
859
860 lseek(fd, addr, SEEK_SET);
861
862 while (left) {
863 if (move > left) move = left;
John Hughes9cecf7f2001-10-16 10:20:22 +0000864 if ((move = read(fd, laddr, move)) <= 0)
John Hughesaa09c6b2001-05-15 14:53:43 +0000865 return left != len ? 0 : -1;
866 if (memchr (laddr, 0, move)) break;
867 left -= move;
868 laddr += move;
869 addr += move;
870 move = page;
871 }
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000872#else /* !USE_PROCFS */
Wichert Akkerman5daa0281999-03-15 19:49:42 +0000873 int started = 0;
Roland McGratheb9e2e82009-06-02 16:49:22 -0700874 int pid = tcp->pid;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000875 int i, n, m;
876 union {
877 long val;
878 char x[sizeof(long)];
879 } u;
880
881 if (addr & (sizeof(long) - 1)) {
882 /* addr not a multiple of sizeof(long) */
883 n = addr - (addr & -sizeof(long)); /* residue */
884 addr &= -sizeof(long); /* residue */
Roland McGratheb9e2e82009-06-02 16:49:22 -0700885 errno = 0;
886 u.val = ptrace(PTRACE_PEEKDATA, pid, (char *)addr, 0);
887 if (errno) {
888 if (started && (errno==EPERM || errno==EIO)) {
889 /* Ran into 'end of memory' - stupid "printpath" */
890 return 0;
891 }
892 if (addr != 0 && errno != EIO && errno != ESRCH)
893 perror("umovestr");
894 return -1;
895 }
Wichert Akkerman5daa0281999-03-15 19:49:42 +0000896 started = 1;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000897 memcpy(laddr, &u.x[n], m = MIN(sizeof(long)-n,len));
898 while (n & (sizeof(long) - 1))
899 if (u.x[n++] == '\0')
900 return 0;
901 addr += sizeof(long), laddr += m, len -= m;
902 }
903 while (len) {
Roland McGratheb9e2e82009-06-02 16:49:22 -0700904 errno = 0;
905 u.val = ptrace(PTRACE_PEEKDATA, pid, (char *)addr, 0);
906 if (errno) {
907 if (started && (errno==EPERM || errno==EIO)) {
908 /* Ran into 'end of memory' - stupid "printpath" */
909 return 0;
910 }
911 if (addr != 0 && errno != EIO && errno != ESRCH)
912 perror("umovestr");
913 return -1;
914 }
Wichert Akkerman5daa0281999-03-15 19:49:42 +0000915 started = 1;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000916 memcpy(laddr, u.x, m = MIN(sizeof(long), len));
917 for (i = 0; i < sizeof(long); i++)
918 if (u.x[i] == '\0')
919 return 0;
920
921 addr += sizeof(long), laddr += m, len -= m;
922 }
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000923#endif /* !USE_PROCFS */
John Hughesaa09c6b2001-05-15 14:53:43 +0000924 return 0;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000925}
926
927#ifdef LINUX
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +0000928# if !defined (SPARC) && !defined(SPARC64)
929# define PTRACE_WRITETEXT 101
930# define PTRACE_WRITEDATA 102
931# endif /* !SPARC && !SPARC64 */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000932#endif /* LINUX */
933
934#ifdef SUNOS4
935
936static int
Roland McGratheb9e2e82009-06-02 16:49:22 -0700937uload(cmd, pid, addr, len, laddr)
938int cmd;
939int pid;
940long addr;
941int len;
942char *laddr;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000943{
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000944 int peek, poke;
945 int n, m;
946 union {
947 long val;
948 char x[sizeof(long)];
949 } u;
950
951 if (cmd == PTRACE_WRITETEXT) {
952 peek = PTRACE_PEEKTEXT;
953 poke = PTRACE_POKETEXT;
954 }
955 else {
956 peek = PTRACE_PEEKDATA;
957 poke = PTRACE_POKEDATA;
958 }
959 if (addr & (sizeof(long) - 1)) {
960 /* addr not a multiple of sizeof(long) */
961 n = addr - (addr & -sizeof(long)); /* residue */
962 addr &= -sizeof(long);
Roland McGratheb9e2e82009-06-02 16:49:22 -0700963 errno = 0;
964 u.val = ptrace(peek, pid, (char *) addr, 0);
965 if (errno) {
966 perror("uload: POKE");
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000967 return -1;
968 }
Roland McGratheb9e2e82009-06-02 16:49:22 -0700969 memcpy(&u.x[n], laddr, m = MIN(sizeof(long) - n, len));
970 if (ptrace(poke, pid, (char *)addr, u.val) < 0) {
971 perror("uload: POKE");
972 return -1;
973 }
974 addr += sizeof(long), laddr += m, len -= m;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000975 }
976 while (len) {
977 if (len < sizeof(long))
Roland McGratheb9e2e82009-06-02 16:49:22 -0700978 u.val = ptrace(peek, pid, (char *) addr, 0);
979 memcpy(u.x, laddr, m = MIN(sizeof(long), len));
980 if (ptrace(poke, pid, (char *) addr, u.val) < 0) {
981 perror("uload: POKE");
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000982 return -1;
983 }
Roland McGratheb9e2e82009-06-02 16:49:22 -0700984 addr += sizeof(long), laddr += m, len -= m;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000985 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000986 return 0;
987}
988
Roland McGratheb9e2e82009-06-02 16:49:22 -0700989int
990tload(pid, addr, len, laddr)
991int pid;
992int addr, len;
993char *laddr;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000994{
Roland McGratheb9e2e82009-06-02 16:49:22 -0700995 return uload(PTRACE_WRITETEXT, pid, addr, len, laddr);
996}
997
998int
999dload(pid, addr, len, laddr)
1000int pid;
1001int addr;
1002int len;
1003char *laddr;
1004{
1005 return uload(PTRACE_WRITEDATA, pid, addr, len, laddr);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001006}
1007
1008#endif /* SUNOS4 */
1009
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001010#ifndef USE_PROCFS
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001011
1012int
Roland McGratheb9e2e82009-06-02 16:49:22 -07001013upeek(tcp, off, res)
1014struct tcb *tcp;
1015long off;
1016long *res;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001017{
1018 long val;
1019
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001020# ifdef SUNOS4_KERNEL_ARCH_KLUDGE
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001021 {
1022 static int is_sun4m = -1;
1023 struct utsname name;
1024
1025 /* Round up the usual suspects. */
1026 if (is_sun4m == -1) {
1027 if (uname(&name) < 0) {
1028 perror("upeek: uname?");
1029 exit(1);
1030 }
1031 is_sun4m = strcmp(name.machine, "sun4m") == 0;
1032 if (is_sun4m) {
Roland McGrathd9f816f2004-09-04 03:39:20 +00001033 const struct xlat *x;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001034
1035 for (x = struct_user_offsets; x->str; x++)
1036 x->val += 1024;
1037 }
1038 }
1039 if (is_sun4m)
1040 off += 1024;
1041 }
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001042# endif /* SUNOS4_KERNEL_ARCH_KLUDGE */
Roland McGratheb9e2e82009-06-02 16:49:22 -07001043 errno = 0;
Denys Vlasenko732d1bf2008-12-17 19:21:59 +00001044 val = do_ptrace(PTRACE_PEEKUSER, tcp, (char *) off, 0);
Roland McGratheb9e2e82009-06-02 16:49:22 -07001045 if (val == -1 && errno) {
1046 if (errno != ESRCH) {
1047 char buf[60];
1048 sprintf(buf,"upeek: ptrace(PTRACE_PEEKUSER,%d,%lu,0)", tcp->pid, off);
1049 perror(buf);
1050 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001051 return -1;
Roland McGratheb9e2e82009-06-02 16:49:22 -07001052 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001053 *res = val;
1054 return 0;
1055}
1056
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001057#endif /* !USE_PROCFS */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001058
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001059void
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001060printcall(struct tcb *tcp)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001061{
Roland McGrath7a918832005-02-02 20:55:23 +00001062#define PRINTBADPC tprintf(sizeof(long) == 4 ? "[????????] " : \
1063 sizeof(long) == 8 ? "[????????????????] " : \
1064 NULL /* crash */)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001065
1066#ifdef LINUX
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001067# ifdef I386
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001068 long eip;
1069
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001070 if (upeek(tcp, 4*EIP, &eip) < 0) {
Roland McGrath7a918832005-02-02 20:55:23 +00001071 PRINTBADPC;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001072 return;
1073 }
1074 tprintf("[%08lx] ", eip);
Roland McGratheac26fc2005-02-02 02:48:53 +00001075
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001076# elif defined(S390) || defined(S390X)
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001077 long psw;
Roland McGratheb9e2e82009-06-02 16:49:22 -07001078 if(upeek(tcp,PT_PSWADDR,&psw) < 0) {
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001079 PRINTBADPC;
1080 return;
1081 }
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001082# ifdef S390
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001083 tprintf("[%08lx] ", psw);
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001084# elif S390X
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001085 tprintf("[%16lx] ", psw);
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001086# endif
Roland McGratheac26fc2005-02-02 02:48:53 +00001087
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001088# elif defined(X86_64)
Michal Ludvig0e035502002-09-23 15:41:01 +00001089 long rip;
1090
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001091 if (upeek(tcp, 8*RIP, &rip) < 0) {
Roland McGrath7a918832005-02-02 20:55:23 +00001092 PRINTBADPC;
Michal Ludvig0e035502002-09-23 15:41:01 +00001093 return;
1094 }
1095 tprintf("[%16lx] ", rip);
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001096# elif defined(IA64)
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00001097 long ip;
1098
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001099 if (upeek(tcp, PT_B0, &ip) < 0) {
Roland McGrath7a918832005-02-02 20:55:23 +00001100 PRINTBADPC;
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00001101 return;
1102 }
1103 tprintf("[%08lx] ", ip);
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001104# elif defined(POWERPC)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001105 long pc;
1106
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001107 if (upeek(tcp, sizeof(unsigned long)*PT_NIP, &pc) < 0) {
Andreas Schwabd69fa492010-07-12 21:39:57 +02001108 PRINTBADPC;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001109 return;
1110 }
Andreas Schwabd69fa492010-07-12 21:39:57 +02001111# ifdef POWERPC64
1112 tprintf("[%016lx] ", pc);
1113# else
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001114 tprintf("[%08lx] ", pc);
Andreas Schwabd69fa492010-07-12 21:39:57 +02001115# endif
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001116# elif defined(M68K)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001117 long pc;
1118
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001119 if (upeek(tcp, 4*PT_PC, &pc) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001120 tprintf ("[????????] ");
1121 return;
1122 }
1123 tprintf("[%08lx] ", pc);
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001124# elif defined(ALPHA)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001125 long pc;
1126
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001127 if (upeek(tcp, REG_PC, &pc) < 0) {
Roland McGrath7a918832005-02-02 20:55:23 +00001128 tprintf ("[????????????????] ");
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001129 return;
1130 }
1131 tprintf("[%08lx] ", pc);
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001132# elif defined(SPARC) || defined(SPARC64)
Mike Frysinger8566c502009-10-12 11:05:14 -04001133 struct pt_regs regs;
Roland McGratheb9e2e82009-06-02 16:49:22 -07001134 if (ptrace(PTRACE_GETREGS,tcp->pid,(char *)&regs,0) < 0) {
Roland McGrath7a918832005-02-02 20:55:23 +00001135 PRINTBADPC;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001136 return;
1137 }
Mike Frysinger8566c502009-10-12 11:05:14 -04001138# if defined(SPARC64)
1139 tprintf("[%08lx] ", regs.tpc);
1140# else
1141 tprintf("[%08lx] ", regs.pc);
1142# endif
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001143# elif defined(HPPA)
Wichert Akkermanc1652e22001-03-27 12:17:16 +00001144 long pc;
1145
Roland McGratheb9e2e82009-06-02 16:49:22 -07001146 if(upeek(tcp,PT_IAOQ0,&pc) < 0) {
Wichert Akkermanc1652e22001-03-27 12:17:16 +00001147 tprintf ("[????????] ");
1148 return;
1149 }
1150 tprintf("[%08lx] ", pc);
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001151# elif defined(MIPS)
Wichert Akkerman75c422b2001-04-10 10:22:50 +00001152 long pc;
1153
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001154 if (upeek(tcp, REG_EPC, &pc) < 0) {
Wichert Akkerman75c422b2001-04-10 10:22:50 +00001155 tprintf ("[????????] ");
1156 return;
1157 }
1158 tprintf("[%08lx] ", pc);
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001159# elif defined(SH)
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001160 long pc;
Wichert Akkermanccef6372002-05-01 16:39:22 +00001161
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001162 if (upeek(tcp, 4*REG_PC, &pc) < 0) {
1163 tprintf ("[????????] ");
1164 return;
1165 }
1166 tprintf("[%08lx] ", pc);
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001167# elif defined(SH64)
Roland McGrathe1e584b2003-06-02 19:18:58 +00001168 long pc;
1169
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001170 if (upeek(tcp, REG_PC, &pc) < 0) {
Roland McGrath7a918832005-02-02 20:55:23 +00001171 tprintf ("[????????????????] ");
Roland McGrathe1e584b2003-06-02 19:18:58 +00001172 return;
1173 }
1174 tprintf("[%08lx] ", pc);
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001175# elif defined(ARM)
Roland McGrathef388682003-06-03 23:28:59 +00001176 long pc;
Roland McGrathe1e584b2003-06-02 19:18:58 +00001177
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001178 if (upeek(tcp, 4*15, &pc) < 0) {
Roland McGrath7a918832005-02-02 20:55:23 +00001179 PRINTBADPC;
Roland McGrathef388682003-06-03 23:28:59 +00001180 return;
1181 }
1182 tprintf("[%08lx] ", pc);
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00001183# elif defined(AVR32)
1184 long pc;
1185
1186 if (upeek(tcp, REG_PC, &pc) < 0) {
1187 tprintf("[????????] ");
1188 return;
1189 }
1190 tprintf("[%08lx] ", pc);
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001191# elif defined(BFIN)
Dmitry V. Levin87ea1f42008-11-10 22:21:41 +00001192 long pc;
1193
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001194 if (upeek(tcp, PT_PC, &pc) < 0) {
Dmitry V. Levin87ea1f42008-11-10 22:21:41 +00001195 PRINTBADPC;
1196 return;
1197 }
1198 tprintf("[%08lx] ", pc);
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001199#elif defined(CRISV10)
1200 long pc;
1201
Edgar E. Iglesiaseeb9ce32009-10-05 14:41:02 +00001202 if (upeek(tcp, 4*PT_IRP, &pc) < 0) {
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001203 PRINTBADPC;
1204 return;
1205 }
1206 tprintf("[%08lx] ", pc);
1207#elif defined(CRISV32)
1208 long pc;
1209
Edgar E. Iglesiaseeb9ce32009-10-05 14:41:02 +00001210 if (upeek(tcp, 4*PT_ERP, &pc) < 0) {
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001211 PRINTBADPC;
1212 return;
1213 }
1214 tprintf("[%08lx] ", pc);
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001215# endif /* architecture */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001216#endif /* LINUX */
1217
1218#ifdef SUNOS4
1219 struct regs regs;
1220
Roland McGratheb9e2e82009-06-02 16:49:22 -07001221 if (ptrace(PTRACE_GETREGS, tcp->pid, (char *) &regs, 0) < 0) {
1222 perror("printcall: ptrace(PTRACE_GETREGS, ...)");
Roland McGrath7a918832005-02-02 20:55:23 +00001223 PRINTBADPC;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001224 return;
1225 }
1226 tprintf("[%08x] ", regs.r_o7);
1227#endif /* SUNOS4 */
1228
1229#ifdef SVR4
1230 /* XXX */
Roland McGrath7a918832005-02-02 20:55:23 +00001231 PRINTBADPC;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001232#endif
1233
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001234#ifdef FREEBSD
1235 struct reg regs;
1236 pread(tcp->pfd_reg, &regs, sizeof(regs), 0);
1237 tprintf("[%08x] ", regs.r_eip);
1238#endif /* FREEBSD */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001239}
1240
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001241
1242/*
1243 * These #if's are huge, please indent them correctly.
1244 * It's easy to get confused otherwise.
1245 */
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001246#ifndef USE_PROCFS
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001247
Dmitry V. Levine5e60852009-12-31 22:50:49 +00001248#ifdef LINUX
Roland McGrathd81f1d92003-01-09 06:53:34 +00001249
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001250# include "syscall.h"
Roland McGrath3291ef22008-05-20 00:34:34 +00001251
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001252# include <sys/syscall.h>
1253# ifndef CLONE_PTRACE
1254# define CLONE_PTRACE 0x00002000
1255# endif
1256# ifndef CLONE_VFORK
1257# define CLONE_VFORK 0x00004000
1258# endif
1259# ifndef CLONE_VM
1260# define CLONE_VM 0x00000100
1261# endif
1262# ifndef CLONE_STOPPED
1263# define CLONE_STOPPED 0x02000000
1264# endif
Roland McGrathd81f1d92003-01-09 06:53:34 +00001265
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001266# ifdef IA64
Roland McGrathd81f1d92003-01-09 06:53:34 +00001267
Roland McGrath08267b82004-02-20 22:56:43 +00001268/* We don't have fork()/vfork() syscalls on ia64 itself, but the ia32
1269 subsystem has them for x86... */
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001270# define SYS_fork 2
1271# define SYS_vfork 190
Roland McGrath08267b82004-02-20 22:56:43 +00001272
Roland McGrathd81f1d92003-01-09 06:53:34 +00001273typedef unsigned long *arg_setup_state;
1274
1275static int
1276arg_setup(struct tcb *tcp, arg_setup_state *state)
1277{
Jan Kratochvil1f942712008-08-06 21:38:52 +00001278 unsigned long cfm, sof, sol;
1279 long bsp;
Roland McGrathd81f1d92003-01-09 06:53:34 +00001280
Jan Kratochvil1f942712008-08-06 21:38:52 +00001281 if (ia32) {
1282 /* Satisfy a false GCC warning. */
1283 *state = NULL;
Roland McGrath08267b82004-02-20 22:56:43 +00001284 return 0;
Jan Kratochvil1f942712008-08-06 21:38:52 +00001285 }
Roland McGrath08267b82004-02-20 22:56:43 +00001286
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001287 if (upeek(tcp, PT_AR_BSP, &bsp) < 0)
Roland McGrathd81f1d92003-01-09 06:53:34 +00001288 return -1;
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001289 if (upeek(tcp, PT_CFM, (long *) &cfm) < 0)
Roland McGrathd81f1d92003-01-09 06:53:34 +00001290 return -1;
1291
1292 sof = (cfm >> 0) & 0x7f;
1293 sol = (cfm >> 7) & 0x7f;
Jan Kratochvil1f942712008-08-06 21:38:52 +00001294 bsp = (long) ia64_rse_skip_regs((unsigned long *) bsp, -sof + sol);
Roland McGrathd81f1d92003-01-09 06:53:34 +00001295
Jan Kratochvil1f942712008-08-06 21:38:52 +00001296 *state = (unsigned long *) bsp;
Roland McGrathd81f1d92003-01-09 06:53:34 +00001297 return 0;
1298}
1299
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001300# define arg_finish_change(tcp, state) 0
Roland McGrathd81f1d92003-01-09 06:53:34 +00001301
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001302# ifdef SYS_fork
Roland McGrathd81f1d92003-01-09 06:53:34 +00001303static int
1304get_arg0 (struct tcb *tcp, arg_setup_state *state, long *valp)
1305{
Roland McGrath08267b82004-02-20 22:56:43 +00001306 int ret;
1307
1308 if (ia32)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001309 ret = upeek (tcp, PT_R11, valp);
Roland McGrath08267b82004-02-20 22:56:43 +00001310 else
1311 ret = umoven (tcp,
1312 (unsigned long) ia64_rse_skip_regs(*state, 0),
1313 sizeof(long), (void *) valp);
1314 return ret;
Roland McGrathd81f1d92003-01-09 06:53:34 +00001315}
1316
1317static int
1318get_arg1 (struct tcb *tcp, arg_setup_state *state, long *valp)
1319{
Roland McGrath08267b82004-02-20 22:56:43 +00001320 int ret;
1321
1322 if (ia32)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001323 ret = upeek (tcp, PT_R9, valp);
Roland McGrath08267b82004-02-20 22:56:43 +00001324 else
1325 ret = umoven (tcp,
1326 (unsigned long) ia64_rse_skip_regs(*state, 1),
1327 sizeof(long), (void *) valp);
1328 return ret;
Roland McGrathd81f1d92003-01-09 06:53:34 +00001329}
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001330# endif
Roland McGrathd81f1d92003-01-09 06:53:34 +00001331
1332static int
1333set_arg0 (struct tcb *tcp, arg_setup_state *state, long val)
1334{
Roland McGrath08267b82004-02-20 22:56:43 +00001335 int req = PTRACE_POKEDATA;
1336 void *ap;
1337
1338 if (ia32) {
1339 ap = (void *) (intptr_t) PT_R11; /* r11 == EBX */
1340 req = PTRACE_POKEUSER;
1341 } else
1342 ap = ia64_rse_skip_regs(*state, 0);
Roland McGratheb9e2e82009-06-02 16:49:22 -07001343 errno = 0;
1344 ptrace(req, tcp->pid, ap, val);
1345 return errno ? -1 : 0;
Roland McGrathd81f1d92003-01-09 06:53:34 +00001346}
1347
1348static int
1349set_arg1 (struct tcb *tcp, arg_setup_state *state, long val)
1350{
Roland McGrath08267b82004-02-20 22:56:43 +00001351 int req = PTRACE_POKEDATA;
1352 void *ap;
1353
1354 if (ia32) {
1355 ap = (void *) (intptr_t) PT_R9; /* r9 == ECX */
1356 req = PTRACE_POKEUSER;
1357 } else
1358 ap = ia64_rse_skip_regs(*state, 1);
Roland McGratheb9e2e82009-06-02 16:49:22 -07001359 errno = 0;
1360 ptrace(req, tcp->pid, ap, val);
1361 return errno ? -1 : 0;
Roland McGrathd81f1d92003-01-09 06:53:34 +00001362}
1363
Roland McGrathb659f872008-07-18 01:19:36 +00001364/* ia64 does not return the input arguments from functions (and syscalls)
1365 according to ia64 RSE (Register Stack Engine) behavior. */
1366
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001367# define restore_arg0(tcp, state, val) ((void) (state), 0)
1368# define restore_arg1(tcp, state, val) ((void) (state), 0)
Roland McGrathb659f872008-07-18 01:19:36 +00001369
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001370# elif defined (SPARC) || defined (SPARC64)
Roland McGrathd81f1d92003-01-09 06:53:34 +00001371
Mike Frysinger8566c502009-10-12 11:05:14 -04001372typedef struct pt_regs arg_setup_state;
Roland McGrathd81f1d92003-01-09 06:53:34 +00001373
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001374# define arg_setup(tcp, state) \
Roland McGratheb9e2e82009-06-02 16:49:22 -07001375 (ptrace (PTRACE_GETREGS, tcp->pid, (char *) (state), 0))
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001376# define arg_finish_change(tcp, state) \
Roland McGratheb9e2e82009-06-02 16:49:22 -07001377 (ptrace (PTRACE_SETREGS, tcp->pid, (char *) (state), 0))
Roland McGrathd81f1d92003-01-09 06:53:34 +00001378
Mike Frysinger8566c502009-10-12 11:05:14 -04001379# define get_arg0(tcp, state, valp) (*(valp) = (state)->u_regs[U_REG_O0], 0)
1380# define get_arg1(tcp, state, valp) (*(valp) = (state)->u_regs[U_REG_O1], 0)
1381# define set_arg0(tcp, state, val) ((state)->u_regs[U_REG_O0] = (val), 0)
1382# define set_arg1(tcp, state, val) ((state)->u_regs[U_REG_O1] = (val), 0)
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001383# define restore_arg0(tcp, state, val) 0
Roland McGrathd81f1d92003-01-09 06:53:34 +00001384
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001385# else /* other architectures */
Roland McGrathd81f1d92003-01-09 06:53:34 +00001386
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001387# if defined S390 || defined S390X
Roland McGrath7b308222003-01-20 09:04:36 +00001388/* Note: this is only true for the `clone' system call, which handles
1389 arguments specially. We could as well say that its first two arguments
1390 are swapped relative to other architectures, but that would just be
1391 another #ifdef in the calls. */
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001392# define arg0_offset PT_GPR3
1393# define arg1_offset PT_ORIGGPR2
1394# define restore_arg0(tcp, state, val) ((void) (state), 0)
1395# define restore_arg1(tcp, state, val) ((void) (state), 0)
1396# define arg0_index 1
1397# define arg1_index 0
1398# elif defined (ALPHA) || defined (MIPS)
1399# define arg0_offset REG_A0
1400# define arg1_offset (REG_A0+1)
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00001401# elif defined (AVR32)
1402# define arg0_offset (REG_R12)
1403# define arg1_offset (REG_R11)
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001404# elif defined (POWERPC)
1405# define arg0_offset (sizeof(unsigned long)*PT_R3)
1406# define arg1_offset (sizeof(unsigned long)*PT_R4)
1407# define restore_arg0(tcp, state, val) ((void) (state), 0)
1408# elif defined (HPPA)
1409# define arg0_offset PT_GR26
1410# define arg1_offset (PT_GR26-4)
1411# elif defined (X86_64)
1412# define arg0_offset ((long)(8*(current_personality ? RBX : RDI)))
1413# define arg1_offset ((long)(8*(current_personality ? RCX : RSI)))
1414# elif defined (SH)
1415# define arg0_offset (4*(REG_REG0+4))
1416# define arg1_offset (4*(REG_REG0+5))
1417# elif defined (SH64)
1418 /* ABI defines arg0 & 1 in r2 & r3 */
1419# define arg0_offset (REG_OFFSET+16)
1420# define arg1_offset (REG_OFFSET+24)
1421# define restore_arg0(tcp, state, val) 0
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001422# elif defined CRISV10 || defined CRISV32
1423# define arg0_offset (4*PT_R11)
1424# define arg1_offset (4*PT_ORIG_R10)
1425# define restore_arg0(tcp, state, val) 0
1426# define restore_arg1(tcp, state, val) 0
1427# define arg0_index 1
1428# define arg1_index 0
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001429# else
1430# define arg0_offset 0
1431# define arg1_offset 4
1432# if defined ARM
1433# define restore_arg0(tcp, state, val) 0
1434# endif
1435# endif
Roland McGrathd81f1d92003-01-09 06:53:34 +00001436
1437typedef int arg_setup_state;
1438
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001439# define arg_setup(tcp, state) (0)
1440# define arg_finish_change(tcp, state) 0
1441# define get_arg0(tcp, cookie, valp) \
1442 (upeek ((tcp), arg0_offset, (valp)))
1443# define get_arg1(tcp, cookie, valp) \
1444 (upeek ((tcp), arg1_offset, (valp)))
Roland McGrathd81f1d92003-01-09 06:53:34 +00001445
1446static int
Roland McGratheb9e2e82009-06-02 16:49:22 -07001447set_arg0 (struct tcb *tcp, void *cookie, long val)
Roland McGrathd81f1d92003-01-09 06:53:34 +00001448{
Roland McGratheb9e2e82009-06-02 16:49:22 -07001449 return ptrace (PTRACE_POKEUSER, tcp->pid, (char*)arg0_offset, val);
Roland McGrathd81f1d92003-01-09 06:53:34 +00001450}
1451
1452static int
Roland McGratheb9e2e82009-06-02 16:49:22 -07001453set_arg1 (struct tcb *tcp, void *cookie, long val)
Roland McGrathd81f1d92003-01-09 06:53:34 +00001454{
Roland McGratheb9e2e82009-06-02 16:49:22 -07001455 return ptrace (PTRACE_POKEUSER, tcp->pid, (char*)arg1_offset, val);
Roland McGrathd81f1d92003-01-09 06:53:34 +00001456}
1457
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001458# endif /* architectures */
Roland McGrathd81f1d92003-01-09 06:53:34 +00001459
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001460# ifndef restore_arg0
1461# define restore_arg0(tcp, state, val) set_arg0((tcp), (state), (val))
1462# endif
1463# ifndef restore_arg1
1464# define restore_arg1(tcp, state, val) set_arg1((tcp), (state), (val))
1465# endif
Roland McGrathd81f1d92003-01-09 06:53:34 +00001466
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001467# ifndef arg0_index
1468# define arg0_index 0
1469# define arg1_index 1
1470# endif
Roland McGrath90d0afd2004-03-01 21:05:16 +00001471
Roland McGrathd81f1d92003-01-09 06:53:34 +00001472int
Denys Vlasenko418d66a2009-01-17 01:52:54 +00001473setbpt(struct tcb *tcp)
Roland McGrathd81f1d92003-01-09 06:53:34 +00001474{
Roland McGrath3291ef22008-05-20 00:34:34 +00001475 static int clone_scno[SUPPORTED_PERSONALITIES] = { SYS_clone };
Roland McGrathd81f1d92003-01-09 06:53:34 +00001476 arg_setup_state state;
1477
1478 if (tcp->flags & TCB_BPTSET) {
1479 fprintf(stderr, "PANIC: TCB already set in pid %u\n", tcp->pid);
1480 return -1;
1481 }
1482
Roland McGrath3291ef22008-05-20 00:34:34 +00001483 /*
1484 * It's a silly kludge to initialize this with a search at runtime.
1485 * But it's better than maintaining another magic thing in the
1486 * godforsaken tables.
1487 */
1488 if (clone_scno[current_personality] == 0) {
1489 int i;
1490 for (i = 0; i < nsyscalls; ++i)
1491 if (sysent[i].sys_func == sys_clone) {
1492 clone_scno[current_personality] = i;
1493 break;
1494 }
1495 }
1496
Roland McGrath76989d72005-06-07 23:21:31 +00001497 switch (known_scno(tcp)) {
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001498# ifdef SYS_vfork
Roland McGrath9383c6c2003-01-18 00:19:31 +00001499 case SYS_vfork:
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001500# endif
1501# ifdef SYS_fork
Roland McGrathd81f1d92003-01-09 06:53:34 +00001502 case SYS_fork:
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001503# endif
1504# if defined SYS_fork || defined SYS_vfork
Roland McGrathd81f1d92003-01-09 06:53:34 +00001505 if (arg_setup (tcp, &state) < 0
1506 || get_arg0 (tcp, &state, &tcp->inst[0]) < 0
1507 || get_arg1 (tcp, &state, &tcp->inst[1]) < 0
Roland McGrath3291ef22008-05-20 00:34:34 +00001508 || change_syscall(tcp, clone_scno[current_personality]) < 0
Roland McGrathd81f1d92003-01-09 06:53:34 +00001509 || set_arg0 (tcp, &state, CLONE_PTRACE|SIGCHLD) < 0
1510 || set_arg1 (tcp, &state, 0) < 0
1511 || arg_finish_change (tcp, &state) < 0)
1512 return -1;
Roland McGrathc9dc3c12004-03-01 20:57:09 +00001513 tcp->u_arg[arg0_index] = CLONE_PTRACE|SIGCHLD;
1514 tcp->u_arg[arg1_index] = 0;
Roland McGrathd81f1d92003-01-09 06:53:34 +00001515 tcp->flags |= TCB_BPTSET;
1516 return 0;
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001517# endif
Roland McGrathd81f1d92003-01-09 06:53:34 +00001518
1519 case SYS_clone:
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001520# ifdef SYS_clone2
Roland McGrathd81f1d92003-01-09 06:53:34 +00001521 case SYS_clone2:
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001522# endif
Jan Kratochvil8fc95752008-08-06 21:43:35 +00001523 /* ia64 calls directly `clone (CLONE_VFORK | CLONE_VM)'
1524 contrary to x86 SYS_vfork above. Even on x86 we turn the
1525 vfork semantics into plain fork - each application must not
1526 depend on the vfork specifics according to POSIX. We would
1527 hang waiting for the parent resume otherwise. We need to
1528 clear also CLONE_VM but only in the CLONE_VFORK case as
1529 otherwise we would break pthread_create. */
1530
Roland McGrathd6ff0d52008-07-18 01:09:44 +00001531 if ((arg_setup (tcp, &state) < 0
1532 || set_arg0 (tcp, &state,
1533 (tcp->u_arg[arg0_index] | CLONE_PTRACE)
Jan Kratochvil8fc95752008-08-06 21:43:35 +00001534 & ~(tcp->u_arg[arg0_index] & CLONE_VFORK
1535 ? CLONE_VFORK | CLONE_VM : 0)) < 0
Roland McGrathd6ff0d52008-07-18 01:09:44 +00001536 || arg_finish_change (tcp, &state) < 0))
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00001537 return -1;
Roland McGrathd81f1d92003-01-09 06:53:34 +00001538 tcp->flags |= TCB_BPTSET;
Roland McGrathc9dc3c12004-03-01 20:57:09 +00001539 tcp->inst[0] = tcp->u_arg[arg0_index];
1540 tcp->inst[1] = tcp->u_arg[arg1_index];
Roland McGrathd81f1d92003-01-09 06:53:34 +00001541 return 0;
1542
1543 default:
1544 fprintf(stderr, "PANIC: setbpt for syscall %ld on %u???\n",
1545 tcp->scno, tcp->pid);
1546 break;
1547 }
1548
1549 return -1;
1550}
1551
1552int
1553clearbpt(tcp)
1554struct tcb *tcp;
1555{
1556 arg_setup_state state;
1557 if (arg_setup (tcp, &state) < 0
Roland McGrathe1df47f2003-01-14 09:46:15 +00001558 || restore_arg0 (tcp, &state, tcp->inst[0]) < 0
1559 || restore_arg1 (tcp, &state, tcp->inst[1]) < 0
Roland McGrathd81f1d92003-01-09 06:53:34 +00001560 || arg_finish_change (tcp, &state))
Andreas Schwab46ed50d2009-11-11 13:54:04 +01001561 if (errno != ESRCH) return -1;
Roland McGrathd81f1d92003-01-09 06:53:34 +00001562 tcp->flags &= ~TCB_BPTSET;
1563 return 0;
1564}
1565
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001566# else /* !defined LINUX */
Roland McGrathd81f1d92003-01-09 06:53:34 +00001567
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001568int
1569setbpt(tcp)
1570struct tcb *tcp;
1571{
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001572# ifdef SUNOS4
1573# ifdef SPARC /* This code is slightly sparc specific */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001574
Wichert Akkermane6f876c1999-06-22 15:28:30 +00001575 struct regs regs;
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001576# define BPT 0x91d02001 /* ta 1 */
1577# define LOOP 0x10800000 /* ba 0 */
1578# define LOOPA 0x30800000 /* ba,a 0 */
1579# define NOP 0x01000000
1580# if LOOPA
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001581 static int loopdeloop[1] = {LOOPA};
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001582# else
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001583 static int loopdeloop[2] = {LOOP, NOP};
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001584# endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001585
1586 if (tcp->flags & TCB_BPTSET) {
1587 fprintf(stderr, "PANIC: TCB already set in pid %u\n", tcp->pid);
1588 return -1;
1589 }
Roland McGratheb9e2e82009-06-02 16:49:22 -07001590 if (ptrace(PTRACE_GETREGS, tcp->pid, (char *)&regs, 0) < 0) {
1591 perror("setbpt: ptrace(PTRACE_GETREGS, ...)");
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001592 return -1;
1593 }
1594 tcp->baddr = regs.r_o7 + 8;
Roland McGratheb9e2e82009-06-02 16:49:22 -07001595 if (ptrace(PTRACE_READTEXT, tcp->pid, (char *)tcp->baddr,
1596 sizeof tcp->inst, (char *)tcp->inst) < 0) {
1597 perror("setbpt: ptrace(PTRACE_READTEXT, ...)");
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001598 return -1;
1599 }
1600
1601 /*
1602 * XXX - BRUTAL MODE ON
1603 * We cannot set a real BPT in the child, since it will not be
1604 * traced at the moment it will reach the trap and would probably
1605 * die with a core dump.
1606 * Thus, we are force our way in by taking out two instructions
1607 * and insert an eternal loop in stead, in expectance of the SIGSTOP
1608 * generated by out PTRACE_ATTACH.
1609 * Of cause, if we evaporate ourselves in the middle of all this...
1610 */
Roland McGratheb9e2e82009-06-02 16:49:22 -07001611 if (ptrace(PTRACE_WRITETEXT, tcp->pid, (char *) tcp->baddr,
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001612 sizeof loopdeloop, (char *) loopdeloop) < 0) {
Roland McGratheb9e2e82009-06-02 16:49:22 -07001613 perror("setbpt: ptrace(PTRACE_WRITETEXT, ...)");
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001614 return -1;
1615 }
1616 tcp->flags |= TCB_BPTSET;
1617
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001618# endif /* SPARC */
1619# endif /* SUNOS4 */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001620
1621 return 0;
1622}
1623
1624int
1625clearbpt(tcp)
1626struct tcb *tcp;
1627{
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001628# ifdef SUNOS4
1629# ifdef SPARC
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001630
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001631# if !LOOPA
Wichert Akkermane6f876c1999-06-22 15:28:30 +00001632 struct regs regs;
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001633# endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001634
1635 if (!(tcp->flags & TCB_BPTSET)) {
1636 fprintf(stderr, "PANIC: TCB not set in pid %u\n", tcp->pid);
1637 return -1;
1638 }
Roland McGratheb9e2e82009-06-02 16:49:22 -07001639 if (ptrace(PTRACE_WRITETEXT, tcp->pid, (char *) tcp->baddr,
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001640 sizeof tcp->inst, (char *) tcp->inst) < 0) {
Roland McGratheb9e2e82009-06-02 16:49:22 -07001641 perror("clearbtp: ptrace(PTRACE_WRITETEXT, ...)");
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001642 return -1;
1643 }
1644 tcp->flags &= ~TCB_BPTSET;
1645
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001646# if !LOOPA
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001647 /*
1648 * Since we don't have a single instruction breakpoint, we may have
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001649 * to adjust the program counter after removing our `breakpoint'.
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001650 */
Roland McGratheb9e2e82009-06-02 16:49:22 -07001651 if (ptrace(PTRACE_GETREGS, tcp->pid, (char *)&regs, 0) < 0) {
1652 perror("clearbpt: ptrace(PTRACE_GETREGS, ...)");
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001653 return -1;
1654 }
Roland McGratheb9e2e82009-06-02 16:49:22 -07001655 if ((regs.r_pc < tcp->baddr) ||
1656 (regs.r_pc > tcp->baddr + 4)) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001657 /* The breakpoint has not been reached yet */
1658 if (debug)
1659 fprintf(stderr,
1660 "NOTE: PC not at bpt (pc %#x baddr %#x)\n",
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001661 regs.r_pc, tcp->baddr);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001662 return 0;
1663 }
1664 if (regs.r_pc != tcp->baddr)
1665 if (debug)
1666 fprintf(stderr, "NOTE: PC adjusted (%#x -> %#x\n",
1667 regs.r_pc, tcp->baddr);
1668
1669 regs.r_pc = tcp->baddr;
Roland McGratheb9e2e82009-06-02 16:49:22 -07001670 if (ptrace(PTRACE_SETREGS, tcp->pid, (char *)&regs, 0) < 0) {
1671 perror("clearbpt: ptrace(PTRACE_SETREGS, ...)");
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001672 return -1;
1673 }
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001674# endif /* LOOPA */
1675# endif /* SPARC */
1676# endif /* SUNOS4 */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001677
1678 return 0;
1679}
1680
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001681# endif /* !defined LINUX */
Roland McGrathd81f1d92003-01-09 06:53:34 +00001682
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001683#endif /* !USE_PROCFS */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001684
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001685
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001686#ifdef SUNOS4
1687
1688static int
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001689getex(tcp, hdr)
1690struct tcb *tcp;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001691struct exec *hdr;
1692{
1693 int n;
1694
1695 for (n = 0; n < sizeof *hdr; n += 4) {
1696 long res;
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001697 if (upeek(tcp, uoff(u_exdata) + n, &res) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001698 return -1;
1699 memcpy(((char *) hdr) + n, &res, 4);
1700 }
1701 if (debug) {
1702 fprintf(stderr, "[struct exec: magic: %o version %u Mach %o\n",
1703 hdr->a_magic, hdr->a_toolversion, hdr->a_machtype);
1704 fprintf(stderr, "Text %lu Data %lu Bss %lu Syms %lu Entry %#lx]\n",
1705 hdr->a_text, hdr->a_data, hdr->a_bss, hdr->a_syms, hdr->a_entry);
1706 }
1707 return 0;
1708}
1709
1710int
1711fixvfork(tcp)
1712struct tcb *tcp;
1713{
1714 int pid = tcp->pid;
1715 /*
1716 * Change `vfork' in a freshly exec'ed dynamically linked
1717 * executable's (internal) symbol table to plain old `fork'
1718 */
1719
1720 struct exec hdr;
1721 struct link_dynamic dyn;
1722 struct link_dynamic_2 ld;
1723 char *strtab, *cp;
1724
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001725 if (getex(tcp, &hdr) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001726 return -1;
1727 if (!hdr.a_dynamic)
1728 return -1;
1729
1730 if (umove(tcp, (int) N_DATADDR(hdr), &dyn) < 0) {
1731 fprintf(stderr, "Cannot read DYNAMIC\n");
1732 return -1;
1733 }
1734 if (umove(tcp, (int) dyn.ld_un.ld_2, &ld) < 0) {
1735 fprintf(stderr, "Cannot read link_dynamic_2\n");
1736 return -1;
1737 }
1738 if ((strtab = malloc((unsigned)ld.ld_symb_size)) == NULL) {
Roland McGrath46100d02005-06-01 18:55:42 +00001739 fprintf(stderr, "out of memory\n");
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001740 return -1;
1741 }
Roland McGratheb9e2e82009-06-02 16:49:22 -07001742 if (umoven(tcp, (int)ld.ld_symbols+(int)N_TXTADDR(hdr),
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001743 (int)ld.ld_symb_size, strtab) < 0)
1744 goto err;
1745
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001746 for (cp = strtab; cp < strtab + ld.ld_symb_size; ) {
1747 if (strcmp(cp, "_vfork") == 0) {
1748 if (debug)
1749 fprintf(stderr, "fixvfork: FOUND _vfork\n");
1750 strcpy(cp, "_fork");
1751 break;
1752 }
1753 cp += strlen(cp)+1;
1754 }
1755 if (cp < strtab + ld.ld_symb_size)
1756 /*
1757 * Write entire symbol table back to avoid
1758 * memory alignment bugs in ptrace
1759 */
Roland McGratheb9e2e82009-06-02 16:49:22 -07001760 if (tload(pid, (int)ld.ld_symbols+(int)N_TXTADDR(hdr),
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001761 (int)ld.ld_symb_size, strtab) < 0)
1762 goto err;
1763
1764 free(strtab);
1765 return 0;
1766
1767err:
1768 free(strtab);
1769 return -1;
1770}
1771
1772#endif /* SUNOS4 */