blob: 711e61441d421f7013c58b71cb4951469b57a658 [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
Dmitry V. Levin31382132011-03-04 05:08:02 +0300419printfd(struct tcb *tcp, int fd)
420{
421 tprintf("%d", fd);
422}
423
424void
Roland McGrath6bc12202003-11-13 22:32:27 +0000425printuid(text, uid)
426const char *text;
427unsigned long uid;
428{
429 tprintf("%s", text);
430 tprintf((uid == -1) ? "%ld" : "%lu", uid);
431}
432
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000433static char path[MAXPATHLEN + 1];
434
Dmitry V. Levina501f142008-11-10 23:19:13 +0000435/*
436 * Quote string `instr' of length `size'
437 * Write up to (3 + `size' * 4) bytes to `outstr' buffer.
438 * If `len' < 0, treat `instr' as a NUL-terminated string
439 * and quote at most (`size' - 1) bytes.
440 */
Roland McGrath6d970322007-11-01 23:53:59 +0000441static int
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000442string_quote(const char *instr, char *outstr, int len, int size)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000443{
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000444 const unsigned char *ustr = (const unsigned char *) instr;
445 char *s = outstr;
446 int usehex = 0, c, i;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000447
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000448 if (xflag > 1)
449 usehex = 1;
450 else if (xflag) {
Dmitry V. Levina501f142008-11-10 23:19:13 +0000451 /* Check for presence of symbol which require
452 to hex-quote the whole string. */
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000453 for (i = 0; i < size; ++i) {
454 c = ustr[i];
Dmitry V. Levina501f142008-11-10 23:19:13 +0000455 /* Check for NUL-terminated string. */
456 if (len < 0) {
457 if (c == '\0')
458 break;
459 /* Quote at most size - 1 bytes. */
460 if (i == size - 1)
461 continue;
462 }
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000463 if (!isprint(c) && !isspace(c)) {
464 usehex = 1;
465 break;
466 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000467 }
468 }
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000469
470 *s++ = '\"';
471
472 if (usehex) {
Dmitry V. Levina501f142008-11-10 23:19:13 +0000473 /* Hex-quote the whole string. */
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000474 for (i = 0; i < size; ++i) {
475 c = ustr[i];
Dmitry V. Levina501f142008-11-10 23:19:13 +0000476 /* Check for NUL-terminated string. */
477 if (len < 0) {
478 if (c == '\0')
479 break;
480 /* Quote at most size - 1 bytes. */
481 if (i == size - 1)
482 continue;
483 }
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000484 sprintf(s, "\\x%02x", c);
485 s += 4;
486 }
487 } else {
488 for (i = 0; i < size; ++i) {
489 c = ustr[i];
Dmitry V. Levina501f142008-11-10 23:19:13 +0000490 /* Check for NUL-terminated string. */
491 if (len < 0) {
492 if (c == '\0')
493 break;
494 /* Quote at most size - 1 bytes. */
495 if (i == size - 1)
496 continue;
497 }
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000498 switch (c) {
499 case '\"': case '\\':
500 *s++ = '\\';
501 *s++ = c;
502 break;
503 case '\f':
504 *s++ = '\\';
505 *s++ = 'f';
506 break;
507 case '\n':
508 *s++ = '\\';
509 *s++ = 'n';
510 break;
511 case '\r':
512 *s++ = '\\';
513 *s++ = 'r';
514 break;
515 case '\t':
516 *s++ = '\\';
517 *s++ = 't';
518 break;
519 case '\v':
520 *s++ = '\\';
521 *s++ = 'v';
522 break;
523 default:
524 if (isprint(c))
525 *s++ = c;
526 else if (i + 1 < size
527 && isdigit(ustr[i + 1])) {
528 sprintf(s, "\\%03o", c);
529 s += 4;
530 } else {
531 sprintf(s, "\\%o", c);
532 s += strlen(s);
533 }
534 break;
535 }
536 }
537 }
538
539 *s++ = '\"';
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000540 *s = '\0';
Roland McGrath6d970322007-11-01 23:53:59 +0000541
542 /* Return nonzero if the string was unterminated. */
543 return i == size;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000544}
545
Dmitry V. Levina501f142008-11-10 23:19:13 +0000546/*
547 * Print path string specified by address `addr' and length `n'.
548 * If path length exceeds `n', append `...' to the output.
549 */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000550void
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000551printpathn(struct tcb *tcp, long addr, int n)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000552{
Dmitry V. Levina501f142008-11-10 23:19:13 +0000553 if (!addr) {
Roland McGrath371ed8f2005-02-06 01:55:07 +0000554 tprintf("NULL");
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000555 return;
556 }
557
Dmitry V. Levina501f142008-11-10 23:19:13 +0000558 /* Cap path length to the path buffer size,
559 and NUL-terminate the buffer. */
560 if (n > sizeof path - 1)
561 n = sizeof path - 1;
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000562 path[n] = '\0';
Dmitry V. Levina501f142008-11-10 23:19:13 +0000563
564 /* Fetch one byte more to find out whether path length > n. */
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000565 if (umovestr(tcp, addr, n + 1, path) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000566 tprintf("%#lx", addr);
567 else {
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000568 static char outstr[4*(sizeof path - 1) + sizeof "\"...\""];
569 int trunc = (path[n] != '\0');
570
571 if (trunc)
572 path[n] = '\0';
Dmitry V. Levina501f142008-11-10 23:19:13 +0000573 (void) string_quote(path, outstr, -1, n + 1);
574 if (trunc)
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000575 strcat(outstr, "...");
576 tprintf("%s", outstr);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000577 }
578}
579
580void
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000581printpath(struct tcb *tcp, long addr)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000582{
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000583 printpathn(tcp, addr, sizeof path - 1);
584}
585
Dmitry V. Levina501f142008-11-10 23:19:13 +0000586/*
587 * Print string specified by address `addr' and length `len'.
588 * If `len' < 0, treat the string as a NUL-terminated string.
589 * If string length exceeds `max_strlen', append `...' to the output.
590 */
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000591void
592printstr(struct tcb *tcp, long addr, int len)
593{
594 static char *str = NULL;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000595 static char *outstr;
Roland McGrath6d970322007-11-01 23:53:59 +0000596 int size;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000597
598 if (!addr) {
599 tprintf("NULL");
600 return;
601 }
Dmitry V. Levina501f142008-11-10 23:19:13 +0000602 /* Allocate static buffers if they are not allocated yet. */
603 if (!str)
604 str = malloc(max_strlen + 1);
605 if (!outstr)
606 outstr = malloc(4 * max_strlen + sizeof "\"...\"");
607 if (!str || !outstr) {
608 fprintf(stderr, "out of memory\n");
609 tprintf("%#lx", addr);
610 return;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000611 }
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000612
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000613 if (len < 0) {
Dmitry V. Levina501f142008-11-10 23:19:13 +0000614 /*
615 * Treat as a NUL-terminated string: fetch one byte more
616 * because string_quote() quotes one byte less.
617 */
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000618 size = max_strlen + 1;
Dmitry V. Levina501f142008-11-10 23:19:13 +0000619 str[max_strlen] = '\0';
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000620 if (umovestr(tcp, addr, size, str) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000621 tprintf("%#lx", addr);
622 return;
623 }
624 }
625 else {
Dmitry V. Levina501f142008-11-10 23:19:13 +0000626 size = MIN(len, max_strlen);
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000627 if (umoven(tcp, addr, size, str) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000628 tprintf("%#lx", addr);
629 return;
630 }
631 }
632
Dmitry V. Levina501f142008-11-10 23:19:13 +0000633 if (string_quote(str, outstr, len, size) &&
634 (len < 0 || len > max_strlen))
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000635 strcat(outstr, "...");
Roland McGratha503dcf2007-08-02 02:06:26 +0000636
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000637 tprintf("%s", outstr);
638}
639
John Hughes1d08dcf2001-07-10 13:48:44 +0000640#if HAVE_SYS_UIO_H
641void
642dumpiov(tcp, len, addr)
643struct tcb * tcp;
644int len;
645long addr;
646{
Dmitry V. Levin4ebb4e32006-12-13 17:08:08 +0000647#if defined(LINUX) && SUPPORTED_PERSONALITIES > 1
648 union {
649 struct { u_int32_t base; u_int32_t len; } *iov32;
650 struct { u_int64_t base; u_int64_t len; } *iov64;
651 } iovu;
652#define iov iovu.iov64
653#define sizeof_iov \
654 (personality_wordsize[current_personality] == 4 \
655 ? sizeof(*iovu.iov32) : sizeof(*iovu.iov64))
656#define iov_iov_base(i) \
657 (personality_wordsize[current_personality] == 4 \
658 ? (u_int64_t) iovu.iov32[i].base : iovu.iov64[i].base)
659#define iov_iov_len(i) \
660 (personality_wordsize[current_personality] == 4 \
661 ? (u_int64_t) iovu.iov32[i].len : iovu.iov64[i].len)
662#else
John Hughes1d08dcf2001-07-10 13:48:44 +0000663 struct iovec *iov;
Dmitry V. Levin4ebb4e32006-12-13 17:08:08 +0000664#define sizeof_iov sizeof(*iov)
665#define iov_iov_base(i) iov[i].iov_base
666#define iov_iov_len(i) iov[i].iov_len
667#endif
John Hughes1d08dcf2001-07-10 13:48:44 +0000668 int i;
Roland McGrathaa524c82005-06-01 19:22:06 +0000669 unsigned long size;
John Hughes1d08dcf2001-07-10 13:48:44 +0000670
Dmitry V. Levin4ebb4e32006-12-13 17:08:08 +0000671 size = sizeof_iov * (unsigned long) len;
672 if (size / sizeof_iov != len
673 || (iov = malloc(size)) == NULL) {
Roland McGrathaa524c82005-06-01 19:22:06 +0000674 fprintf(stderr, "out of memory\n");
John Hughes1d08dcf2001-07-10 13:48:44 +0000675 return;
676 }
Roland McGrathaa524c82005-06-01 19:22:06 +0000677 if (umoven(tcp, addr, size, (char *) iov) >= 0) {
John Hughes1d08dcf2001-07-10 13:48:44 +0000678 for (i = 0; i < len; i++) {
Denys Vlasenkoadedb512008-12-30 18:47:55 +0000679 /* include the buffer number to make it easy to
680 * match up the trace with the source */
681 tprintf(" * %lu bytes in buffer %d\n",
682 (unsigned long)iov_iov_len(i), i);
683 dumpstr(tcp, (long) iov_iov_base(i),
684 iov_iov_len(i));
685 }
John Hughes1d08dcf2001-07-10 13:48:44 +0000686 }
687 free((char *) iov);
Dmitry V. Levin4ebb4e32006-12-13 17:08:08 +0000688#undef sizeof_iov
689#undef iov_iov_base
690#undef iov_iov_len
691#undef iov
John Hughes1d08dcf2001-07-10 13:48:44 +0000692}
693#endif
694
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000695void
696dumpstr(tcp, addr, len)
697struct tcb *tcp;
698long addr;
699int len;
700{
701 static int strsize = -1;
702 static unsigned char *str;
703 static char outstr[80];
704 char *s;
705 int i, j;
706
707 if (strsize < len) {
708 if (str)
709 free(str);
710 if ((str = malloc(len)) == NULL) {
Roland McGrath46100d02005-06-01 18:55:42 +0000711 fprintf(stderr, "out of memory\n");
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000712 return;
713 }
714 strsize = len;
715 }
716
717 if (umoven(tcp, addr, len, (char *) str) < 0)
718 return;
719
720 for (i = 0; i < len; i += 16) {
721 s = outstr;
722 sprintf(s, " | %05x ", i);
723 s += 9;
724 for (j = 0; j < 16; j++) {
725 if (j == 8)
726 *s++ = ' ';
727 if (i + j < len) {
728 sprintf(s, " %02x", str[i + j]);
729 s += 3;
730 }
731 else {
732 *s++ = ' '; *s++ = ' '; *s++ = ' ';
733 }
734 }
735 *s++ = ' '; *s++ = ' ';
736 for (j = 0; j < 16; j++) {
737 if (j == 8)
738 *s++ = ' ';
739 if (i + j < len) {
740 if (isprint(str[i + j]))
741 *s++ = str[i + j];
742 else
743 *s++ = '.';
744 }
745 else
746 *s++ = ' ';
747 }
748 tprintf("%s |\n", outstr);
749 }
750}
751
752#define PAGMASK (~(PAGSIZ - 1))
753/*
754 * move `len' bytes of data from process `pid'
755 * at address `addr' to our space at `laddr'
756 */
757int
Denys Vlasenkoef2fbf82009-01-06 21:45:06 +0000758umoven(struct tcb *tcp, long addr, int len, char *laddr)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000759{
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000760#ifdef LINUX
Roland McGratheb9e2e82009-06-02 16:49:22 -0700761 int pid = tcp->pid;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000762 int n, m;
Wichert Akkerman5daa0281999-03-15 19:49:42 +0000763 int started = 0;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000764 union {
765 long val;
766 char x[sizeof(long)];
767 } u;
768
769 if (addr & (sizeof(long) - 1)) {
770 /* addr not a multiple of sizeof(long) */
771 n = addr - (addr & -sizeof(long)); /* residue */
772 addr &= -sizeof(long); /* residue */
Roland McGratheb9e2e82009-06-02 16:49:22 -0700773 errno = 0;
774 u.val = ptrace(PTRACE_PEEKDATA, pid, (char *) addr, 0);
775 if (errno) {
776 if (started && (errno==EPERM || errno==EIO)) {
777 /* Ran into 'end of memory' - stupid "printpath" */
778 return 0;
779 }
780 /* But if not started, we had a bogus address. */
781 if (addr != 0 && errno != EIO && errno != ESRCH)
782 perror("ptrace: umoven");
783 return -1;
784 }
Wichert Akkerman5daa0281999-03-15 19:49:42 +0000785 started = 1;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000786 memcpy(laddr, &u.x[n], m = MIN(sizeof(long) - n, len));
787 addr += sizeof(long), laddr += m, len -= m;
788 }
789 while (len) {
Roland McGratheb9e2e82009-06-02 16:49:22 -0700790 errno = 0;
791 u.val = ptrace(PTRACE_PEEKDATA, pid, (char *) addr, 0);
792 if (errno) {
793 if (started && (errno==EPERM || errno==EIO)) {
794 /* Ran into 'end of memory' - stupid "printpath" */
795 return 0;
796 }
797 if (addr != 0 && errno != EIO && errno != ESRCH)
798 perror("ptrace: umoven");
799 return -1;
800 }
Wichert Akkerman5daa0281999-03-15 19:49:42 +0000801 started = 1;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000802 memcpy(laddr, u.x, m = MIN(sizeof(long), len));
803 addr += sizeof(long), laddr += m, len -= m;
804 }
805#endif /* LINUX */
806
807#ifdef SUNOS4
808 int pid = tcp->pid;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000809 int n;
810
811 while (len) {
812 n = MIN(len, PAGSIZ);
813 n = MIN(n, ((addr + PAGSIZ) & PAGMASK) - addr);
Roland McGratheb9e2e82009-06-02 16:49:22 -0700814 if (ptrace(PTRACE_READDATA, pid,
815 (char *) addr, len, laddr) < 0) {
816 if (errno != ESRCH) {
817 perror("umoven: ptrace(PTRACE_READDATA, ...)");
818 abort();
819 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000820 return -1;
821 }
822 len -= n;
823 addr += n;
824 laddr += n;
825 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000826#endif /* SUNOS4 */
827
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000828#ifdef USE_PROCFS
Wichert Akkermanea78f0f1999-11-29 15:34:02 +0000829#ifdef HAVE_MP_PROCFS
John Hughesaa09c6b2001-05-15 14:53:43 +0000830 int fd = tcp->pfd_as;
Wichert Akkerman9ce1a631999-08-29 23:15:07 +0000831#else
John Hughesaa09c6b2001-05-15 14:53:43 +0000832 int fd = tcp->pfd;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000833#endif
John Hughesaa09c6b2001-05-15 14:53:43 +0000834 lseek(fd, addr, SEEK_SET);
835 if (read(fd, laddr, len) == -1)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000836 return -1;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000837#endif /* USE_PROCFS */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000838
839 return 0;
840}
841
842/*
843 * like `umove' but make the additional effort of looking
844 * for a terminating zero byte.
845 */
846int
Denys Vlasenkoef2fbf82009-01-06 21:45:06 +0000847umovestr(struct tcb *tcp, long addr, int len, char *laddr)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000848{
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000849#ifdef USE_PROCFS
John Hughesaa09c6b2001-05-15 14:53:43 +0000850#ifdef HAVE_MP_PROCFS
851 int fd = tcp->pfd_as;
852#else
853 int fd = tcp->pfd;
854#endif
855 /* Some systems (e.g. FreeBSD) can be upset if we read off the
856 end of valid memory, avoid this by trying to read up
857 to page boundaries. But we don't know what a page is (and
858 getpagesize(2) (if it exists) doesn't necessarily return
859 hardware page size). Assume all pages >= 1024 (a-historical
860 I know) */
861
862 int page = 1024; /* How to find this? */
863 int move = page - (addr & (page - 1));
864 int left = len;
865
866 lseek(fd, addr, SEEK_SET);
867
868 while (left) {
869 if (move > left) move = left;
John Hughes9cecf7f2001-10-16 10:20:22 +0000870 if ((move = read(fd, laddr, move)) <= 0)
John Hughesaa09c6b2001-05-15 14:53:43 +0000871 return left != len ? 0 : -1;
872 if (memchr (laddr, 0, move)) break;
873 left -= move;
874 laddr += move;
875 addr += move;
876 move = page;
877 }
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000878#else /* !USE_PROCFS */
Wichert Akkerman5daa0281999-03-15 19:49:42 +0000879 int started = 0;
Roland McGratheb9e2e82009-06-02 16:49:22 -0700880 int pid = tcp->pid;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000881 int i, n, m;
882 union {
883 long val;
884 char x[sizeof(long)];
885 } u;
886
887 if (addr & (sizeof(long) - 1)) {
888 /* addr not a multiple of sizeof(long) */
889 n = addr - (addr & -sizeof(long)); /* residue */
890 addr &= -sizeof(long); /* residue */
Roland McGratheb9e2e82009-06-02 16:49:22 -0700891 errno = 0;
892 u.val = ptrace(PTRACE_PEEKDATA, pid, (char *)addr, 0);
893 if (errno) {
894 if (started && (errno==EPERM || errno==EIO)) {
895 /* Ran into 'end of memory' - stupid "printpath" */
896 return 0;
897 }
898 if (addr != 0 && errno != EIO && errno != ESRCH)
899 perror("umovestr");
900 return -1;
901 }
Wichert Akkerman5daa0281999-03-15 19:49:42 +0000902 started = 1;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000903 memcpy(laddr, &u.x[n], m = MIN(sizeof(long)-n,len));
904 while (n & (sizeof(long) - 1))
905 if (u.x[n++] == '\0')
906 return 0;
907 addr += sizeof(long), laddr += m, len -= m;
908 }
909 while (len) {
Roland McGratheb9e2e82009-06-02 16:49:22 -0700910 errno = 0;
911 u.val = ptrace(PTRACE_PEEKDATA, pid, (char *)addr, 0);
912 if (errno) {
913 if (started && (errno==EPERM || errno==EIO)) {
914 /* Ran into 'end of memory' - stupid "printpath" */
915 return 0;
916 }
917 if (addr != 0 && errno != EIO && errno != ESRCH)
918 perror("umovestr");
919 return -1;
920 }
Wichert Akkerman5daa0281999-03-15 19:49:42 +0000921 started = 1;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000922 memcpy(laddr, u.x, m = MIN(sizeof(long), len));
923 for (i = 0; i < sizeof(long); i++)
924 if (u.x[i] == '\0')
925 return 0;
926
927 addr += sizeof(long), laddr += m, len -= m;
928 }
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000929#endif /* !USE_PROCFS */
John Hughesaa09c6b2001-05-15 14:53:43 +0000930 return 0;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000931}
932
933#ifdef LINUX
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +0000934# if !defined (SPARC) && !defined(SPARC64)
935# define PTRACE_WRITETEXT 101
936# define PTRACE_WRITEDATA 102
937# endif /* !SPARC && !SPARC64 */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000938#endif /* LINUX */
939
940#ifdef SUNOS4
941
942static int
Roland McGratheb9e2e82009-06-02 16:49:22 -0700943uload(cmd, pid, addr, len, laddr)
944int cmd;
945int pid;
946long addr;
947int len;
948char *laddr;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000949{
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000950 int peek, poke;
951 int n, m;
952 union {
953 long val;
954 char x[sizeof(long)];
955 } u;
956
957 if (cmd == PTRACE_WRITETEXT) {
958 peek = PTRACE_PEEKTEXT;
959 poke = PTRACE_POKETEXT;
960 }
961 else {
962 peek = PTRACE_PEEKDATA;
963 poke = PTRACE_POKEDATA;
964 }
965 if (addr & (sizeof(long) - 1)) {
966 /* addr not a multiple of sizeof(long) */
967 n = addr - (addr & -sizeof(long)); /* residue */
968 addr &= -sizeof(long);
Roland McGratheb9e2e82009-06-02 16:49:22 -0700969 errno = 0;
970 u.val = ptrace(peek, pid, (char *) addr, 0);
971 if (errno) {
972 perror("uload: POKE");
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000973 return -1;
974 }
Roland McGratheb9e2e82009-06-02 16:49:22 -0700975 memcpy(&u.x[n], laddr, m = MIN(sizeof(long) - n, len));
976 if (ptrace(poke, pid, (char *)addr, u.val) < 0) {
977 perror("uload: POKE");
978 return -1;
979 }
980 addr += sizeof(long), laddr += m, len -= m;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000981 }
982 while (len) {
983 if (len < sizeof(long))
Roland McGratheb9e2e82009-06-02 16:49:22 -0700984 u.val = ptrace(peek, pid, (char *) addr, 0);
985 memcpy(u.x, laddr, m = MIN(sizeof(long), len));
986 if (ptrace(poke, pid, (char *) addr, u.val) < 0) {
987 perror("uload: POKE");
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000988 return -1;
989 }
Roland McGratheb9e2e82009-06-02 16:49:22 -0700990 addr += sizeof(long), laddr += m, len -= m;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000991 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000992 return 0;
993}
994
Roland McGratheb9e2e82009-06-02 16:49:22 -0700995int
996tload(pid, addr, len, laddr)
997int pid;
998int addr, len;
999char *laddr;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001000{
Roland McGratheb9e2e82009-06-02 16:49:22 -07001001 return uload(PTRACE_WRITETEXT, pid, addr, len, laddr);
1002}
1003
1004int
1005dload(pid, addr, len, laddr)
1006int pid;
1007int addr;
1008int len;
1009char *laddr;
1010{
1011 return uload(PTRACE_WRITEDATA, pid, addr, len, laddr);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001012}
1013
1014#endif /* SUNOS4 */
1015
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001016#ifndef USE_PROCFS
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001017
1018int
Roland McGratheb9e2e82009-06-02 16:49:22 -07001019upeek(tcp, off, res)
1020struct tcb *tcp;
1021long off;
1022long *res;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001023{
1024 long val;
1025
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001026# ifdef SUNOS4_KERNEL_ARCH_KLUDGE
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001027 {
1028 static int is_sun4m = -1;
1029 struct utsname name;
1030
1031 /* Round up the usual suspects. */
1032 if (is_sun4m == -1) {
1033 if (uname(&name) < 0) {
1034 perror("upeek: uname?");
1035 exit(1);
1036 }
1037 is_sun4m = strcmp(name.machine, "sun4m") == 0;
1038 if (is_sun4m) {
Roland McGrathd9f816f2004-09-04 03:39:20 +00001039 const struct xlat *x;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001040
1041 for (x = struct_user_offsets; x->str; x++)
1042 x->val += 1024;
1043 }
1044 }
1045 if (is_sun4m)
1046 off += 1024;
1047 }
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001048# endif /* SUNOS4_KERNEL_ARCH_KLUDGE */
Roland McGratheb9e2e82009-06-02 16:49:22 -07001049 errno = 0;
Denys Vlasenko732d1bf2008-12-17 19:21:59 +00001050 val = do_ptrace(PTRACE_PEEKUSER, tcp, (char *) off, 0);
Roland McGratheb9e2e82009-06-02 16:49:22 -07001051 if (val == -1 && errno) {
1052 if (errno != ESRCH) {
1053 char buf[60];
1054 sprintf(buf,"upeek: ptrace(PTRACE_PEEKUSER,%d,%lu,0)", tcp->pid, off);
1055 perror(buf);
1056 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001057 return -1;
Roland McGratheb9e2e82009-06-02 16:49:22 -07001058 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001059 *res = val;
1060 return 0;
1061}
1062
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001063#endif /* !USE_PROCFS */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001064
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001065void
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001066printcall(struct tcb *tcp)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001067{
Roland McGrath7a918832005-02-02 20:55:23 +00001068#define PRINTBADPC tprintf(sizeof(long) == 4 ? "[????????] " : \
1069 sizeof(long) == 8 ? "[????????????????] " : \
1070 NULL /* crash */)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001071
1072#ifdef LINUX
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001073# ifdef I386
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001074 long eip;
1075
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001076 if (upeek(tcp, 4*EIP, &eip) < 0) {
Roland McGrath7a918832005-02-02 20:55:23 +00001077 PRINTBADPC;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001078 return;
1079 }
1080 tprintf("[%08lx] ", eip);
Roland McGratheac26fc2005-02-02 02:48:53 +00001081
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001082# elif defined(S390) || defined(S390X)
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001083 long psw;
Roland McGratheb9e2e82009-06-02 16:49:22 -07001084 if(upeek(tcp,PT_PSWADDR,&psw) < 0) {
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001085 PRINTBADPC;
1086 return;
1087 }
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001088# ifdef S390
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001089 tprintf("[%08lx] ", psw);
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001090# elif S390X
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001091 tprintf("[%16lx] ", psw);
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001092# endif
Roland McGratheac26fc2005-02-02 02:48:53 +00001093
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001094# elif defined(X86_64)
Michal Ludvig0e035502002-09-23 15:41:01 +00001095 long rip;
1096
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001097 if (upeek(tcp, 8*RIP, &rip) < 0) {
Roland McGrath7a918832005-02-02 20:55:23 +00001098 PRINTBADPC;
Michal Ludvig0e035502002-09-23 15:41:01 +00001099 return;
1100 }
1101 tprintf("[%16lx] ", rip);
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001102# elif defined(IA64)
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00001103 long ip;
1104
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001105 if (upeek(tcp, PT_B0, &ip) < 0) {
Roland McGrath7a918832005-02-02 20:55:23 +00001106 PRINTBADPC;
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00001107 return;
1108 }
1109 tprintf("[%08lx] ", ip);
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001110# elif defined(POWERPC)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001111 long pc;
1112
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001113 if (upeek(tcp, sizeof(unsigned long)*PT_NIP, &pc) < 0) {
Andreas Schwabd69fa492010-07-12 21:39:57 +02001114 PRINTBADPC;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001115 return;
1116 }
Andreas Schwabd69fa492010-07-12 21:39:57 +02001117# ifdef POWERPC64
1118 tprintf("[%016lx] ", pc);
1119# else
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001120 tprintf("[%08lx] ", pc);
Andreas Schwabd69fa492010-07-12 21:39:57 +02001121# endif
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001122# elif defined(M68K)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001123 long pc;
1124
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001125 if (upeek(tcp, 4*PT_PC, &pc) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001126 tprintf ("[????????] ");
1127 return;
1128 }
1129 tprintf("[%08lx] ", pc);
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001130# elif defined(ALPHA)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001131 long pc;
1132
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001133 if (upeek(tcp, REG_PC, &pc) < 0) {
Roland McGrath7a918832005-02-02 20:55:23 +00001134 tprintf ("[????????????????] ");
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001135 return;
1136 }
1137 tprintf("[%08lx] ", pc);
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001138# elif defined(SPARC) || defined(SPARC64)
Mike Frysinger8566c502009-10-12 11:05:14 -04001139 struct pt_regs regs;
Roland McGratheb9e2e82009-06-02 16:49:22 -07001140 if (ptrace(PTRACE_GETREGS,tcp->pid,(char *)&regs,0) < 0) {
Roland McGrath7a918832005-02-02 20:55:23 +00001141 PRINTBADPC;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001142 return;
1143 }
Mike Frysinger8566c502009-10-12 11:05:14 -04001144# if defined(SPARC64)
1145 tprintf("[%08lx] ", regs.tpc);
1146# else
1147 tprintf("[%08lx] ", regs.pc);
1148# endif
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001149# elif defined(HPPA)
Wichert Akkermanc1652e22001-03-27 12:17:16 +00001150 long pc;
1151
Roland McGratheb9e2e82009-06-02 16:49:22 -07001152 if(upeek(tcp,PT_IAOQ0,&pc) < 0) {
Wichert Akkermanc1652e22001-03-27 12:17:16 +00001153 tprintf ("[????????] ");
1154 return;
1155 }
1156 tprintf("[%08lx] ", pc);
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001157# elif defined(MIPS)
Wichert Akkerman75c422b2001-04-10 10:22:50 +00001158 long pc;
1159
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001160 if (upeek(tcp, REG_EPC, &pc) < 0) {
Wichert Akkerman75c422b2001-04-10 10:22:50 +00001161 tprintf ("[????????] ");
1162 return;
1163 }
1164 tprintf("[%08lx] ", pc);
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001165# elif defined(SH)
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001166 long pc;
Wichert Akkermanccef6372002-05-01 16:39:22 +00001167
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001168 if (upeek(tcp, 4*REG_PC, &pc) < 0) {
1169 tprintf ("[????????] ");
1170 return;
1171 }
1172 tprintf("[%08lx] ", pc);
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001173# elif defined(SH64)
Roland McGrathe1e584b2003-06-02 19:18:58 +00001174 long pc;
1175
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001176 if (upeek(tcp, REG_PC, &pc) < 0) {
Roland McGrath7a918832005-02-02 20:55:23 +00001177 tprintf ("[????????????????] ");
Roland McGrathe1e584b2003-06-02 19:18:58 +00001178 return;
1179 }
1180 tprintf("[%08lx] ", pc);
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001181# elif defined(ARM)
Roland McGrathef388682003-06-03 23:28:59 +00001182 long pc;
Roland McGrathe1e584b2003-06-02 19:18:58 +00001183
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001184 if (upeek(tcp, 4*15, &pc) < 0) {
Roland McGrath7a918832005-02-02 20:55:23 +00001185 PRINTBADPC;
Roland McGrathef388682003-06-03 23:28:59 +00001186 return;
1187 }
1188 tprintf("[%08lx] ", pc);
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00001189# elif defined(AVR32)
1190 long pc;
1191
1192 if (upeek(tcp, REG_PC, &pc) < 0) {
1193 tprintf("[????????] ");
1194 return;
1195 }
1196 tprintf("[%08lx] ", pc);
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001197# elif defined(BFIN)
Dmitry V. Levin87ea1f42008-11-10 22:21:41 +00001198 long pc;
1199
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001200 if (upeek(tcp, PT_PC, &pc) < 0) {
Dmitry V. Levin87ea1f42008-11-10 22:21:41 +00001201 PRINTBADPC;
1202 return;
1203 }
1204 tprintf("[%08lx] ", pc);
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001205#elif defined(CRISV10)
1206 long pc;
1207
Edgar E. Iglesiaseeb9ce32009-10-05 14:41:02 +00001208 if (upeek(tcp, 4*PT_IRP, &pc) < 0) {
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001209 PRINTBADPC;
1210 return;
1211 }
1212 tprintf("[%08lx] ", pc);
1213#elif defined(CRISV32)
1214 long pc;
1215
Edgar E. Iglesiaseeb9ce32009-10-05 14:41:02 +00001216 if (upeek(tcp, 4*PT_ERP, &pc) < 0) {
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001217 PRINTBADPC;
1218 return;
1219 }
1220 tprintf("[%08lx] ", pc);
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001221# endif /* architecture */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001222#endif /* LINUX */
1223
1224#ifdef SUNOS4
1225 struct regs regs;
1226
Roland McGratheb9e2e82009-06-02 16:49:22 -07001227 if (ptrace(PTRACE_GETREGS, tcp->pid, (char *) &regs, 0) < 0) {
1228 perror("printcall: ptrace(PTRACE_GETREGS, ...)");
Roland McGrath7a918832005-02-02 20:55:23 +00001229 PRINTBADPC;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001230 return;
1231 }
1232 tprintf("[%08x] ", regs.r_o7);
1233#endif /* SUNOS4 */
1234
1235#ifdef SVR4
1236 /* XXX */
Roland McGrath7a918832005-02-02 20:55:23 +00001237 PRINTBADPC;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001238#endif
1239
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001240#ifdef FREEBSD
1241 struct reg regs;
1242 pread(tcp->pfd_reg, &regs, sizeof(regs), 0);
1243 tprintf("[%08x] ", regs.r_eip);
1244#endif /* FREEBSD */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001245}
1246
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001247
1248/*
1249 * These #if's are huge, please indent them correctly.
1250 * It's easy to get confused otherwise.
1251 */
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001252#ifndef USE_PROCFS
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001253
Dmitry V. Levine5e60852009-12-31 22:50:49 +00001254#ifdef LINUX
Roland McGrathd81f1d92003-01-09 06:53:34 +00001255
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001256# include "syscall.h"
Roland McGrath3291ef22008-05-20 00:34:34 +00001257
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001258# include <sys/syscall.h>
1259# ifndef CLONE_PTRACE
1260# define CLONE_PTRACE 0x00002000
1261# endif
1262# ifndef CLONE_VFORK
1263# define CLONE_VFORK 0x00004000
1264# endif
1265# ifndef CLONE_VM
1266# define CLONE_VM 0x00000100
1267# endif
1268# ifndef CLONE_STOPPED
1269# define CLONE_STOPPED 0x02000000
1270# endif
Roland McGrathd81f1d92003-01-09 06:53:34 +00001271
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001272# ifdef IA64
Roland McGrathd81f1d92003-01-09 06:53:34 +00001273
Roland McGrath08267b82004-02-20 22:56:43 +00001274/* We don't have fork()/vfork() syscalls on ia64 itself, but the ia32
1275 subsystem has them for x86... */
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001276# define SYS_fork 2
1277# define SYS_vfork 190
Roland McGrath08267b82004-02-20 22:56:43 +00001278
Roland McGrathd81f1d92003-01-09 06:53:34 +00001279typedef unsigned long *arg_setup_state;
1280
1281static int
1282arg_setup(struct tcb *tcp, arg_setup_state *state)
1283{
Jan Kratochvil1f942712008-08-06 21:38:52 +00001284 unsigned long cfm, sof, sol;
1285 long bsp;
Roland McGrathd81f1d92003-01-09 06:53:34 +00001286
Jan Kratochvil1f942712008-08-06 21:38:52 +00001287 if (ia32) {
1288 /* Satisfy a false GCC warning. */
1289 *state = NULL;
Roland McGrath08267b82004-02-20 22:56:43 +00001290 return 0;
Jan Kratochvil1f942712008-08-06 21:38:52 +00001291 }
Roland McGrath08267b82004-02-20 22:56:43 +00001292
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001293 if (upeek(tcp, PT_AR_BSP, &bsp) < 0)
Roland McGrathd81f1d92003-01-09 06:53:34 +00001294 return -1;
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001295 if (upeek(tcp, PT_CFM, (long *) &cfm) < 0)
Roland McGrathd81f1d92003-01-09 06:53:34 +00001296 return -1;
1297
1298 sof = (cfm >> 0) & 0x7f;
1299 sol = (cfm >> 7) & 0x7f;
Jan Kratochvil1f942712008-08-06 21:38:52 +00001300 bsp = (long) ia64_rse_skip_regs((unsigned long *) bsp, -sof + sol);
Roland McGrathd81f1d92003-01-09 06:53:34 +00001301
Jan Kratochvil1f942712008-08-06 21:38:52 +00001302 *state = (unsigned long *) bsp;
Roland McGrathd81f1d92003-01-09 06:53:34 +00001303 return 0;
1304}
1305
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001306# define arg_finish_change(tcp, state) 0
Roland McGrathd81f1d92003-01-09 06:53:34 +00001307
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001308# ifdef SYS_fork
Roland McGrathd81f1d92003-01-09 06:53:34 +00001309static int
1310get_arg0 (struct tcb *tcp, arg_setup_state *state, long *valp)
1311{
Roland McGrath08267b82004-02-20 22:56:43 +00001312 int ret;
1313
1314 if (ia32)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001315 ret = upeek (tcp, PT_R11, valp);
Roland McGrath08267b82004-02-20 22:56:43 +00001316 else
1317 ret = umoven (tcp,
1318 (unsigned long) ia64_rse_skip_regs(*state, 0),
1319 sizeof(long), (void *) valp);
1320 return ret;
Roland McGrathd81f1d92003-01-09 06:53:34 +00001321}
1322
1323static int
1324get_arg1 (struct tcb *tcp, arg_setup_state *state, long *valp)
1325{
Roland McGrath08267b82004-02-20 22:56:43 +00001326 int ret;
1327
1328 if (ia32)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001329 ret = upeek (tcp, PT_R9, valp);
Roland McGrath08267b82004-02-20 22:56:43 +00001330 else
1331 ret = umoven (tcp,
1332 (unsigned long) ia64_rse_skip_regs(*state, 1),
1333 sizeof(long), (void *) valp);
1334 return ret;
Roland McGrathd81f1d92003-01-09 06:53:34 +00001335}
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001336# endif
Roland McGrathd81f1d92003-01-09 06:53:34 +00001337
1338static int
1339set_arg0 (struct tcb *tcp, arg_setup_state *state, long val)
1340{
Roland McGrath08267b82004-02-20 22:56:43 +00001341 int req = PTRACE_POKEDATA;
1342 void *ap;
1343
1344 if (ia32) {
1345 ap = (void *) (intptr_t) PT_R11; /* r11 == EBX */
1346 req = PTRACE_POKEUSER;
1347 } else
1348 ap = ia64_rse_skip_regs(*state, 0);
Roland McGratheb9e2e82009-06-02 16:49:22 -07001349 errno = 0;
1350 ptrace(req, tcp->pid, ap, val);
1351 return errno ? -1 : 0;
Roland McGrathd81f1d92003-01-09 06:53:34 +00001352}
1353
1354static int
1355set_arg1 (struct tcb *tcp, arg_setup_state *state, long val)
1356{
Roland McGrath08267b82004-02-20 22:56:43 +00001357 int req = PTRACE_POKEDATA;
1358 void *ap;
1359
1360 if (ia32) {
1361 ap = (void *) (intptr_t) PT_R9; /* r9 == ECX */
1362 req = PTRACE_POKEUSER;
1363 } else
1364 ap = ia64_rse_skip_regs(*state, 1);
Roland McGratheb9e2e82009-06-02 16:49:22 -07001365 errno = 0;
1366 ptrace(req, tcp->pid, ap, val);
1367 return errno ? -1 : 0;
Roland McGrathd81f1d92003-01-09 06:53:34 +00001368}
1369
Roland McGrathb659f872008-07-18 01:19:36 +00001370/* ia64 does not return the input arguments from functions (and syscalls)
1371 according to ia64 RSE (Register Stack Engine) behavior. */
1372
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001373# define restore_arg0(tcp, state, val) ((void) (state), 0)
1374# define restore_arg1(tcp, state, val) ((void) (state), 0)
Roland McGrathb659f872008-07-18 01:19:36 +00001375
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001376# elif defined (SPARC) || defined (SPARC64)
Roland McGrathd81f1d92003-01-09 06:53:34 +00001377
Mike Frysinger8566c502009-10-12 11:05:14 -04001378typedef struct pt_regs arg_setup_state;
Roland McGrathd81f1d92003-01-09 06:53:34 +00001379
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001380# define arg_setup(tcp, state) \
Roland McGratheb9e2e82009-06-02 16:49:22 -07001381 (ptrace (PTRACE_GETREGS, tcp->pid, (char *) (state), 0))
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001382# define arg_finish_change(tcp, state) \
Roland McGratheb9e2e82009-06-02 16:49:22 -07001383 (ptrace (PTRACE_SETREGS, tcp->pid, (char *) (state), 0))
Roland McGrathd81f1d92003-01-09 06:53:34 +00001384
Mike Frysinger8566c502009-10-12 11:05:14 -04001385# define get_arg0(tcp, state, valp) (*(valp) = (state)->u_regs[U_REG_O0], 0)
1386# define get_arg1(tcp, state, valp) (*(valp) = (state)->u_regs[U_REG_O1], 0)
1387# define set_arg0(tcp, state, val) ((state)->u_regs[U_REG_O0] = (val), 0)
1388# define set_arg1(tcp, state, val) ((state)->u_regs[U_REG_O1] = (val), 0)
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001389# define restore_arg0(tcp, state, val) 0
Roland McGrathd81f1d92003-01-09 06:53:34 +00001390
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001391# else /* other architectures */
Roland McGrathd81f1d92003-01-09 06:53:34 +00001392
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001393# if defined S390 || defined S390X
Roland McGrath7b308222003-01-20 09:04:36 +00001394/* Note: this is only true for the `clone' system call, which handles
1395 arguments specially. We could as well say that its first two arguments
1396 are swapped relative to other architectures, but that would just be
1397 another #ifdef in the calls. */
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001398# define arg0_offset PT_GPR3
1399# define arg1_offset PT_ORIGGPR2
1400# define restore_arg0(tcp, state, val) ((void) (state), 0)
1401# define restore_arg1(tcp, state, val) ((void) (state), 0)
1402# define arg0_index 1
1403# define arg1_index 0
1404# elif defined (ALPHA) || defined (MIPS)
1405# define arg0_offset REG_A0
1406# define arg1_offset (REG_A0+1)
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00001407# elif defined (AVR32)
1408# define arg0_offset (REG_R12)
1409# define arg1_offset (REG_R11)
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001410# elif defined (POWERPC)
1411# define arg0_offset (sizeof(unsigned long)*PT_R3)
1412# define arg1_offset (sizeof(unsigned long)*PT_R4)
1413# define restore_arg0(tcp, state, val) ((void) (state), 0)
1414# elif defined (HPPA)
1415# define arg0_offset PT_GR26
1416# define arg1_offset (PT_GR26-4)
1417# elif defined (X86_64)
1418# define arg0_offset ((long)(8*(current_personality ? RBX : RDI)))
1419# define arg1_offset ((long)(8*(current_personality ? RCX : RSI)))
1420# elif defined (SH)
1421# define arg0_offset (4*(REG_REG0+4))
1422# define arg1_offset (4*(REG_REG0+5))
1423# elif defined (SH64)
1424 /* ABI defines arg0 & 1 in r2 & r3 */
1425# define arg0_offset (REG_OFFSET+16)
1426# define arg1_offset (REG_OFFSET+24)
1427# define restore_arg0(tcp, state, val) 0
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001428# elif defined CRISV10 || defined CRISV32
1429# define arg0_offset (4*PT_R11)
1430# define arg1_offset (4*PT_ORIG_R10)
1431# define restore_arg0(tcp, state, val) 0
1432# define restore_arg1(tcp, state, val) 0
1433# define arg0_index 1
1434# define arg1_index 0
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001435# else
1436# define arg0_offset 0
1437# define arg1_offset 4
1438# if defined ARM
1439# define restore_arg0(tcp, state, val) 0
1440# endif
1441# endif
Roland McGrathd81f1d92003-01-09 06:53:34 +00001442
1443typedef int arg_setup_state;
1444
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001445# define arg_setup(tcp, state) (0)
1446# define arg_finish_change(tcp, state) 0
1447# define get_arg0(tcp, cookie, valp) \
1448 (upeek ((tcp), arg0_offset, (valp)))
1449# define get_arg1(tcp, cookie, valp) \
1450 (upeek ((tcp), arg1_offset, (valp)))
Roland McGrathd81f1d92003-01-09 06:53:34 +00001451
1452static int
Roland McGratheb9e2e82009-06-02 16:49:22 -07001453set_arg0 (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*)arg0_offset, val);
Roland McGrathd81f1d92003-01-09 06:53:34 +00001456}
1457
1458static int
Roland McGratheb9e2e82009-06-02 16:49:22 -07001459set_arg1 (struct tcb *tcp, void *cookie, long val)
Roland McGrathd81f1d92003-01-09 06:53:34 +00001460{
Roland McGratheb9e2e82009-06-02 16:49:22 -07001461 return ptrace (PTRACE_POKEUSER, tcp->pid, (char*)arg1_offset, val);
Roland McGrathd81f1d92003-01-09 06:53:34 +00001462}
1463
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001464# endif /* architectures */
Roland McGrathd81f1d92003-01-09 06:53:34 +00001465
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001466# ifndef restore_arg0
1467# define restore_arg0(tcp, state, val) set_arg0((tcp), (state), (val))
1468# endif
1469# ifndef restore_arg1
1470# define restore_arg1(tcp, state, val) set_arg1((tcp), (state), (val))
1471# endif
Roland McGrathd81f1d92003-01-09 06:53:34 +00001472
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001473# ifndef arg0_index
1474# define arg0_index 0
1475# define arg1_index 1
1476# endif
Roland McGrath90d0afd2004-03-01 21:05:16 +00001477
Roland McGrathd81f1d92003-01-09 06:53:34 +00001478int
Denys Vlasenko418d66a2009-01-17 01:52:54 +00001479setbpt(struct tcb *tcp)
Roland McGrathd81f1d92003-01-09 06:53:34 +00001480{
Roland McGrath3291ef22008-05-20 00:34:34 +00001481 static int clone_scno[SUPPORTED_PERSONALITIES] = { SYS_clone };
Roland McGrathd81f1d92003-01-09 06:53:34 +00001482 arg_setup_state state;
1483
1484 if (tcp->flags & TCB_BPTSET) {
1485 fprintf(stderr, "PANIC: TCB already set in pid %u\n", tcp->pid);
1486 return -1;
1487 }
1488
Roland McGrath3291ef22008-05-20 00:34:34 +00001489 /*
1490 * It's a silly kludge to initialize this with a search at runtime.
1491 * But it's better than maintaining another magic thing in the
1492 * godforsaken tables.
1493 */
1494 if (clone_scno[current_personality] == 0) {
1495 int i;
1496 for (i = 0; i < nsyscalls; ++i)
1497 if (sysent[i].sys_func == sys_clone) {
1498 clone_scno[current_personality] = i;
1499 break;
1500 }
1501 }
1502
Roland McGrath76989d72005-06-07 23:21:31 +00001503 switch (known_scno(tcp)) {
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001504# ifdef SYS_vfork
Roland McGrath9383c6c2003-01-18 00:19:31 +00001505 case SYS_vfork:
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001506# endif
1507# ifdef SYS_fork
Roland McGrathd81f1d92003-01-09 06:53:34 +00001508 case SYS_fork:
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001509# endif
1510# if defined SYS_fork || defined SYS_vfork
Roland McGrathd81f1d92003-01-09 06:53:34 +00001511 if (arg_setup (tcp, &state) < 0
1512 || get_arg0 (tcp, &state, &tcp->inst[0]) < 0
1513 || get_arg1 (tcp, &state, &tcp->inst[1]) < 0
Roland McGrath3291ef22008-05-20 00:34:34 +00001514 || change_syscall(tcp, clone_scno[current_personality]) < 0
Roland McGrathd81f1d92003-01-09 06:53:34 +00001515 || set_arg0 (tcp, &state, CLONE_PTRACE|SIGCHLD) < 0
1516 || set_arg1 (tcp, &state, 0) < 0
1517 || arg_finish_change (tcp, &state) < 0)
1518 return -1;
Roland McGrathc9dc3c12004-03-01 20:57:09 +00001519 tcp->u_arg[arg0_index] = CLONE_PTRACE|SIGCHLD;
1520 tcp->u_arg[arg1_index] = 0;
Roland McGrathd81f1d92003-01-09 06:53:34 +00001521 tcp->flags |= TCB_BPTSET;
1522 return 0;
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001523# endif
Roland McGrathd81f1d92003-01-09 06:53:34 +00001524
1525 case SYS_clone:
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001526# ifdef SYS_clone2
Roland McGrathd81f1d92003-01-09 06:53:34 +00001527 case SYS_clone2:
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001528# endif
Jan Kratochvil8fc95752008-08-06 21:43:35 +00001529 /* ia64 calls directly `clone (CLONE_VFORK | CLONE_VM)'
1530 contrary to x86 SYS_vfork above. Even on x86 we turn the
1531 vfork semantics into plain fork - each application must not
1532 depend on the vfork specifics according to POSIX. We would
1533 hang waiting for the parent resume otherwise. We need to
1534 clear also CLONE_VM but only in the CLONE_VFORK case as
1535 otherwise we would break pthread_create. */
1536
Roland McGrathd6ff0d52008-07-18 01:09:44 +00001537 if ((arg_setup (tcp, &state) < 0
1538 || set_arg0 (tcp, &state,
1539 (tcp->u_arg[arg0_index] | CLONE_PTRACE)
Jan Kratochvil8fc95752008-08-06 21:43:35 +00001540 & ~(tcp->u_arg[arg0_index] & CLONE_VFORK
1541 ? CLONE_VFORK | CLONE_VM : 0)) < 0
Roland McGrathd6ff0d52008-07-18 01:09:44 +00001542 || arg_finish_change (tcp, &state) < 0))
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00001543 return -1;
Roland McGrathd81f1d92003-01-09 06:53:34 +00001544 tcp->flags |= TCB_BPTSET;
Roland McGrathc9dc3c12004-03-01 20:57:09 +00001545 tcp->inst[0] = tcp->u_arg[arg0_index];
1546 tcp->inst[1] = tcp->u_arg[arg1_index];
Roland McGrathd81f1d92003-01-09 06:53:34 +00001547 return 0;
1548
1549 default:
1550 fprintf(stderr, "PANIC: setbpt for syscall %ld on %u???\n",
1551 tcp->scno, tcp->pid);
1552 break;
1553 }
1554
1555 return -1;
1556}
1557
1558int
1559clearbpt(tcp)
1560struct tcb *tcp;
1561{
1562 arg_setup_state state;
1563 if (arg_setup (tcp, &state) < 0
Roland McGrathe1df47f2003-01-14 09:46:15 +00001564 || restore_arg0 (tcp, &state, tcp->inst[0]) < 0
1565 || restore_arg1 (tcp, &state, tcp->inst[1]) < 0
Roland McGrathd81f1d92003-01-09 06:53:34 +00001566 || arg_finish_change (tcp, &state))
Andreas Schwab46ed50d2009-11-11 13:54:04 +01001567 if (errno != ESRCH) return -1;
Roland McGrathd81f1d92003-01-09 06:53:34 +00001568 tcp->flags &= ~TCB_BPTSET;
1569 return 0;
1570}
1571
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001572# else /* !defined LINUX */
Roland McGrathd81f1d92003-01-09 06:53:34 +00001573
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001574int
1575setbpt(tcp)
1576struct tcb *tcp;
1577{
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001578# ifdef SUNOS4
1579# ifdef SPARC /* This code is slightly sparc specific */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001580
Wichert Akkermane6f876c1999-06-22 15:28:30 +00001581 struct regs regs;
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001582# define BPT 0x91d02001 /* ta 1 */
1583# define LOOP 0x10800000 /* ba 0 */
1584# define LOOPA 0x30800000 /* ba,a 0 */
1585# define NOP 0x01000000
1586# if LOOPA
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001587 static int loopdeloop[1] = {LOOPA};
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001588# else
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001589 static int loopdeloop[2] = {LOOP, NOP};
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001590# endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001591
1592 if (tcp->flags & TCB_BPTSET) {
1593 fprintf(stderr, "PANIC: TCB already set in pid %u\n", tcp->pid);
1594 return -1;
1595 }
Roland McGratheb9e2e82009-06-02 16:49:22 -07001596 if (ptrace(PTRACE_GETREGS, tcp->pid, (char *)&regs, 0) < 0) {
1597 perror("setbpt: ptrace(PTRACE_GETREGS, ...)");
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001598 return -1;
1599 }
1600 tcp->baddr = regs.r_o7 + 8;
Roland McGratheb9e2e82009-06-02 16:49:22 -07001601 if (ptrace(PTRACE_READTEXT, tcp->pid, (char *)tcp->baddr,
1602 sizeof tcp->inst, (char *)tcp->inst) < 0) {
1603 perror("setbpt: ptrace(PTRACE_READTEXT, ...)");
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001604 return -1;
1605 }
1606
1607 /*
1608 * XXX - BRUTAL MODE ON
1609 * We cannot set a real BPT in the child, since it will not be
1610 * traced at the moment it will reach the trap and would probably
1611 * die with a core dump.
1612 * Thus, we are force our way in by taking out two instructions
1613 * and insert an eternal loop in stead, in expectance of the SIGSTOP
1614 * generated by out PTRACE_ATTACH.
1615 * Of cause, if we evaporate ourselves in the middle of all this...
1616 */
Roland McGratheb9e2e82009-06-02 16:49:22 -07001617 if (ptrace(PTRACE_WRITETEXT, tcp->pid, (char *) tcp->baddr,
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001618 sizeof loopdeloop, (char *) loopdeloop) < 0) {
Roland McGratheb9e2e82009-06-02 16:49:22 -07001619 perror("setbpt: ptrace(PTRACE_WRITETEXT, ...)");
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001620 return -1;
1621 }
1622 tcp->flags |= TCB_BPTSET;
1623
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001624# endif /* SPARC */
1625# endif /* SUNOS4 */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001626
1627 return 0;
1628}
1629
1630int
1631clearbpt(tcp)
1632struct tcb *tcp;
1633{
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001634# ifdef SUNOS4
1635# ifdef SPARC
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001636
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001637# if !LOOPA
Wichert Akkermane6f876c1999-06-22 15:28:30 +00001638 struct regs regs;
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001639# endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001640
1641 if (!(tcp->flags & TCB_BPTSET)) {
1642 fprintf(stderr, "PANIC: TCB not set in pid %u\n", tcp->pid);
1643 return -1;
1644 }
Roland McGratheb9e2e82009-06-02 16:49:22 -07001645 if (ptrace(PTRACE_WRITETEXT, tcp->pid, (char *) tcp->baddr,
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001646 sizeof tcp->inst, (char *) tcp->inst) < 0) {
Roland McGratheb9e2e82009-06-02 16:49:22 -07001647 perror("clearbtp: ptrace(PTRACE_WRITETEXT, ...)");
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001648 return -1;
1649 }
1650 tcp->flags &= ~TCB_BPTSET;
1651
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001652# if !LOOPA
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001653 /*
1654 * Since we don't have a single instruction breakpoint, we may have
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001655 * to adjust the program counter after removing our `breakpoint'.
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001656 */
Roland McGratheb9e2e82009-06-02 16:49:22 -07001657 if (ptrace(PTRACE_GETREGS, tcp->pid, (char *)&regs, 0) < 0) {
1658 perror("clearbpt: ptrace(PTRACE_GETREGS, ...)");
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001659 return -1;
1660 }
Roland McGratheb9e2e82009-06-02 16:49:22 -07001661 if ((regs.r_pc < tcp->baddr) ||
1662 (regs.r_pc > tcp->baddr + 4)) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001663 /* The breakpoint has not been reached yet */
1664 if (debug)
1665 fprintf(stderr,
1666 "NOTE: PC not at bpt (pc %#x baddr %#x)\n",
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001667 regs.r_pc, tcp->baddr);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001668 return 0;
1669 }
1670 if (regs.r_pc != tcp->baddr)
1671 if (debug)
1672 fprintf(stderr, "NOTE: PC adjusted (%#x -> %#x\n",
1673 regs.r_pc, tcp->baddr);
1674
1675 regs.r_pc = tcp->baddr;
Roland McGratheb9e2e82009-06-02 16:49:22 -07001676 if (ptrace(PTRACE_SETREGS, tcp->pid, (char *)&regs, 0) < 0) {
1677 perror("clearbpt: ptrace(PTRACE_SETREGS, ...)");
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001678 return -1;
1679 }
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001680# endif /* LOOPA */
1681# endif /* SPARC */
1682# endif /* SUNOS4 */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001683
1684 return 0;
1685}
1686
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001687# endif /* !defined LINUX */
Roland McGrathd81f1d92003-01-09 06:53:34 +00001688
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001689#endif /* !USE_PROCFS */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001690
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001691
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001692#ifdef SUNOS4
1693
1694static int
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001695getex(tcp, hdr)
1696struct tcb *tcp;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001697struct exec *hdr;
1698{
1699 int n;
1700
1701 for (n = 0; n < sizeof *hdr; n += 4) {
1702 long res;
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001703 if (upeek(tcp, uoff(u_exdata) + n, &res) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001704 return -1;
1705 memcpy(((char *) hdr) + n, &res, 4);
1706 }
1707 if (debug) {
1708 fprintf(stderr, "[struct exec: magic: %o version %u Mach %o\n",
1709 hdr->a_magic, hdr->a_toolversion, hdr->a_machtype);
1710 fprintf(stderr, "Text %lu Data %lu Bss %lu Syms %lu Entry %#lx]\n",
1711 hdr->a_text, hdr->a_data, hdr->a_bss, hdr->a_syms, hdr->a_entry);
1712 }
1713 return 0;
1714}
1715
1716int
1717fixvfork(tcp)
1718struct tcb *tcp;
1719{
1720 int pid = tcp->pid;
1721 /*
1722 * Change `vfork' in a freshly exec'ed dynamically linked
1723 * executable's (internal) symbol table to plain old `fork'
1724 */
1725
1726 struct exec hdr;
1727 struct link_dynamic dyn;
1728 struct link_dynamic_2 ld;
1729 char *strtab, *cp;
1730
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001731 if (getex(tcp, &hdr) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001732 return -1;
1733 if (!hdr.a_dynamic)
1734 return -1;
1735
1736 if (umove(tcp, (int) N_DATADDR(hdr), &dyn) < 0) {
1737 fprintf(stderr, "Cannot read DYNAMIC\n");
1738 return -1;
1739 }
1740 if (umove(tcp, (int) dyn.ld_un.ld_2, &ld) < 0) {
1741 fprintf(stderr, "Cannot read link_dynamic_2\n");
1742 return -1;
1743 }
1744 if ((strtab = malloc((unsigned)ld.ld_symb_size)) == NULL) {
Roland McGrath46100d02005-06-01 18:55:42 +00001745 fprintf(stderr, "out of memory\n");
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001746 return -1;
1747 }
Roland McGratheb9e2e82009-06-02 16:49:22 -07001748 if (umoven(tcp, (int)ld.ld_symbols+(int)N_TXTADDR(hdr),
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001749 (int)ld.ld_symb_size, strtab) < 0)
1750 goto err;
1751
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001752 for (cp = strtab; cp < strtab + ld.ld_symb_size; ) {
1753 if (strcmp(cp, "_vfork") == 0) {
1754 if (debug)
1755 fprintf(stderr, "fixvfork: FOUND _vfork\n");
1756 strcpy(cp, "_fork");
1757 break;
1758 }
1759 cp += strlen(cp)+1;
1760 }
1761 if (cp < strtab + ld.ld_symb_size)
1762 /*
1763 * Write entire symbol table back to avoid
1764 * memory alignment bugs in ptrace
1765 */
Roland McGratheb9e2e82009-06-02 16:49:22 -07001766 if (tload(pid, (int)ld.ld_symbols+(int)N_TXTADDR(hdr),
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001767 (int)ld.ld_symb_size, strtab) < 0)
1768 goto err;
1769
1770 free(strtab);
1771 return 0;
1772
1773err:
1774 free(strtab);
1775 return -1;
1776}
1777
1778#endif /* SUNOS4 */