blob: 8704a460e0521df49f583783b9561685ed113a17 [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{
Grant Edwards8a082772011-04-07 20:25:40 +0000421 const char *p;
422
423 if (show_fd_path && (p = getfdpath(tcp, fd)))
424 tprintf("%d<%s>", fd, p);
425 else
426 tprintf("%d", fd);
Dmitry V. Levin31382132011-03-04 05:08:02 +0300427}
428
429void
Roland McGrath6bc12202003-11-13 22:32:27 +0000430printuid(text, uid)
431const char *text;
432unsigned long uid;
433{
434 tprintf("%s", text);
435 tprintf((uid == -1) ? "%ld" : "%lu", uid);
436}
437
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000438static char path[MAXPATHLEN + 1];
439
Dmitry V. Levina501f142008-11-10 23:19:13 +0000440/*
441 * Quote string `instr' of length `size'
442 * Write up to (3 + `size' * 4) bytes to `outstr' buffer.
443 * If `len' < 0, treat `instr' as a NUL-terminated string
444 * and quote at most (`size' - 1) bytes.
445 */
Roland McGrath6d970322007-11-01 23:53:59 +0000446static int
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000447string_quote(const char *instr, char *outstr, int len, int size)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000448{
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000449 const unsigned char *ustr = (const unsigned char *) instr;
450 char *s = outstr;
451 int usehex = 0, c, i;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000452
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000453 if (xflag > 1)
454 usehex = 1;
455 else if (xflag) {
Dmitry V. Levina501f142008-11-10 23:19:13 +0000456 /* Check for presence of symbol which require
457 to hex-quote the whole string. */
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000458 for (i = 0; i < size; ++i) {
459 c = ustr[i];
Dmitry V. Levina501f142008-11-10 23:19:13 +0000460 /* Check for NUL-terminated string. */
461 if (len < 0) {
462 if (c == '\0')
463 break;
464 /* Quote at most size - 1 bytes. */
465 if (i == size - 1)
466 continue;
467 }
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000468 if (!isprint(c) && !isspace(c)) {
469 usehex = 1;
470 break;
471 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000472 }
473 }
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000474
475 *s++ = '\"';
476
477 if (usehex) {
Dmitry V. Levina501f142008-11-10 23:19:13 +0000478 /* Hex-quote the whole string. */
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000479 for (i = 0; i < size; ++i) {
480 c = ustr[i];
Dmitry V. Levina501f142008-11-10 23:19:13 +0000481 /* Check for NUL-terminated string. */
482 if (len < 0) {
483 if (c == '\0')
484 break;
485 /* Quote at most size - 1 bytes. */
486 if (i == size - 1)
487 continue;
488 }
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000489 sprintf(s, "\\x%02x", c);
490 s += 4;
491 }
492 } else {
493 for (i = 0; i < size; ++i) {
494 c = ustr[i];
Dmitry V. Levina501f142008-11-10 23:19:13 +0000495 /* Check for NUL-terminated string. */
496 if (len < 0) {
497 if (c == '\0')
498 break;
499 /* Quote at most size - 1 bytes. */
500 if (i == size - 1)
501 continue;
502 }
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000503 switch (c) {
504 case '\"': case '\\':
505 *s++ = '\\';
506 *s++ = c;
507 break;
508 case '\f':
509 *s++ = '\\';
510 *s++ = 'f';
511 break;
512 case '\n':
513 *s++ = '\\';
514 *s++ = 'n';
515 break;
516 case '\r':
517 *s++ = '\\';
518 *s++ = 'r';
519 break;
520 case '\t':
521 *s++ = '\\';
522 *s++ = 't';
523 break;
524 case '\v':
525 *s++ = '\\';
526 *s++ = 'v';
527 break;
528 default:
529 if (isprint(c))
530 *s++ = c;
531 else if (i + 1 < size
532 && isdigit(ustr[i + 1])) {
533 sprintf(s, "\\%03o", c);
534 s += 4;
535 } else {
536 sprintf(s, "\\%o", c);
537 s += strlen(s);
538 }
539 break;
540 }
541 }
542 }
543
544 *s++ = '\"';
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000545 *s = '\0';
Roland McGrath6d970322007-11-01 23:53:59 +0000546
547 /* Return nonzero if the string was unterminated. */
548 return i == size;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000549}
550
Dmitry V. Levina501f142008-11-10 23:19:13 +0000551/*
552 * Print path string specified by address `addr' and length `n'.
553 * If path length exceeds `n', append `...' to the output.
554 */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000555void
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000556printpathn(struct tcb *tcp, long addr, int n)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000557{
Dmitry V. Levina501f142008-11-10 23:19:13 +0000558 if (!addr) {
Roland McGrath371ed8f2005-02-06 01:55:07 +0000559 tprintf("NULL");
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000560 return;
561 }
562
Dmitry V. Levina501f142008-11-10 23:19:13 +0000563 /* Cap path length to the path buffer size,
564 and NUL-terminate the buffer. */
565 if (n > sizeof path - 1)
566 n = sizeof path - 1;
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000567 path[n] = '\0';
Dmitry V. Levina501f142008-11-10 23:19:13 +0000568
569 /* Fetch one byte more to find out whether path length > n. */
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000570 if (umovestr(tcp, addr, n + 1, path) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000571 tprintf("%#lx", addr);
572 else {
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000573 static char outstr[4*(sizeof path - 1) + sizeof "\"...\""];
574 int trunc = (path[n] != '\0');
575
576 if (trunc)
577 path[n] = '\0';
Dmitry V. Levina501f142008-11-10 23:19:13 +0000578 (void) string_quote(path, outstr, -1, n + 1);
579 if (trunc)
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000580 strcat(outstr, "...");
581 tprintf("%s", outstr);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000582 }
583}
584
585void
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000586printpath(struct tcb *tcp, long addr)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000587{
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000588 printpathn(tcp, addr, sizeof path - 1);
589}
590
Dmitry V. Levina501f142008-11-10 23:19:13 +0000591/*
592 * Print string specified by address `addr' and length `len'.
593 * If `len' < 0, treat the string as a NUL-terminated string.
594 * If string length exceeds `max_strlen', append `...' to the output.
595 */
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000596void
597printstr(struct tcb *tcp, long addr, int len)
598{
599 static char *str = NULL;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000600 static char *outstr;
Roland McGrath6d970322007-11-01 23:53:59 +0000601 int size;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000602
603 if (!addr) {
604 tprintf("NULL");
605 return;
606 }
Dmitry V. Levina501f142008-11-10 23:19:13 +0000607 /* Allocate static buffers if they are not allocated yet. */
608 if (!str)
609 str = malloc(max_strlen + 1);
610 if (!outstr)
611 outstr = malloc(4 * max_strlen + sizeof "\"...\"");
612 if (!str || !outstr) {
613 fprintf(stderr, "out of memory\n");
614 tprintf("%#lx", addr);
615 return;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000616 }
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000617
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000618 if (len < 0) {
Dmitry V. Levina501f142008-11-10 23:19:13 +0000619 /*
620 * Treat as a NUL-terminated string: fetch one byte more
621 * because string_quote() quotes one byte less.
622 */
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000623 size = max_strlen + 1;
Dmitry V. Levina501f142008-11-10 23:19:13 +0000624 str[max_strlen] = '\0';
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000625 if (umovestr(tcp, addr, size, str) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000626 tprintf("%#lx", addr);
627 return;
628 }
629 }
630 else {
Dmitry V. Levina501f142008-11-10 23:19:13 +0000631 size = MIN(len, max_strlen);
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000632 if (umoven(tcp, addr, size, str) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000633 tprintf("%#lx", addr);
634 return;
635 }
636 }
637
Dmitry V. Levina501f142008-11-10 23:19:13 +0000638 if (string_quote(str, outstr, len, size) &&
639 (len < 0 || len > max_strlen))
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000640 strcat(outstr, "...");
Roland McGratha503dcf2007-08-02 02:06:26 +0000641
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000642 tprintf("%s", outstr);
643}
644
John Hughes1d08dcf2001-07-10 13:48:44 +0000645#if HAVE_SYS_UIO_H
646void
647dumpiov(tcp, len, addr)
648struct tcb * tcp;
649int len;
650long addr;
651{
Dmitry V. Levin4ebb4e32006-12-13 17:08:08 +0000652#if defined(LINUX) && SUPPORTED_PERSONALITIES > 1
653 union {
654 struct { u_int32_t base; u_int32_t len; } *iov32;
655 struct { u_int64_t base; u_int64_t len; } *iov64;
656 } iovu;
657#define iov iovu.iov64
658#define sizeof_iov \
659 (personality_wordsize[current_personality] == 4 \
660 ? sizeof(*iovu.iov32) : sizeof(*iovu.iov64))
661#define iov_iov_base(i) \
662 (personality_wordsize[current_personality] == 4 \
663 ? (u_int64_t) iovu.iov32[i].base : iovu.iov64[i].base)
664#define iov_iov_len(i) \
665 (personality_wordsize[current_personality] == 4 \
666 ? (u_int64_t) iovu.iov32[i].len : iovu.iov64[i].len)
667#else
John Hughes1d08dcf2001-07-10 13:48:44 +0000668 struct iovec *iov;
Dmitry V. Levin4ebb4e32006-12-13 17:08:08 +0000669#define sizeof_iov sizeof(*iov)
670#define iov_iov_base(i) iov[i].iov_base
671#define iov_iov_len(i) iov[i].iov_len
672#endif
John Hughes1d08dcf2001-07-10 13:48:44 +0000673 int i;
Roland McGrathaa524c82005-06-01 19:22:06 +0000674 unsigned long size;
John Hughes1d08dcf2001-07-10 13:48:44 +0000675
Dmitry V. Levin4ebb4e32006-12-13 17:08:08 +0000676 size = sizeof_iov * (unsigned long) len;
677 if (size / sizeof_iov != len
678 || (iov = malloc(size)) == NULL) {
Roland McGrathaa524c82005-06-01 19:22:06 +0000679 fprintf(stderr, "out of memory\n");
John Hughes1d08dcf2001-07-10 13:48:44 +0000680 return;
681 }
Roland McGrathaa524c82005-06-01 19:22:06 +0000682 if (umoven(tcp, addr, size, (char *) iov) >= 0) {
John Hughes1d08dcf2001-07-10 13:48:44 +0000683 for (i = 0; i < len; i++) {
Denys Vlasenkoadedb512008-12-30 18:47:55 +0000684 /* include the buffer number to make it easy to
685 * match up the trace with the source */
686 tprintf(" * %lu bytes in buffer %d\n",
687 (unsigned long)iov_iov_len(i), i);
688 dumpstr(tcp, (long) iov_iov_base(i),
689 iov_iov_len(i));
690 }
John Hughes1d08dcf2001-07-10 13:48:44 +0000691 }
692 free((char *) iov);
Dmitry V. Levin4ebb4e32006-12-13 17:08:08 +0000693#undef sizeof_iov
694#undef iov_iov_base
695#undef iov_iov_len
696#undef iov
John Hughes1d08dcf2001-07-10 13:48:44 +0000697}
698#endif
699
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000700void
701dumpstr(tcp, addr, len)
702struct tcb *tcp;
703long addr;
704int len;
705{
706 static int strsize = -1;
707 static unsigned char *str;
708 static char outstr[80];
709 char *s;
710 int i, j;
711
712 if (strsize < len) {
713 if (str)
714 free(str);
715 if ((str = malloc(len)) == NULL) {
Roland McGrath46100d02005-06-01 18:55:42 +0000716 fprintf(stderr, "out of memory\n");
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000717 return;
718 }
719 strsize = len;
720 }
721
722 if (umoven(tcp, addr, len, (char *) str) < 0)
723 return;
724
725 for (i = 0; i < len; i += 16) {
726 s = outstr;
727 sprintf(s, " | %05x ", i);
728 s += 9;
729 for (j = 0; j < 16; j++) {
730 if (j == 8)
731 *s++ = ' ';
732 if (i + j < len) {
733 sprintf(s, " %02x", str[i + j]);
734 s += 3;
735 }
736 else {
737 *s++ = ' '; *s++ = ' '; *s++ = ' ';
738 }
739 }
740 *s++ = ' '; *s++ = ' ';
741 for (j = 0; j < 16; j++) {
742 if (j == 8)
743 *s++ = ' ';
744 if (i + j < len) {
745 if (isprint(str[i + j]))
746 *s++ = str[i + j];
747 else
748 *s++ = '.';
749 }
750 else
751 *s++ = ' ';
752 }
753 tprintf("%s |\n", outstr);
754 }
755}
756
757#define PAGMASK (~(PAGSIZ - 1))
758/*
759 * move `len' bytes of data from process `pid'
760 * at address `addr' to our space at `laddr'
761 */
762int
Denys Vlasenkoef2fbf82009-01-06 21:45:06 +0000763umoven(struct tcb *tcp, long addr, int len, char *laddr)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000764{
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000765#ifdef LINUX
Roland McGratheb9e2e82009-06-02 16:49:22 -0700766 int pid = tcp->pid;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000767 int n, m;
Wichert Akkerman5daa0281999-03-15 19:49:42 +0000768 int started = 0;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000769 union {
770 long val;
771 char x[sizeof(long)];
772 } u;
773
774 if (addr & (sizeof(long) - 1)) {
775 /* addr not a multiple of sizeof(long) */
776 n = addr - (addr & -sizeof(long)); /* residue */
777 addr &= -sizeof(long); /* residue */
Roland McGratheb9e2e82009-06-02 16:49:22 -0700778 errno = 0;
779 u.val = ptrace(PTRACE_PEEKDATA, pid, (char *) addr, 0);
780 if (errno) {
781 if (started && (errno==EPERM || errno==EIO)) {
782 /* Ran into 'end of memory' - stupid "printpath" */
783 return 0;
784 }
785 /* But if not started, we had a bogus address. */
786 if (addr != 0 && errno != EIO && errno != ESRCH)
787 perror("ptrace: umoven");
788 return -1;
789 }
Wichert Akkerman5daa0281999-03-15 19:49:42 +0000790 started = 1;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000791 memcpy(laddr, &u.x[n], m = MIN(sizeof(long) - n, len));
792 addr += sizeof(long), laddr += m, len -= m;
793 }
794 while (len) {
Roland McGratheb9e2e82009-06-02 16:49:22 -0700795 errno = 0;
796 u.val = ptrace(PTRACE_PEEKDATA, pid, (char *) addr, 0);
797 if (errno) {
798 if (started && (errno==EPERM || errno==EIO)) {
799 /* Ran into 'end of memory' - stupid "printpath" */
800 return 0;
801 }
802 if (addr != 0 && errno != EIO && errno != ESRCH)
803 perror("ptrace: umoven");
804 return -1;
805 }
Wichert Akkerman5daa0281999-03-15 19:49:42 +0000806 started = 1;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000807 memcpy(laddr, u.x, m = MIN(sizeof(long), len));
808 addr += sizeof(long), laddr += m, len -= m;
809 }
810#endif /* LINUX */
811
812#ifdef SUNOS4
813 int pid = tcp->pid;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000814 int n;
815
816 while (len) {
817 n = MIN(len, PAGSIZ);
818 n = MIN(n, ((addr + PAGSIZ) & PAGMASK) - addr);
Roland McGratheb9e2e82009-06-02 16:49:22 -0700819 if (ptrace(PTRACE_READDATA, pid,
820 (char *) addr, len, laddr) < 0) {
821 if (errno != ESRCH) {
822 perror("umoven: ptrace(PTRACE_READDATA, ...)");
823 abort();
824 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000825 return -1;
826 }
827 len -= n;
828 addr += n;
829 laddr += n;
830 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000831#endif /* SUNOS4 */
832
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000833#ifdef USE_PROCFS
Wichert Akkermanea78f0f1999-11-29 15:34:02 +0000834#ifdef HAVE_MP_PROCFS
John Hughesaa09c6b2001-05-15 14:53:43 +0000835 int fd = tcp->pfd_as;
Wichert Akkerman9ce1a631999-08-29 23:15:07 +0000836#else
John Hughesaa09c6b2001-05-15 14:53:43 +0000837 int fd = tcp->pfd;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000838#endif
John Hughesaa09c6b2001-05-15 14:53:43 +0000839 lseek(fd, addr, SEEK_SET);
840 if (read(fd, laddr, len) == -1)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000841 return -1;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000842#endif /* USE_PROCFS */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000843
844 return 0;
845}
846
847/*
848 * like `umove' but make the additional effort of looking
849 * for a terminating zero byte.
850 */
851int
Denys Vlasenkoef2fbf82009-01-06 21:45:06 +0000852umovestr(struct tcb *tcp, long addr, int len, char *laddr)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000853{
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000854#ifdef USE_PROCFS
John Hughesaa09c6b2001-05-15 14:53:43 +0000855#ifdef HAVE_MP_PROCFS
856 int fd = tcp->pfd_as;
857#else
858 int fd = tcp->pfd;
859#endif
860 /* Some systems (e.g. FreeBSD) can be upset if we read off the
861 end of valid memory, avoid this by trying to read up
862 to page boundaries. But we don't know what a page is (and
863 getpagesize(2) (if it exists) doesn't necessarily return
864 hardware page size). Assume all pages >= 1024 (a-historical
865 I know) */
866
867 int page = 1024; /* How to find this? */
868 int move = page - (addr & (page - 1));
869 int left = len;
870
871 lseek(fd, addr, SEEK_SET);
872
873 while (left) {
874 if (move > left) move = left;
John Hughes9cecf7f2001-10-16 10:20:22 +0000875 if ((move = read(fd, laddr, move)) <= 0)
John Hughesaa09c6b2001-05-15 14:53:43 +0000876 return left != len ? 0 : -1;
877 if (memchr (laddr, 0, move)) break;
878 left -= move;
879 laddr += move;
880 addr += move;
881 move = page;
882 }
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000883#else /* !USE_PROCFS */
Wichert Akkerman5daa0281999-03-15 19:49:42 +0000884 int started = 0;
Roland McGratheb9e2e82009-06-02 16:49:22 -0700885 int pid = tcp->pid;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000886 int i, n, m;
887 union {
888 long val;
889 char x[sizeof(long)];
890 } u;
891
892 if (addr & (sizeof(long) - 1)) {
893 /* addr not a multiple of sizeof(long) */
894 n = addr - (addr & -sizeof(long)); /* residue */
895 addr &= -sizeof(long); /* residue */
Roland McGratheb9e2e82009-06-02 16:49:22 -0700896 errno = 0;
897 u.val = ptrace(PTRACE_PEEKDATA, pid, (char *)addr, 0);
898 if (errno) {
899 if (started && (errno==EPERM || errno==EIO)) {
900 /* Ran into 'end of memory' - stupid "printpath" */
901 return 0;
902 }
903 if (addr != 0 && errno != EIO && errno != ESRCH)
904 perror("umovestr");
905 return -1;
906 }
Wichert Akkerman5daa0281999-03-15 19:49:42 +0000907 started = 1;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000908 memcpy(laddr, &u.x[n], m = MIN(sizeof(long)-n,len));
909 while (n & (sizeof(long) - 1))
910 if (u.x[n++] == '\0')
911 return 0;
912 addr += sizeof(long), laddr += m, len -= m;
913 }
914 while (len) {
Roland McGratheb9e2e82009-06-02 16:49:22 -0700915 errno = 0;
916 u.val = ptrace(PTRACE_PEEKDATA, pid, (char *)addr, 0);
917 if (errno) {
918 if (started && (errno==EPERM || errno==EIO)) {
919 /* Ran into 'end of memory' - stupid "printpath" */
920 return 0;
921 }
922 if (addr != 0 && errno != EIO && errno != ESRCH)
923 perror("umovestr");
924 return -1;
925 }
Wichert Akkerman5daa0281999-03-15 19:49:42 +0000926 started = 1;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000927 memcpy(laddr, u.x, m = MIN(sizeof(long), len));
928 for (i = 0; i < sizeof(long); i++)
929 if (u.x[i] == '\0')
930 return 0;
931
932 addr += sizeof(long), laddr += m, len -= m;
933 }
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000934#endif /* !USE_PROCFS */
John Hughesaa09c6b2001-05-15 14:53:43 +0000935 return 0;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000936}
937
938#ifdef LINUX
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +0000939# if !defined (SPARC) && !defined(SPARC64)
940# define PTRACE_WRITETEXT 101
941# define PTRACE_WRITEDATA 102
942# endif /* !SPARC && !SPARC64 */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000943#endif /* LINUX */
944
945#ifdef SUNOS4
946
947static int
Roland McGratheb9e2e82009-06-02 16:49:22 -0700948uload(cmd, pid, addr, len, laddr)
949int cmd;
950int pid;
951long addr;
952int len;
953char *laddr;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000954{
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000955 int peek, poke;
956 int n, m;
957 union {
958 long val;
959 char x[sizeof(long)];
960 } u;
961
962 if (cmd == PTRACE_WRITETEXT) {
963 peek = PTRACE_PEEKTEXT;
964 poke = PTRACE_POKETEXT;
965 }
966 else {
967 peek = PTRACE_PEEKDATA;
968 poke = PTRACE_POKEDATA;
969 }
970 if (addr & (sizeof(long) - 1)) {
971 /* addr not a multiple of sizeof(long) */
972 n = addr - (addr & -sizeof(long)); /* residue */
973 addr &= -sizeof(long);
Roland McGratheb9e2e82009-06-02 16:49:22 -0700974 errno = 0;
975 u.val = ptrace(peek, pid, (char *) addr, 0);
976 if (errno) {
977 perror("uload: POKE");
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000978 return -1;
979 }
Roland McGratheb9e2e82009-06-02 16:49:22 -0700980 memcpy(&u.x[n], laddr, m = MIN(sizeof(long) - n, len));
981 if (ptrace(poke, pid, (char *)addr, u.val) < 0) {
982 perror("uload: POKE");
983 return -1;
984 }
985 addr += sizeof(long), laddr += m, len -= m;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000986 }
987 while (len) {
988 if (len < sizeof(long))
Roland McGratheb9e2e82009-06-02 16:49:22 -0700989 u.val = ptrace(peek, pid, (char *) addr, 0);
990 memcpy(u.x, laddr, m = MIN(sizeof(long), len));
991 if (ptrace(poke, pid, (char *) addr, u.val) < 0) {
992 perror("uload: POKE");
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000993 return -1;
994 }
Roland McGratheb9e2e82009-06-02 16:49:22 -0700995 addr += sizeof(long), laddr += m, len -= m;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000996 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000997 return 0;
998}
999
Roland McGratheb9e2e82009-06-02 16:49:22 -07001000int
1001tload(pid, addr, len, laddr)
1002int pid;
1003int addr, len;
1004char *laddr;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001005{
Roland McGratheb9e2e82009-06-02 16:49:22 -07001006 return uload(PTRACE_WRITETEXT, pid, addr, len, laddr);
1007}
1008
1009int
1010dload(pid, addr, len, laddr)
1011int pid;
1012int addr;
1013int len;
1014char *laddr;
1015{
1016 return uload(PTRACE_WRITEDATA, pid, addr, len, laddr);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001017}
1018
1019#endif /* SUNOS4 */
1020
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001021#ifndef USE_PROCFS
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001022
1023int
Roland McGratheb9e2e82009-06-02 16:49:22 -07001024upeek(tcp, off, res)
1025struct tcb *tcp;
1026long off;
1027long *res;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001028{
1029 long val;
1030
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001031# ifdef SUNOS4_KERNEL_ARCH_KLUDGE
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001032 {
1033 static int is_sun4m = -1;
1034 struct utsname name;
1035
1036 /* Round up the usual suspects. */
1037 if (is_sun4m == -1) {
1038 if (uname(&name) < 0) {
1039 perror("upeek: uname?");
1040 exit(1);
1041 }
1042 is_sun4m = strcmp(name.machine, "sun4m") == 0;
1043 if (is_sun4m) {
Roland McGrathd9f816f2004-09-04 03:39:20 +00001044 const struct xlat *x;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001045
1046 for (x = struct_user_offsets; x->str; x++)
1047 x->val += 1024;
1048 }
1049 }
1050 if (is_sun4m)
1051 off += 1024;
1052 }
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001053# endif /* SUNOS4_KERNEL_ARCH_KLUDGE */
Roland McGratheb9e2e82009-06-02 16:49:22 -07001054 errno = 0;
Denys Vlasenko732d1bf2008-12-17 19:21:59 +00001055 val = do_ptrace(PTRACE_PEEKUSER, tcp, (char *) off, 0);
Roland McGratheb9e2e82009-06-02 16:49:22 -07001056 if (val == -1 && errno) {
1057 if (errno != ESRCH) {
1058 char buf[60];
1059 sprintf(buf,"upeek: ptrace(PTRACE_PEEKUSER,%d,%lu,0)", tcp->pid, off);
1060 perror(buf);
1061 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001062 return -1;
Roland McGratheb9e2e82009-06-02 16:49:22 -07001063 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001064 *res = val;
1065 return 0;
1066}
1067
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001068#endif /* !USE_PROCFS */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001069
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001070void
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001071printcall(struct tcb *tcp)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001072{
Roland McGrath7a918832005-02-02 20:55:23 +00001073#define PRINTBADPC tprintf(sizeof(long) == 4 ? "[????????] " : \
1074 sizeof(long) == 8 ? "[????????????????] " : \
1075 NULL /* crash */)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001076
1077#ifdef LINUX
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001078# ifdef I386
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001079 long eip;
1080
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001081 if (upeek(tcp, 4*EIP, &eip) < 0) {
Roland McGrath7a918832005-02-02 20:55:23 +00001082 PRINTBADPC;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001083 return;
1084 }
1085 tprintf("[%08lx] ", eip);
Roland McGratheac26fc2005-02-02 02:48:53 +00001086
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001087# elif defined(S390) || defined(S390X)
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001088 long psw;
Roland McGratheb9e2e82009-06-02 16:49:22 -07001089 if(upeek(tcp,PT_PSWADDR,&psw) < 0) {
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001090 PRINTBADPC;
1091 return;
1092 }
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001093# ifdef S390
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001094 tprintf("[%08lx] ", psw);
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001095# elif S390X
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001096 tprintf("[%16lx] ", psw);
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001097# endif
Roland McGratheac26fc2005-02-02 02:48:53 +00001098
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001099# elif defined(X86_64)
Michal Ludvig0e035502002-09-23 15:41:01 +00001100 long rip;
1101
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001102 if (upeek(tcp, 8*RIP, &rip) < 0) {
Roland McGrath7a918832005-02-02 20:55:23 +00001103 PRINTBADPC;
Michal Ludvig0e035502002-09-23 15:41:01 +00001104 return;
1105 }
1106 tprintf("[%16lx] ", rip);
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001107# elif defined(IA64)
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00001108 long ip;
1109
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001110 if (upeek(tcp, PT_B0, &ip) < 0) {
Roland McGrath7a918832005-02-02 20:55:23 +00001111 PRINTBADPC;
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00001112 return;
1113 }
1114 tprintf("[%08lx] ", ip);
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001115# elif defined(POWERPC)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001116 long pc;
1117
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001118 if (upeek(tcp, sizeof(unsigned long)*PT_NIP, &pc) < 0) {
Andreas Schwabd69fa492010-07-12 21:39:57 +02001119 PRINTBADPC;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001120 return;
1121 }
Andreas Schwabd69fa492010-07-12 21:39:57 +02001122# ifdef POWERPC64
1123 tprintf("[%016lx] ", pc);
1124# else
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001125 tprintf("[%08lx] ", pc);
Andreas Schwabd69fa492010-07-12 21:39:57 +02001126# endif
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001127# elif defined(M68K)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001128 long pc;
1129
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001130 if (upeek(tcp, 4*PT_PC, &pc) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001131 tprintf ("[????????] ");
1132 return;
1133 }
1134 tprintf("[%08lx] ", pc);
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001135# elif defined(ALPHA)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001136 long pc;
1137
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001138 if (upeek(tcp, REG_PC, &pc) < 0) {
Roland McGrath7a918832005-02-02 20:55:23 +00001139 tprintf ("[????????????????] ");
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001140 return;
1141 }
1142 tprintf("[%08lx] ", pc);
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001143# elif defined(SPARC) || defined(SPARC64)
Mike Frysinger8566c502009-10-12 11:05:14 -04001144 struct pt_regs regs;
Roland McGratheb9e2e82009-06-02 16:49:22 -07001145 if (ptrace(PTRACE_GETREGS,tcp->pid,(char *)&regs,0) < 0) {
Roland McGrath7a918832005-02-02 20:55:23 +00001146 PRINTBADPC;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001147 return;
1148 }
Mike Frysinger8566c502009-10-12 11:05:14 -04001149# if defined(SPARC64)
1150 tprintf("[%08lx] ", regs.tpc);
1151# else
1152 tprintf("[%08lx] ", regs.pc);
1153# endif
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001154# elif defined(HPPA)
Wichert Akkermanc1652e22001-03-27 12:17:16 +00001155 long pc;
1156
Roland McGratheb9e2e82009-06-02 16:49:22 -07001157 if(upeek(tcp,PT_IAOQ0,&pc) < 0) {
Wichert Akkermanc1652e22001-03-27 12:17:16 +00001158 tprintf ("[????????] ");
1159 return;
1160 }
1161 tprintf("[%08lx] ", pc);
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001162# elif defined(MIPS)
Wichert Akkerman75c422b2001-04-10 10:22:50 +00001163 long pc;
1164
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001165 if (upeek(tcp, REG_EPC, &pc) < 0) {
Wichert Akkerman75c422b2001-04-10 10:22:50 +00001166 tprintf ("[????????] ");
1167 return;
1168 }
1169 tprintf("[%08lx] ", pc);
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001170# elif defined(SH)
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001171 long pc;
Wichert Akkermanccef6372002-05-01 16:39:22 +00001172
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001173 if (upeek(tcp, 4*REG_PC, &pc) < 0) {
1174 tprintf ("[????????] ");
1175 return;
1176 }
1177 tprintf("[%08lx] ", pc);
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001178# elif defined(SH64)
Roland McGrathe1e584b2003-06-02 19:18:58 +00001179 long pc;
1180
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001181 if (upeek(tcp, REG_PC, &pc) < 0) {
Roland McGrath7a918832005-02-02 20:55:23 +00001182 tprintf ("[????????????????] ");
Roland McGrathe1e584b2003-06-02 19:18:58 +00001183 return;
1184 }
1185 tprintf("[%08lx] ", pc);
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001186# elif defined(ARM)
Roland McGrathef388682003-06-03 23:28:59 +00001187 long pc;
Roland McGrathe1e584b2003-06-02 19:18:58 +00001188
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001189 if (upeek(tcp, 4*15, &pc) < 0) {
Roland McGrath7a918832005-02-02 20:55:23 +00001190 PRINTBADPC;
Roland McGrathef388682003-06-03 23:28:59 +00001191 return;
1192 }
1193 tprintf("[%08lx] ", pc);
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00001194# elif defined(AVR32)
1195 long pc;
1196
1197 if (upeek(tcp, REG_PC, &pc) < 0) {
1198 tprintf("[????????] ");
1199 return;
1200 }
1201 tprintf("[%08lx] ", pc);
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001202# elif defined(BFIN)
Dmitry V. Levin87ea1f42008-11-10 22:21:41 +00001203 long pc;
1204
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001205 if (upeek(tcp, PT_PC, &pc) < 0) {
Dmitry V. Levin87ea1f42008-11-10 22:21:41 +00001206 PRINTBADPC;
1207 return;
1208 }
1209 tprintf("[%08lx] ", pc);
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001210#elif defined(CRISV10)
1211 long pc;
1212
Edgar E. Iglesiaseeb9ce32009-10-05 14:41:02 +00001213 if (upeek(tcp, 4*PT_IRP, &pc) < 0) {
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001214 PRINTBADPC;
1215 return;
1216 }
1217 tprintf("[%08lx] ", pc);
1218#elif defined(CRISV32)
1219 long pc;
1220
Edgar E. Iglesiaseeb9ce32009-10-05 14:41:02 +00001221 if (upeek(tcp, 4*PT_ERP, &pc) < 0) {
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001222 PRINTBADPC;
1223 return;
1224 }
1225 tprintf("[%08lx] ", pc);
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001226# endif /* architecture */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001227#endif /* LINUX */
1228
1229#ifdef SUNOS4
1230 struct regs regs;
1231
Roland McGratheb9e2e82009-06-02 16:49:22 -07001232 if (ptrace(PTRACE_GETREGS, tcp->pid, (char *) &regs, 0) < 0) {
1233 perror("printcall: ptrace(PTRACE_GETREGS, ...)");
Roland McGrath7a918832005-02-02 20:55:23 +00001234 PRINTBADPC;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001235 return;
1236 }
1237 tprintf("[%08x] ", regs.r_o7);
1238#endif /* SUNOS4 */
1239
1240#ifdef SVR4
1241 /* XXX */
Roland McGrath7a918832005-02-02 20:55:23 +00001242 PRINTBADPC;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001243#endif
1244
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001245#ifdef FREEBSD
1246 struct reg regs;
1247 pread(tcp->pfd_reg, &regs, sizeof(regs), 0);
1248 tprintf("[%08x] ", regs.r_eip);
1249#endif /* FREEBSD */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001250}
1251
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001252
1253/*
1254 * These #if's are huge, please indent them correctly.
1255 * It's easy to get confused otherwise.
1256 */
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001257#ifndef USE_PROCFS
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001258
Dmitry V. Levine5e60852009-12-31 22:50:49 +00001259#ifdef LINUX
Roland McGrathd81f1d92003-01-09 06:53:34 +00001260
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001261# include "syscall.h"
Roland McGrath3291ef22008-05-20 00:34:34 +00001262
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001263# include <sys/syscall.h>
1264# ifndef CLONE_PTRACE
1265# define CLONE_PTRACE 0x00002000
1266# endif
1267# ifndef CLONE_VFORK
1268# define CLONE_VFORK 0x00004000
1269# endif
1270# ifndef CLONE_VM
1271# define CLONE_VM 0x00000100
1272# endif
1273# ifndef CLONE_STOPPED
1274# define CLONE_STOPPED 0x02000000
1275# endif
Roland McGrathd81f1d92003-01-09 06:53:34 +00001276
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001277# ifdef IA64
Roland McGrathd81f1d92003-01-09 06:53:34 +00001278
Roland McGrath08267b82004-02-20 22:56:43 +00001279/* We don't have fork()/vfork() syscalls on ia64 itself, but the ia32
1280 subsystem has them for x86... */
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001281# define SYS_fork 2
1282# define SYS_vfork 190
Roland McGrath08267b82004-02-20 22:56:43 +00001283
Roland McGrathd81f1d92003-01-09 06:53:34 +00001284typedef unsigned long *arg_setup_state;
1285
1286static int
1287arg_setup(struct tcb *tcp, arg_setup_state *state)
1288{
Jan Kratochvil1f942712008-08-06 21:38:52 +00001289 unsigned long cfm, sof, sol;
1290 long bsp;
Roland McGrathd81f1d92003-01-09 06:53:34 +00001291
Jan Kratochvil1f942712008-08-06 21:38:52 +00001292 if (ia32) {
1293 /* Satisfy a false GCC warning. */
1294 *state = NULL;
Roland McGrath08267b82004-02-20 22:56:43 +00001295 return 0;
Jan Kratochvil1f942712008-08-06 21:38:52 +00001296 }
Roland McGrath08267b82004-02-20 22:56:43 +00001297
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001298 if (upeek(tcp, PT_AR_BSP, &bsp) < 0)
Roland McGrathd81f1d92003-01-09 06:53:34 +00001299 return -1;
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001300 if (upeek(tcp, PT_CFM, (long *) &cfm) < 0)
Roland McGrathd81f1d92003-01-09 06:53:34 +00001301 return -1;
1302
1303 sof = (cfm >> 0) & 0x7f;
1304 sol = (cfm >> 7) & 0x7f;
Jan Kratochvil1f942712008-08-06 21:38:52 +00001305 bsp = (long) ia64_rse_skip_regs((unsigned long *) bsp, -sof + sol);
Roland McGrathd81f1d92003-01-09 06:53:34 +00001306
Jan Kratochvil1f942712008-08-06 21:38:52 +00001307 *state = (unsigned long *) bsp;
Roland McGrathd81f1d92003-01-09 06:53:34 +00001308 return 0;
1309}
1310
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001311# define arg_finish_change(tcp, state) 0
Roland McGrathd81f1d92003-01-09 06:53:34 +00001312
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001313# ifdef SYS_fork
Roland McGrathd81f1d92003-01-09 06:53:34 +00001314static int
1315get_arg0 (struct tcb *tcp, arg_setup_state *state, long *valp)
1316{
Roland McGrath08267b82004-02-20 22:56:43 +00001317 int ret;
1318
1319 if (ia32)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001320 ret = upeek (tcp, PT_R11, valp);
Roland McGrath08267b82004-02-20 22:56:43 +00001321 else
1322 ret = umoven (tcp,
1323 (unsigned long) ia64_rse_skip_regs(*state, 0),
1324 sizeof(long), (void *) valp);
1325 return ret;
Roland McGrathd81f1d92003-01-09 06:53:34 +00001326}
1327
1328static int
1329get_arg1 (struct tcb *tcp, arg_setup_state *state, long *valp)
1330{
Roland McGrath08267b82004-02-20 22:56:43 +00001331 int ret;
1332
1333 if (ia32)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001334 ret = upeek (tcp, PT_R9, valp);
Roland McGrath08267b82004-02-20 22:56:43 +00001335 else
1336 ret = umoven (tcp,
1337 (unsigned long) ia64_rse_skip_regs(*state, 1),
1338 sizeof(long), (void *) valp);
1339 return ret;
Roland McGrathd81f1d92003-01-09 06:53:34 +00001340}
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001341# endif
Roland McGrathd81f1d92003-01-09 06:53:34 +00001342
1343static int
1344set_arg0 (struct tcb *tcp, arg_setup_state *state, long val)
1345{
Roland McGrath08267b82004-02-20 22:56:43 +00001346 int req = PTRACE_POKEDATA;
1347 void *ap;
1348
1349 if (ia32) {
1350 ap = (void *) (intptr_t) PT_R11; /* r11 == EBX */
1351 req = PTRACE_POKEUSER;
1352 } else
1353 ap = ia64_rse_skip_regs(*state, 0);
Roland McGratheb9e2e82009-06-02 16:49:22 -07001354 errno = 0;
1355 ptrace(req, tcp->pid, ap, val);
1356 return errno ? -1 : 0;
Roland McGrathd81f1d92003-01-09 06:53:34 +00001357}
1358
1359static int
1360set_arg1 (struct tcb *tcp, arg_setup_state *state, long val)
1361{
Roland McGrath08267b82004-02-20 22:56:43 +00001362 int req = PTRACE_POKEDATA;
1363 void *ap;
1364
1365 if (ia32) {
1366 ap = (void *) (intptr_t) PT_R9; /* r9 == ECX */
1367 req = PTRACE_POKEUSER;
1368 } else
1369 ap = ia64_rse_skip_regs(*state, 1);
Roland McGratheb9e2e82009-06-02 16:49:22 -07001370 errno = 0;
1371 ptrace(req, tcp->pid, ap, val);
1372 return errno ? -1 : 0;
Roland McGrathd81f1d92003-01-09 06:53:34 +00001373}
1374
Roland McGrathb659f872008-07-18 01:19:36 +00001375/* ia64 does not return the input arguments from functions (and syscalls)
1376 according to ia64 RSE (Register Stack Engine) behavior. */
1377
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001378# define restore_arg0(tcp, state, val) ((void) (state), 0)
1379# define restore_arg1(tcp, state, val) ((void) (state), 0)
Roland McGrathb659f872008-07-18 01:19:36 +00001380
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001381# elif defined (SPARC) || defined (SPARC64)
Roland McGrathd81f1d92003-01-09 06:53:34 +00001382
Mike Frysinger8566c502009-10-12 11:05:14 -04001383typedef struct pt_regs arg_setup_state;
Roland McGrathd81f1d92003-01-09 06:53:34 +00001384
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001385# define arg_setup(tcp, state) \
Roland McGratheb9e2e82009-06-02 16:49:22 -07001386 (ptrace (PTRACE_GETREGS, tcp->pid, (char *) (state), 0))
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001387# define arg_finish_change(tcp, state) \
Roland McGratheb9e2e82009-06-02 16:49:22 -07001388 (ptrace (PTRACE_SETREGS, tcp->pid, (char *) (state), 0))
Roland McGrathd81f1d92003-01-09 06:53:34 +00001389
Mike Frysinger8566c502009-10-12 11:05:14 -04001390# define get_arg0(tcp, state, valp) (*(valp) = (state)->u_regs[U_REG_O0], 0)
1391# define get_arg1(tcp, state, valp) (*(valp) = (state)->u_regs[U_REG_O1], 0)
1392# define set_arg0(tcp, state, val) ((state)->u_regs[U_REG_O0] = (val), 0)
1393# define set_arg1(tcp, state, val) ((state)->u_regs[U_REG_O1] = (val), 0)
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001394# define restore_arg0(tcp, state, val) 0
Roland McGrathd81f1d92003-01-09 06:53:34 +00001395
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001396# else /* other architectures */
Roland McGrathd81f1d92003-01-09 06:53:34 +00001397
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001398# if defined S390 || defined S390X
Roland McGrath7b308222003-01-20 09:04:36 +00001399/* Note: this is only true for the `clone' system call, which handles
1400 arguments specially. We could as well say that its first two arguments
1401 are swapped relative to other architectures, but that would just be
1402 another #ifdef in the calls. */
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001403# define arg0_offset PT_GPR3
1404# define arg1_offset PT_ORIGGPR2
1405# define restore_arg0(tcp, state, val) ((void) (state), 0)
1406# define restore_arg1(tcp, state, val) ((void) (state), 0)
1407# define arg0_index 1
1408# define arg1_index 0
1409# elif defined (ALPHA) || defined (MIPS)
1410# define arg0_offset REG_A0
1411# define arg1_offset (REG_A0+1)
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00001412# elif defined (AVR32)
1413# define arg0_offset (REG_R12)
1414# define arg1_offset (REG_R11)
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001415# elif defined (POWERPC)
1416# define arg0_offset (sizeof(unsigned long)*PT_R3)
1417# define arg1_offset (sizeof(unsigned long)*PT_R4)
1418# define restore_arg0(tcp, state, val) ((void) (state), 0)
1419# elif defined (HPPA)
1420# define arg0_offset PT_GR26
1421# define arg1_offset (PT_GR26-4)
1422# elif defined (X86_64)
1423# define arg0_offset ((long)(8*(current_personality ? RBX : RDI)))
1424# define arg1_offset ((long)(8*(current_personality ? RCX : RSI)))
1425# elif defined (SH)
1426# define arg0_offset (4*(REG_REG0+4))
1427# define arg1_offset (4*(REG_REG0+5))
1428# elif defined (SH64)
1429 /* ABI defines arg0 & 1 in r2 & r3 */
1430# define arg0_offset (REG_OFFSET+16)
1431# define arg1_offset (REG_OFFSET+24)
1432# define restore_arg0(tcp, state, val) 0
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001433# elif defined CRISV10 || defined CRISV32
1434# define arg0_offset (4*PT_R11)
1435# define arg1_offset (4*PT_ORIG_R10)
1436# define restore_arg0(tcp, state, val) 0
1437# define restore_arg1(tcp, state, val) 0
1438# define arg0_index 1
1439# define arg1_index 0
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001440# else
1441# define arg0_offset 0
1442# define arg1_offset 4
1443# if defined ARM
1444# define restore_arg0(tcp, state, val) 0
1445# endif
1446# endif
Roland McGrathd81f1d92003-01-09 06:53:34 +00001447
1448typedef int arg_setup_state;
1449
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001450# define arg_setup(tcp, state) (0)
1451# define arg_finish_change(tcp, state) 0
1452# define get_arg0(tcp, cookie, valp) \
1453 (upeek ((tcp), arg0_offset, (valp)))
1454# define get_arg1(tcp, cookie, valp) \
1455 (upeek ((tcp), arg1_offset, (valp)))
Roland McGrathd81f1d92003-01-09 06:53:34 +00001456
1457static int
Roland McGratheb9e2e82009-06-02 16:49:22 -07001458set_arg0 (struct tcb *tcp, void *cookie, long val)
Roland McGrathd81f1d92003-01-09 06:53:34 +00001459{
Roland McGratheb9e2e82009-06-02 16:49:22 -07001460 return ptrace (PTRACE_POKEUSER, tcp->pid, (char*)arg0_offset, val);
Roland McGrathd81f1d92003-01-09 06:53:34 +00001461}
1462
1463static int
Roland McGratheb9e2e82009-06-02 16:49:22 -07001464set_arg1 (struct tcb *tcp, void *cookie, long val)
Roland McGrathd81f1d92003-01-09 06:53:34 +00001465{
Roland McGratheb9e2e82009-06-02 16:49:22 -07001466 return ptrace (PTRACE_POKEUSER, tcp->pid, (char*)arg1_offset, val);
Roland McGrathd81f1d92003-01-09 06:53:34 +00001467}
1468
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001469# endif /* architectures */
Roland McGrathd81f1d92003-01-09 06:53:34 +00001470
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001471# ifndef restore_arg0
1472# define restore_arg0(tcp, state, val) set_arg0((tcp), (state), (val))
1473# endif
1474# ifndef restore_arg1
1475# define restore_arg1(tcp, state, val) set_arg1((tcp), (state), (val))
1476# endif
Roland McGrathd81f1d92003-01-09 06:53:34 +00001477
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001478# ifndef arg0_index
1479# define arg0_index 0
1480# define arg1_index 1
1481# endif
Roland McGrath90d0afd2004-03-01 21:05:16 +00001482
Roland McGrathd81f1d92003-01-09 06:53:34 +00001483int
Denys Vlasenko418d66a2009-01-17 01:52:54 +00001484setbpt(struct tcb *tcp)
Roland McGrathd81f1d92003-01-09 06:53:34 +00001485{
Roland McGrath3291ef22008-05-20 00:34:34 +00001486 static int clone_scno[SUPPORTED_PERSONALITIES] = { SYS_clone };
Roland McGrathd81f1d92003-01-09 06:53:34 +00001487 arg_setup_state state;
1488
1489 if (tcp->flags & TCB_BPTSET) {
1490 fprintf(stderr, "PANIC: TCB already set in pid %u\n", tcp->pid);
1491 return -1;
1492 }
1493
Roland McGrath3291ef22008-05-20 00:34:34 +00001494 /*
1495 * It's a silly kludge to initialize this with a search at runtime.
1496 * But it's better than maintaining another magic thing in the
1497 * godforsaken tables.
1498 */
1499 if (clone_scno[current_personality] == 0) {
1500 int i;
1501 for (i = 0; i < nsyscalls; ++i)
1502 if (sysent[i].sys_func == sys_clone) {
1503 clone_scno[current_personality] = i;
1504 break;
1505 }
1506 }
1507
Roland McGrath76989d72005-06-07 23:21:31 +00001508 switch (known_scno(tcp)) {
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001509# ifdef SYS_vfork
Roland McGrath9383c6c2003-01-18 00:19:31 +00001510 case SYS_vfork:
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001511# endif
1512# ifdef SYS_fork
Roland McGrathd81f1d92003-01-09 06:53:34 +00001513 case SYS_fork:
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001514# endif
1515# if defined SYS_fork || defined SYS_vfork
Roland McGrathd81f1d92003-01-09 06:53:34 +00001516 if (arg_setup (tcp, &state) < 0
1517 || get_arg0 (tcp, &state, &tcp->inst[0]) < 0
1518 || get_arg1 (tcp, &state, &tcp->inst[1]) < 0
Roland McGrath3291ef22008-05-20 00:34:34 +00001519 || change_syscall(tcp, clone_scno[current_personality]) < 0
Roland McGrathd81f1d92003-01-09 06:53:34 +00001520 || set_arg0 (tcp, &state, CLONE_PTRACE|SIGCHLD) < 0
1521 || set_arg1 (tcp, &state, 0) < 0
1522 || arg_finish_change (tcp, &state) < 0)
1523 return -1;
Roland McGrathc9dc3c12004-03-01 20:57:09 +00001524 tcp->u_arg[arg0_index] = CLONE_PTRACE|SIGCHLD;
1525 tcp->u_arg[arg1_index] = 0;
Roland McGrathd81f1d92003-01-09 06:53:34 +00001526 tcp->flags |= TCB_BPTSET;
1527 return 0;
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001528# endif
Roland McGrathd81f1d92003-01-09 06:53:34 +00001529
1530 case SYS_clone:
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001531# ifdef SYS_clone2
Roland McGrathd81f1d92003-01-09 06:53:34 +00001532 case SYS_clone2:
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001533# endif
Jan Kratochvil8fc95752008-08-06 21:43:35 +00001534 /* ia64 calls directly `clone (CLONE_VFORK | CLONE_VM)'
1535 contrary to x86 SYS_vfork above. Even on x86 we turn the
1536 vfork semantics into plain fork - each application must not
1537 depend on the vfork specifics according to POSIX. We would
1538 hang waiting for the parent resume otherwise. We need to
1539 clear also CLONE_VM but only in the CLONE_VFORK case as
1540 otherwise we would break pthread_create. */
1541
Roland McGrathd6ff0d52008-07-18 01:09:44 +00001542 if ((arg_setup (tcp, &state) < 0
1543 || set_arg0 (tcp, &state,
1544 (tcp->u_arg[arg0_index] | CLONE_PTRACE)
Jan Kratochvil8fc95752008-08-06 21:43:35 +00001545 & ~(tcp->u_arg[arg0_index] & CLONE_VFORK
1546 ? CLONE_VFORK | CLONE_VM : 0)) < 0
Roland McGrathd6ff0d52008-07-18 01:09:44 +00001547 || arg_finish_change (tcp, &state) < 0))
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00001548 return -1;
Roland McGrathd81f1d92003-01-09 06:53:34 +00001549 tcp->flags |= TCB_BPTSET;
Roland McGrathc9dc3c12004-03-01 20:57:09 +00001550 tcp->inst[0] = tcp->u_arg[arg0_index];
1551 tcp->inst[1] = tcp->u_arg[arg1_index];
Roland McGrathd81f1d92003-01-09 06:53:34 +00001552 return 0;
1553
1554 default:
1555 fprintf(stderr, "PANIC: setbpt for syscall %ld on %u???\n",
1556 tcp->scno, tcp->pid);
1557 break;
1558 }
1559
1560 return -1;
1561}
1562
1563int
1564clearbpt(tcp)
1565struct tcb *tcp;
1566{
1567 arg_setup_state state;
1568 if (arg_setup (tcp, &state) < 0
Roland McGrathe1df47f2003-01-14 09:46:15 +00001569 || restore_arg0 (tcp, &state, tcp->inst[0]) < 0
1570 || restore_arg1 (tcp, &state, tcp->inst[1]) < 0
Roland McGrathd81f1d92003-01-09 06:53:34 +00001571 || arg_finish_change (tcp, &state))
Andreas Schwab46ed50d2009-11-11 13:54:04 +01001572 if (errno != ESRCH) return -1;
Roland McGrathd81f1d92003-01-09 06:53:34 +00001573 tcp->flags &= ~TCB_BPTSET;
1574 return 0;
1575}
1576
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001577# else /* !defined LINUX */
Roland McGrathd81f1d92003-01-09 06:53:34 +00001578
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001579int
1580setbpt(tcp)
1581struct tcb *tcp;
1582{
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001583# ifdef SUNOS4
1584# ifdef SPARC /* This code is slightly sparc specific */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001585
Wichert Akkermane6f876c1999-06-22 15:28:30 +00001586 struct regs regs;
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001587# define BPT 0x91d02001 /* ta 1 */
1588# define LOOP 0x10800000 /* ba 0 */
1589# define LOOPA 0x30800000 /* ba,a 0 */
1590# define NOP 0x01000000
1591# if LOOPA
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001592 static int loopdeloop[1] = {LOOPA};
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001593# else
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001594 static int loopdeloop[2] = {LOOP, NOP};
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001595# endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001596
1597 if (tcp->flags & TCB_BPTSET) {
1598 fprintf(stderr, "PANIC: TCB already set in pid %u\n", tcp->pid);
1599 return -1;
1600 }
Roland McGratheb9e2e82009-06-02 16:49:22 -07001601 if (ptrace(PTRACE_GETREGS, tcp->pid, (char *)&regs, 0) < 0) {
1602 perror("setbpt: ptrace(PTRACE_GETREGS, ...)");
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001603 return -1;
1604 }
1605 tcp->baddr = regs.r_o7 + 8;
Roland McGratheb9e2e82009-06-02 16:49:22 -07001606 if (ptrace(PTRACE_READTEXT, tcp->pid, (char *)tcp->baddr,
1607 sizeof tcp->inst, (char *)tcp->inst) < 0) {
1608 perror("setbpt: ptrace(PTRACE_READTEXT, ...)");
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001609 return -1;
1610 }
1611
1612 /*
1613 * XXX - BRUTAL MODE ON
1614 * We cannot set a real BPT in the child, since it will not be
1615 * traced at the moment it will reach the trap and would probably
1616 * die with a core dump.
1617 * Thus, we are force our way in by taking out two instructions
1618 * and insert an eternal loop in stead, in expectance of the SIGSTOP
1619 * generated by out PTRACE_ATTACH.
1620 * Of cause, if we evaporate ourselves in the middle of all this...
1621 */
Roland McGratheb9e2e82009-06-02 16:49:22 -07001622 if (ptrace(PTRACE_WRITETEXT, tcp->pid, (char *) tcp->baddr,
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001623 sizeof loopdeloop, (char *) loopdeloop) < 0) {
Roland McGratheb9e2e82009-06-02 16:49:22 -07001624 perror("setbpt: ptrace(PTRACE_WRITETEXT, ...)");
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001625 return -1;
1626 }
1627 tcp->flags |= TCB_BPTSET;
1628
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001629# endif /* SPARC */
1630# endif /* SUNOS4 */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001631
1632 return 0;
1633}
1634
1635int
1636clearbpt(tcp)
1637struct tcb *tcp;
1638{
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001639# ifdef SUNOS4
1640# ifdef SPARC
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001641
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001642# if !LOOPA
Wichert Akkermane6f876c1999-06-22 15:28:30 +00001643 struct regs regs;
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001644# endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001645
1646 if (!(tcp->flags & TCB_BPTSET)) {
1647 fprintf(stderr, "PANIC: TCB not set in pid %u\n", tcp->pid);
1648 return -1;
1649 }
Roland McGratheb9e2e82009-06-02 16:49:22 -07001650 if (ptrace(PTRACE_WRITETEXT, tcp->pid, (char *) tcp->baddr,
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001651 sizeof tcp->inst, (char *) tcp->inst) < 0) {
Roland McGratheb9e2e82009-06-02 16:49:22 -07001652 perror("clearbtp: ptrace(PTRACE_WRITETEXT, ...)");
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001653 return -1;
1654 }
1655 tcp->flags &= ~TCB_BPTSET;
1656
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001657# if !LOOPA
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001658 /*
1659 * Since we don't have a single instruction breakpoint, we may have
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001660 * to adjust the program counter after removing our `breakpoint'.
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001661 */
Roland McGratheb9e2e82009-06-02 16:49:22 -07001662 if (ptrace(PTRACE_GETREGS, tcp->pid, (char *)&regs, 0) < 0) {
1663 perror("clearbpt: ptrace(PTRACE_GETREGS, ...)");
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001664 return -1;
1665 }
Roland McGratheb9e2e82009-06-02 16:49:22 -07001666 if ((regs.r_pc < tcp->baddr) ||
1667 (regs.r_pc > tcp->baddr + 4)) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001668 /* The breakpoint has not been reached yet */
1669 if (debug)
1670 fprintf(stderr,
1671 "NOTE: PC not at bpt (pc %#x baddr %#x)\n",
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001672 regs.r_pc, tcp->baddr);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001673 return 0;
1674 }
1675 if (regs.r_pc != tcp->baddr)
1676 if (debug)
1677 fprintf(stderr, "NOTE: PC adjusted (%#x -> %#x\n",
1678 regs.r_pc, tcp->baddr);
1679
1680 regs.r_pc = tcp->baddr;
Roland McGratheb9e2e82009-06-02 16:49:22 -07001681 if (ptrace(PTRACE_SETREGS, tcp->pid, (char *)&regs, 0) < 0) {
1682 perror("clearbpt: ptrace(PTRACE_SETREGS, ...)");
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001683 return -1;
1684 }
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001685# endif /* LOOPA */
1686# endif /* SPARC */
1687# endif /* SUNOS4 */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001688
1689 return 0;
1690}
1691
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001692# endif /* !defined LINUX */
Roland McGrathd81f1d92003-01-09 06:53:34 +00001693
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001694#endif /* !USE_PROCFS */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001695
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001696
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001697#ifdef SUNOS4
1698
1699static int
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001700getex(tcp, hdr)
1701struct tcb *tcp;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001702struct exec *hdr;
1703{
1704 int n;
1705
1706 for (n = 0; n < sizeof *hdr; n += 4) {
1707 long res;
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001708 if (upeek(tcp, uoff(u_exdata) + n, &res) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001709 return -1;
1710 memcpy(((char *) hdr) + n, &res, 4);
1711 }
1712 if (debug) {
1713 fprintf(stderr, "[struct exec: magic: %o version %u Mach %o\n",
1714 hdr->a_magic, hdr->a_toolversion, hdr->a_machtype);
1715 fprintf(stderr, "Text %lu Data %lu Bss %lu Syms %lu Entry %#lx]\n",
1716 hdr->a_text, hdr->a_data, hdr->a_bss, hdr->a_syms, hdr->a_entry);
1717 }
1718 return 0;
1719}
1720
1721int
1722fixvfork(tcp)
1723struct tcb *tcp;
1724{
1725 int pid = tcp->pid;
1726 /*
1727 * Change `vfork' in a freshly exec'ed dynamically linked
1728 * executable's (internal) symbol table to plain old `fork'
1729 */
1730
1731 struct exec hdr;
1732 struct link_dynamic dyn;
1733 struct link_dynamic_2 ld;
1734 char *strtab, *cp;
1735
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001736 if (getex(tcp, &hdr) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001737 return -1;
1738 if (!hdr.a_dynamic)
1739 return -1;
1740
1741 if (umove(tcp, (int) N_DATADDR(hdr), &dyn) < 0) {
1742 fprintf(stderr, "Cannot read DYNAMIC\n");
1743 return -1;
1744 }
1745 if (umove(tcp, (int) dyn.ld_un.ld_2, &ld) < 0) {
1746 fprintf(stderr, "Cannot read link_dynamic_2\n");
1747 return -1;
1748 }
1749 if ((strtab = malloc((unsigned)ld.ld_symb_size)) == NULL) {
Roland McGrath46100d02005-06-01 18:55:42 +00001750 fprintf(stderr, "out of memory\n");
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001751 return -1;
1752 }
Roland McGratheb9e2e82009-06-02 16:49:22 -07001753 if (umoven(tcp, (int)ld.ld_symbols+(int)N_TXTADDR(hdr),
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001754 (int)ld.ld_symb_size, strtab) < 0)
1755 goto err;
1756
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001757 for (cp = strtab; cp < strtab + ld.ld_symb_size; ) {
1758 if (strcmp(cp, "_vfork") == 0) {
1759 if (debug)
1760 fprintf(stderr, "fixvfork: FOUND _vfork\n");
1761 strcpy(cp, "_fork");
1762 break;
1763 }
1764 cp += strlen(cp)+1;
1765 }
1766 if (cp < strtab + ld.ld_symb_size)
1767 /*
1768 * Write entire symbol table back to avoid
1769 * memory alignment bugs in ptrace
1770 */
Roland McGratheb9e2e82009-06-02 16:49:22 -07001771 if (tload(pid, (int)ld.ld_symbols+(int)N_TXTADDR(hdr),
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001772 (int)ld.ld_symb_size, strtab) < 0)
1773 goto err;
1774
1775 free(strtab);
1776 return 0;
1777
1778err:
1779 free(strtab);
1780 return -1;
1781}
1782
1783#endif /* SUNOS4 */