blob: 07cbfdeda40b308843318581a9beea61af7c2ee6 [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
Roland McGrathb2dee132005-06-01 19:02:36 +0000343printflags(xlat, flags, dflt)
Roland McGrathd9f816f2004-09-04 03:39:20 +0000344const struct xlat *xlat;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000345int flags;
Roland McGrathb2dee132005-06-01 19:02:36 +0000346const char *dflt;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000347{
348 int n;
349 char *sep;
350
351 if (flags == 0 && xlat->val == 0) {
352 tprintf("%s", xlat->str);
353 return 1;
354 }
355
356 sep = "";
357 for (n = 0; xlat->str; xlat++) {
358 if (xlat->val && (flags & xlat->val) == xlat->val) {
359 tprintf("%s%s", sep, xlat->str);
360 flags &= ~xlat->val;
361 sep = "|";
362 n++;
363 }
364 }
Roland McGrathb2dee132005-06-01 19:02:36 +0000365
366 if (n) {
367 if (flags) {
368 tprintf("%s%#x", sep, flags);
369 n++;
370 }
371 } else {
372 if (flags) {
373 tprintf("%#x", flags);
374 if (dflt)
375 tprintf(" /* %s */", dflt);
376 } else {
377 if (dflt)
378 tprintf("0");
379 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000380 }
Roland McGrathb2dee132005-06-01 19:02:36 +0000381
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000382 return n;
383}
384
385void
386printnum(tcp, addr, fmt)
387struct tcb *tcp;
388long addr;
389char *fmt;
390{
Roland McGratheb285352003-01-14 09:59:00 +0000391 long num;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000392
393 if (!addr) {
394 tprintf("NULL");
395 return;
396 }
397 if (umove(tcp, addr, &num) < 0) {
398 tprintf("%#lx", addr);
399 return;
400 }
401 tprintf("[");
402 tprintf(fmt, num);
403 tprintf("]");
404}
405
Roland McGrath6bc12202003-11-13 22:32:27 +0000406void
Roland McGrath9814a942005-07-04 23:28:10 +0000407printnum_int(tcp, addr, fmt)
408struct tcb *tcp;
409long addr;
410char *fmt;
411{
412 int num;
413
414 if (!addr) {
415 tprintf("NULL");
416 return;
417 }
418 if (umove(tcp, addr, &num) < 0) {
419 tprintf("%#lx", addr);
420 return;
421 }
422 tprintf("[");
423 tprintf(fmt, num);
424 tprintf("]");
425}
426
427void
Roland McGrath6bc12202003-11-13 22:32:27 +0000428printuid(text, uid)
429const char *text;
430unsigned long uid;
431{
432 tprintf("%s", text);
433 tprintf((uid == -1) ? "%ld" : "%lu", uid);
434}
435
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000436static char path[MAXPATHLEN + 1];
437
Dmitry V. Levina501f142008-11-10 23:19:13 +0000438/*
439 * Quote string `instr' of length `size'
440 * Write up to (3 + `size' * 4) bytes to `outstr' buffer.
441 * If `len' < 0, treat `instr' as a NUL-terminated string
442 * and quote at most (`size' - 1) bytes.
443 */
Roland McGrath6d970322007-11-01 23:53:59 +0000444static int
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000445string_quote(const char *instr, char *outstr, int len, int size)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000446{
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000447 const unsigned char *ustr = (const unsigned char *) instr;
448 char *s = outstr;
449 int usehex = 0, c, i;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000450
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000451 if (xflag > 1)
452 usehex = 1;
453 else if (xflag) {
Dmitry V. Levina501f142008-11-10 23:19:13 +0000454 /* Check for presence of symbol which require
455 to hex-quote the whole string. */
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000456 for (i = 0; i < size; ++i) {
457 c = ustr[i];
Dmitry V. Levina501f142008-11-10 23:19:13 +0000458 /* Check for NUL-terminated string. */
459 if (len < 0) {
460 if (c == '\0')
461 break;
462 /* Quote at most size - 1 bytes. */
463 if (i == size - 1)
464 continue;
465 }
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000466 if (!isprint(c) && !isspace(c)) {
467 usehex = 1;
468 break;
469 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000470 }
471 }
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000472
473 *s++ = '\"';
474
475 if (usehex) {
Dmitry V. Levina501f142008-11-10 23:19:13 +0000476 /* Hex-quote the whole string. */
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000477 for (i = 0; i < size; ++i) {
478 c = ustr[i];
Dmitry V. Levina501f142008-11-10 23:19:13 +0000479 /* Check for NUL-terminated string. */
480 if (len < 0) {
481 if (c == '\0')
482 break;
483 /* Quote at most size - 1 bytes. */
484 if (i == size - 1)
485 continue;
486 }
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000487 sprintf(s, "\\x%02x", c);
488 s += 4;
489 }
490 } else {
491 for (i = 0; i < size; ++i) {
492 c = ustr[i];
Dmitry V. Levina501f142008-11-10 23:19:13 +0000493 /* Check for NUL-terminated string. */
494 if (len < 0) {
495 if (c == '\0')
496 break;
497 /* Quote at most size - 1 bytes. */
498 if (i == size - 1)
499 continue;
500 }
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000501 switch (c) {
502 case '\"': case '\\':
503 *s++ = '\\';
504 *s++ = c;
505 break;
506 case '\f':
507 *s++ = '\\';
508 *s++ = 'f';
509 break;
510 case '\n':
511 *s++ = '\\';
512 *s++ = 'n';
513 break;
514 case '\r':
515 *s++ = '\\';
516 *s++ = 'r';
517 break;
518 case '\t':
519 *s++ = '\\';
520 *s++ = 't';
521 break;
522 case '\v':
523 *s++ = '\\';
524 *s++ = 'v';
525 break;
526 default:
527 if (isprint(c))
528 *s++ = c;
529 else if (i + 1 < size
530 && isdigit(ustr[i + 1])) {
531 sprintf(s, "\\%03o", c);
532 s += 4;
533 } else {
534 sprintf(s, "\\%o", c);
535 s += strlen(s);
536 }
537 break;
538 }
539 }
540 }
541
542 *s++ = '\"';
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000543 *s = '\0';
Roland McGrath6d970322007-11-01 23:53:59 +0000544
545 /* Return nonzero if the string was unterminated. */
546 return i == size;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000547}
548
Dmitry V. Levina501f142008-11-10 23:19:13 +0000549/*
550 * Print path string specified by address `addr' and length `n'.
551 * If path length exceeds `n', append `...' to the output.
552 */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000553void
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000554printpathn(struct tcb *tcp, long addr, int n)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000555{
Dmitry V. Levina501f142008-11-10 23:19:13 +0000556 if (!addr) {
Roland McGrath371ed8f2005-02-06 01:55:07 +0000557 tprintf("NULL");
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000558 return;
559 }
560
Dmitry V. Levina501f142008-11-10 23:19:13 +0000561 /* Cap path length to the path buffer size,
562 and NUL-terminate the buffer. */
563 if (n > sizeof path - 1)
564 n = sizeof path - 1;
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000565 path[n] = '\0';
Dmitry V. Levina501f142008-11-10 23:19:13 +0000566
567 /* Fetch one byte more to find out whether path length > n. */
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000568 if (umovestr(tcp, addr, n + 1, path) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000569 tprintf("%#lx", addr);
570 else {
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000571 static char outstr[4*(sizeof path - 1) + sizeof "\"...\""];
572 int trunc = (path[n] != '\0');
573
574 if (trunc)
575 path[n] = '\0';
Dmitry V. Levina501f142008-11-10 23:19:13 +0000576 (void) string_quote(path, outstr, -1, n + 1);
577 if (trunc)
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000578 strcat(outstr, "...");
579 tprintf("%s", outstr);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000580 }
581}
582
583void
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000584printpath(struct tcb *tcp, long addr)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000585{
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000586 printpathn(tcp, addr, sizeof path - 1);
587}
588
Dmitry V. Levina501f142008-11-10 23:19:13 +0000589/*
590 * Print string specified by address `addr' and length `len'.
591 * If `len' < 0, treat the string as a NUL-terminated string.
592 * If string length exceeds `max_strlen', append `...' to the output.
593 */
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000594void
595printstr(struct tcb *tcp, long addr, int len)
596{
597 static char *str = NULL;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000598 static char *outstr;
Roland McGrath6d970322007-11-01 23:53:59 +0000599 int size;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000600
601 if (!addr) {
602 tprintf("NULL");
603 return;
604 }
Dmitry V. Levina501f142008-11-10 23:19:13 +0000605 /* Allocate static buffers if they are not allocated yet. */
606 if (!str)
607 str = malloc(max_strlen + 1);
608 if (!outstr)
609 outstr = malloc(4 * max_strlen + sizeof "\"...\"");
610 if (!str || !outstr) {
611 fprintf(stderr, "out of memory\n");
612 tprintf("%#lx", addr);
613 return;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000614 }
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000615
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000616 if (len < 0) {
Dmitry V. Levina501f142008-11-10 23:19:13 +0000617 /*
618 * Treat as a NUL-terminated string: fetch one byte more
619 * because string_quote() quotes one byte less.
620 */
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000621 size = max_strlen + 1;
Dmitry V. Levina501f142008-11-10 23:19:13 +0000622 str[max_strlen] = '\0';
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000623 if (umovestr(tcp, addr, size, str) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000624 tprintf("%#lx", addr);
625 return;
626 }
627 }
628 else {
Dmitry V. Levina501f142008-11-10 23:19:13 +0000629 size = MIN(len, max_strlen);
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000630 if (umoven(tcp, addr, size, str) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000631 tprintf("%#lx", addr);
632 return;
633 }
634 }
635
Dmitry V. Levina501f142008-11-10 23:19:13 +0000636 if (string_quote(str, outstr, len, size) &&
637 (len < 0 || len > max_strlen))
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000638 strcat(outstr, "...");
Roland McGratha503dcf2007-08-02 02:06:26 +0000639
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000640 tprintf("%s", outstr);
641}
642
John Hughes1d08dcf2001-07-10 13:48:44 +0000643#if HAVE_SYS_UIO_H
644void
645dumpiov(tcp, len, addr)
646struct tcb * tcp;
647int len;
648long addr;
649{
Dmitry V. Levin4ebb4e32006-12-13 17:08:08 +0000650#if defined(LINUX) && SUPPORTED_PERSONALITIES > 1
651 union {
652 struct { u_int32_t base; u_int32_t len; } *iov32;
653 struct { u_int64_t base; u_int64_t len; } *iov64;
654 } iovu;
655#define iov iovu.iov64
656#define sizeof_iov \
657 (personality_wordsize[current_personality] == 4 \
658 ? sizeof(*iovu.iov32) : sizeof(*iovu.iov64))
659#define iov_iov_base(i) \
660 (personality_wordsize[current_personality] == 4 \
661 ? (u_int64_t) iovu.iov32[i].base : iovu.iov64[i].base)
662#define iov_iov_len(i) \
663 (personality_wordsize[current_personality] == 4 \
664 ? (u_int64_t) iovu.iov32[i].len : iovu.iov64[i].len)
665#else
John Hughes1d08dcf2001-07-10 13:48:44 +0000666 struct iovec *iov;
Dmitry V. Levin4ebb4e32006-12-13 17:08:08 +0000667#define sizeof_iov sizeof(*iov)
668#define iov_iov_base(i) iov[i].iov_base
669#define iov_iov_len(i) iov[i].iov_len
670#endif
John Hughes1d08dcf2001-07-10 13:48:44 +0000671 int i;
Roland McGrathaa524c82005-06-01 19:22:06 +0000672 unsigned long size;
John Hughes1d08dcf2001-07-10 13:48:44 +0000673
Dmitry V. Levin4ebb4e32006-12-13 17:08:08 +0000674 size = sizeof_iov * (unsigned long) len;
675 if (size / sizeof_iov != len
676 || (iov = malloc(size)) == NULL) {
Roland McGrathaa524c82005-06-01 19:22:06 +0000677 fprintf(stderr, "out of memory\n");
John Hughes1d08dcf2001-07-10 13:48:44 +0000678 return;
679 }
Roland McGrathaa524c82005-06-01 19:22:06 +0000680 if (umoven(tcp, addr, size, (char *) iov) >= 0) {
John Hughes1d08dcf2001-07-10 13:48:44 +0000681 for (i = 0; i < len; i++) {
Denys Vlasenkoadedb512008-12-30 18:47:55 +0000682 /* include the buffer number to make it easy to
683 * match up the trace with the source */
684 tprintf(" * %lu bytes in buffer %d\n",
685 (unsigned long)iov_iov_len(i), i);
686 dumpstr(tcp, (long) iov_iov_base(i),
687 iov_iov_len(i));
688 }
John Hughes1d08dcf2001-07-10 13:48:44 +0000689 }
690 free((char *) iov);
Dmitry V. Levin4ebb4e32006-12-13 17:08:08 +0000691#undef sizeof_iov
692#undef iov_iov_base
693#undef iov_iov_len
694#undef iov
John Hughes1d08dcf2001-07-10 13:48:44 +0000695}
696#endif
697
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000698void
699dumpstr(tcp, addr, len)
700struct tcb *tcp;
701long addr;
702int len;
703{
704 static int strsize = -1;
705 static unsigned char *str;
706 static char outstr[80];
707 char *s;
708 int i, j;
709
710 if (strsize < len) {
711 if (str)
712 free(str);
713 if ((str = malloc(len)) == NULL) {
Roland McGrath46100d02005-06-01 18:55:42 +0000714 fprintf(stderr, "out of memory\n");
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000715 return;
716 }
717 strsize = len;
718 }
719
720 if (umoven(tcp, addr, len, (char *) str) < 0)
721 return;
722
723 for (i = 0; i < len; i += 16) {
724 s = outstr;
725 sprintf(s, " | %05x ", i);
726 s += 9;
727 for (j = 0; j < 16; j++) {
728 if (j == 8)
729 *s++ = ' ';
730 if (i + j < len) {
731 sprintf(s, " %02x", str[i + j]);
732 s += 3;
733 }
734 else {
735 *s++ = ' '; *s++ = ' '; *s++ = ' ';
736 }
737 }
738 *s++ = ' '; *s++ = ' ';
739 for (j = 0; j < 16; j++) {
740 if (j == 8)
741 *s++ = ' ';
742 if (i + j < len) {
743 if (isprint(str[i + j]))
744 *s++ = str[i + j];
745 else
746 *s++ = '.';
747 }
748 else
749 *s++ = ' ';
750 }
751 tprintf("%s |\n", outstr);
752 }
753}
754
755#define PAGMASK (~(PAGSIZ - 1))
756/*
757 * move `len' bytes of data from process `pid'
758 * at address `addr' to our space at `laddr'
759 */
760int
Denys Vlasenkoef2fbf82009-01-06 21:45:06 +0000761umoven(struct tcb *tcp, long addr, int len, char *laddr)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000762{
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000763#ifdef LINUX
Roland McGratheb9e2e82009-06-02 16:49:22 -0700764 int pid = tcp->pid;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000765 int n, m;
Wichert Akkerman5daa0281999-03-15 19:49:42 +0000766 int started = 0;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000767 union {
768 long val;
769 char x[sizeof(long)];
770 } u;
771
772 if (addr & (sizeof(long) - 1)) {
773 /* addr not a multiple of sizeof(long) */
774 n = addr - (addr & -sizeof(long)); /* residue */
775 addr &= -sizeof(long); /* residue */
Roland McGratheb9e2e82009-06-02 16:49:22 -0700776 errno = 0;
777 u.val = ptrace(PTRACE_PEEKDATA, pid, (char *) addr, 0);
778 if (errno) {
779 if (started && (errno==EPERM || errno==EIO)) {
780 /* Ran into 'end of memory' - stupid "printpath" */
781 return 0;
782 }
783 /* But if not started, we had a bogus address. */
784 if (addr != 0 && errno != EIO && errno != ESRCH)
785 perror("ptrace: umoven");
786 return -1;
787 }
Wichert Akkerman5daa0281999-03-15 19:49:42 +0000788 started = 1;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000789 memcpy(laddr, &u.x[n], m = MIN(sizeof(long) - n, len));
790 addr += sizeof(long), laddr += m, len -= m;
791 }
792 while (len) {
Roland McGratheb9e2e82009-06-02 16:49:22 -0700793 errno = 0;
794 u.val = ptrace(PTRACE_PEEKDATA, pid, (char *) addr, 0);
795 if (errno) {
796 if (started && (errno==EPERM || errno==EIO)) {
797 /* Ran into 'end of memory' - stupid "printpath" */
798 return 0;
799 }
800 if (addr != 0 && errno != EIO && errno != ESRCH)
801 perror("ptrace: umoven");
802 return -1;
803 }
Wichert Akkerman5daa0281999-03-15 19:49:42 +0000804 started = 1;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000805 memcpy(laddr, u.x, m = MIN(sizeof(long), len));
806 addr += sizeof(long), laddr += m, len -= m;
807 }
808#endif /* LINUX */
809
810#ifdef SUNOS4
811 int pid = tcp->pid;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000812 int n;
813
814 while (len) {
815 n = MIN(len, PAGSIZ);
816 n = MIN(n, ((addr + PAGSIZ) & PAGMASK) - addr);
Roland McGratheb9e2e82009-06-02 16:49:22 -0700817 if (ptrace(PTRACE_READDATA, pid,
818 (char *) addr, len, laddr) < 0) {
819 if (errno != ESRCH) {
820 perror("umoven: ptrace(PTRACE_READDATA, ...)");
821 abort();
822 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000823 return -1;
824 }
825 len -= n;
826 addr += n;
827 laddr += n;
828 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000829#endif /* SUNOS4 */
830
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000831#ifdef USE_PROCFS
Wichert Akkermanea78f0f1999-11-29 15:34:02 +0000832#ifdef HAVE_MP_PROCFS
John Hughesaa09c6b2001-05-15 14:53:43 +0000833 int fd = tcp->pfd_as;
Wichert Akkerman9ce1a631999-08-29 23:15:07 +0000834#else
John Hughesaa09c6b2001-05-15 14:53:43 +0000835 int fd = tcp->pfd;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000836#endif
John Hughesaa09c6b2001-05-15 14:53:43 +0000837 lseek(fd, addr, SEEK_SET);
838 if (read(fd, laddr, len) == -1)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000839 return -1;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000840#endif /* USE_PROCFS */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000841
842 return 0;
843}
844
845/*
846 * like `umove' but make the additional effort of looking
847 * for a terminating zero byte.
848 */
849int
Denys Vlasenkoef2fbf82009-01-06 21:45:06 +0000850umovestr(struct tcb *tcp, long addr, int len, char *laddr)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000851{
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000852#ifdef USE_PROCFS
John Hughesaa09c6b2001-05-15 14:53:43 +0000853#ifdef HAVE_MP_PROCFS
854 int fd = tcp->pfd_as;
855#else
856 int fd = tcp->pfd;
857#endif
858 /* Some systems (e.g. FreeBSD) can be upset if we read off the
859 end of valid memory, avoid this by trying to read up
860 to page boundaries. But we don't know what a page is (and
861 getpagesize(2) (if it exists) doesn't necessarily return
862 hardware page size). Assume all pages >= 1024 (a-historical
863 I know) */
864
865 int page = 1024; /* How to find this? */
866 int move = page - (addr & (page - 1));
867 int left = len;
868
869 lseek(fd, addr, SEEK_SET);
870
871 while (left) {
872 if (move > left) move = left;
John Hughes9cecf7f2001-10-16 10:20:22 +0000873 if ((move = read(fd, laddr, move)) <= 0)
John Hughesaa09c6b2001-05-15 14:53:43 +0000874 return left != len ? 0 : -1;
875 if (memchr (laddr, 0, move)) break;
876 left -= move;
877 laddr += move;
878 addr += move;
879 move = page;
880 }
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000881#else /* !USE_PROCFS */
Wichert Akkerman5daa0281999-03-15 19:49:42 +0000882 int started = 0;
Roland McGratheb9e2e82009-06-02 16:49:22 -0700883 int pid = tcp->pid;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000884 int i, n, m;
885 union {
886 long val;
887 char x[sizeof(long)];
888 } u;
889
890 if (addr & (sizeof(long) - 1)) {
891 /* addr not a multiple of sizeof(long) */
892 n = addr - (addr & -sizeof(long)); /* residue */
893 addr &= -sizeof(long); /* residue */
Roland McGratheb9e2e82009-06-02 16:49:22 -0700894 errno = 0;
895 u.val = ptrace(PTRACE_PEEKDATA, pid, (char *)addr, 0);
896 if (errno) {
897 if (started && (errno==EPERM || errno==EIO)) {
898 /* Ran into 'end of memory' - stupid "printpath" */
899 return 0;
900 }
901 if (addr != 0 && errno != EIO && errno != ESRCH)
902 perror("umovestr");
903 return -1;
904 }
Wichert Akkerman5daa0281999-03-15 19:49:42 +0000905 started = 1;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000906 memcpy(laddr, &u.x[n], m = MIN(sizeof(long)-n,len));
907 while (n & (sizeof(long) - 1))
908 if (u.x[n++] == '\0')
909 return 0;
910 addr += sizeof(long), laddr += m, len -= m;
911 }
912 while (len) {
Roland McGratheb9e2e82009-06-02 16:49:22 -0700913 errno = 0;
914 u.val = ptrace(PTRACE_PEEKDATA, pid, (char *)addr, 0);
915 if (errno) {
916 if (started && (errno==EPERM || errno==EIO)) {
917 /* Ran into 'end of memory' - stupid "printpath" */
918 return 0;
919 }
920 if (addr != 0 && errno != EIO && errno != ESRCH)
921 perror("umovestr");
922 return -1;
923 }
Wichert Akkerman5daa0281999-03-15 19:49:42 +0000924 started = 1;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000925 memcpy(laddr, u.x, m = MIN(sizeof(long), len));
926 for (i = 0; i < sizeof(long); i++)
927 if (u.x[i] == '\0')
928 return 0;
929
930 addr += sizeof(long), laddr += m, len -= m;
931 }
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000932#endif /* !USE_PROCFS */
John Hughesaa09c6b2001-05-15 14:53:43 +0000933 return 0;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000934}
935
936#ifdef LINUX
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +0000937# if !defined (SPARC) && !defined(SPARC64)
938# define PTRACE_WRITETEXT 101
939# define PTRACE_WRITEDATA 102
940# endif /* !SPARC && !SPARC64 */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000941#endif /* LINUX */
942
943#ifdef SUNOS4
944
945static int
Roland McGratheb9e2e82009-06-02 16:49:22 -0700946uload(cmd, pid, addr, len, laddr)
947int cmd;
948int pid;
949long addr;
950int len;
951char *laddr;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000952{
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000953 int peek, poke;
954 int n, m;
955 union {
956 long val;
957 char x[sizeof(long)];
958 } u;
959
960 if (cmd == PTRACE_WRITETEXT) {
961 peek = PTRACE_PEEKTEXT;
962 poke = PTRACE_POKETEXT;
963 }
964 else {
965 peek = PTRACE_PEEKDATA;
966 poke = PTRACE_POKEDATA;
967 }
968 if (addr & (sizeof(long) - 1)) {
969 /* addr not a multiple of sizeof(long) */
970 n = addr - (addr & -sizeof(long)); /* residue */
971 addr &= -sizeof(long);
Roland McGratheb9e2e82009-06-02 16:49:22 -0700972 errno = 0;
973 u.val = ptrace(peek, pid, (char *) addr, 0);
974 if (errno) {
975 perror("uload: POKE");
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000976 return -1;
977 }
Roland McGratheb9e2e82009-06-02 16:49:22 -0700978 memcpy(&u.x[n], laddr, m = MIN(sizeof(long) - n, len));
979 if (ptrace(poke, pid, (char *)addr, u.val) < 0) {
980 perror("uload: POKE");
981 return -1;
982 }
983 addr += sizeof(long), laddr += m, len -= m;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000984 }
985 while (len) {
986 if (len < sizeof(long))
Roland McGratheb9e2e82009-06-02 16:49:22 -0700987 u.val = ptrace(peek, pid, (char *) addr, 0);
988 memcpy(u.x, laddr, m = MIN(sizeof(long), len));
989 if (ptrace(poke, pid, (char *) addr, u.val) < 0) {
990 perror("uload: POKE");
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000991 return -1;
992 }
Roland McGratheb9e2e82009-06-02 16:49:22 -0700993 addr += sizeof(long), laddr += m, len -= m;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000994 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000995 return 0;
996}
997
Roland McGratheb9e2e82009-06-02 16:49:22 -0700998int
999tload(pid, addr, len, laddr)
1000int pid;
1001int addr, len;
1002char *laddr;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001003{
Roland McGratheb9e2e82009-06-02 16:49:22 -07001004 return uload(PTRACE_WRITETEXT, pid, addr, len, laddr);
1005}
1006
1007int
1008dload(pid, addr, len, laddr)
1009int pid;
1010int addr;
1011int len;
1012char *laddr;
1013{
1014 return uload(PTRACE_WRITEDATA, pid, addr, len, laddr);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001015}
1016
1017#endif /* SUNOS4 */
1018
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001019#ifndef USE_PROCFS
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001020
1021int
Roland McGratheb9e2e82009-06-02 16:49:22 -07001022upeek(tcp, off, res)
1023struct tcb *tcp;
1024long off;
1025long *res;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001026{
1027 long val;
1028
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001029# ifdef SUNOS4_KERNEL_ARCH_KLUDGE
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001030 {
1031 static int is_sun4m = -1;
1032 struct utsname name;
1033
1034 /* Round up the usual suspects. */
1035 if (is_sun4m == -1) {
1036 if (uname(&name) < 0) {
1037 perror("upeek: uname?");
1038 exit(1);
1039 }
1040 is_sun4m = strcmp(name.machine, "sun4m") == 0;
1041 if (is_sun4m) {
Roland McGrathd9f816f2004-09-04 03:39:20 +00001042 const struct xlat *x;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001043
1044 for (x = struct_user_offsets; x->str; x++)
1045 x->val += 1024;
1046 }
1047 }
1048 if (is_sun4m)
1049 off += 1024;
1050 }
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001051# endif /* SUNOS4_KERNEL_ARCH_KLUDGE */
Roland McGratheb9e2e82009-06-02 16:49:22 -07001052 errno = 0;
Denys Vlasenko732d1bf2008-12-17 19:21:59 +00001053 val = do_ptrace(PTRACE_PEEKUSER, tcp, (char *) off, 0);
Roland McGratheb9e2e82009-06-02 16:49:22 -07001054 if (val == -1 && errno) {
1055 if (errno != ESRCH) {
1056 char buf[60];
1057 sprintf(buf,"upeek: ptrace(PTRACE_PEEKUSER,%d,%lu,0)", tcp->pid, off);
1058 perror(buf);
1059 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001060 return -1;
Roland McGratheb9e2e82009-06-02 16:49:22 -07001061 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001062 *res = val;
1063 return 0;
1064}
1065
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001066#endif /* !USE_PROCFS */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001067
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001068void
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001069printcall(struct tcb *tcp)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001070{
Roland McGrath7a918832005-02-02 20:55:23 +00001071#define PRINTBADPC tprintf(sizeof(long) == 4 ? "[????????] " : \
1072 sizeof(long) == 8 ? "[????????????????] " : \
1073 NULL /* crash */)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001074
1075#ifdef LINUX
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001076# ifdef I386
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001077 long eip;
1078
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001079 if (upeek(tcp, 4*EIP, &eip) < 0) {
Roland McGrath7a918832005-02-02 20:55:23 +00001080 PRINTBADPC;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001081 return;
1082 }
1083 tprintf("[%08lx] ", eip);
Roland McGratheac26fc2005-02-02 02:48:53 +00001084
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001085# elif defined(S390) || defined(S390X)
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001086 long psw;
Roland McGratheb9e2e82009-06-02 16:49:22 -07001087 if(upeek(tcp,PT_PSWADDR,&psw) < 0) {
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001088 PRINTBADPC;
1089 return;
1090 }
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001091# ifdef S390
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001092 tprintf("[%08lx] ", psw);
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001093# elif S390X
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001094 tprintf("[%16lx] ", psw);
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001095# endif
Roland McGratheac26fc2005-02-02 02:48:53 +00001096
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001097# elif defined(X86_64)
Michal Ludvig0e035502002-09-23 15:41:01 +00001098 long rip;
1099
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001100 if (upeek(tcp, 8*RIP, &rip) < 0) {
Roland McGrath7a918832005-02-02 20:55:23 +00001101 PRINTBADPC;
Michal Ludvig0e035502002-09-23 15:41:01 +00001102 return;
1103 }
1104 tprintf("[%16lx] ", rip);
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001105# elif defined(IA64)
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00001106 long ip;
1107
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001108 if (upeek(tcp, PT_B0, &ip) < 0) {
Roland McGrath7a918832005-02-02 20:55:23 +00001109 PRINTBADPC;
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00001110 return;
1111 }
1112 tprintf("[%08lx] ", ip);
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001113# elif defined(POWERPC)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001114 long pc;
1115
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001116 if (upeek(tcp, sizeof(unsigned long)*PT_NIP, &pc) < 0) {
Andreas Schwabd69fa492010-07-12 21:39:57 +02001117 PRINTBADPC;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001118 return;
1119 }
Andreas Schwabd69fa492010-07-12 21:39:57 +02001120# ifdef POWERPC64
1121 tprintf("[%016lx] ", pc);
1122# else
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001123 tprintf("[%08lx] ", pc);
Andreas Schwabd69fa492010-07-12 21:39:57 +02001124# endif
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001125# elif defined(M68K)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001126 long pc;
1127
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001128 if (upeek(tcp, 4*PT_PC, &pc) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001129 tprintf ("[????????] ");
1130 return;
1131 }
1132 tprintf("[%08lx] ", pc);
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001133# elif defined(ALPHA)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001134 long pc;
1135
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001136 if (upeek(tcp, REG_PC, &pc) < 0) {
Roland McGrath7a918832005-02-02 20:55:23 +00001137 tprintf ("[????????????????] ");
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001138 return;
1139 }
1140 tprintf("[%08lx] ", pc);
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001141# elif defined(SPARC) || defined(SPARC64)
Mike Frysinger8566c502009-10-12 11:05:14 -04001142 struct pt_regs regs;
Roland McGratheb9e2e82009-06-02 16:49:22 -07001143 if (ptrace(PTRACE_GETREGS,tcp->pid,(char *)&regs,0) < 0) {
Roland McGrath7a918832005-02-02 20:55:23 +00001144 PRINTBADPC;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001145 return;
1146 }
Mike Frysinger8566c502009-10-12 11:05:14 -04001147# if defined(SPARC64)
1148 tprintf("[%08lx] ", regs.tpc);
1149# else
1150 tprintf("[%08lx] ", regs.pc);
1151# endif
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001152# elif defined(HPPA)
Wichert Akkermanc1652e22001-03-27 12:17:16 +00001153 long pc;
1154
Roland McGratheb9e2e82009-06-02 16:49:22 -07001155 if(upeek(tcp,PT_IAOQ0,&pc) < 0) {
Wichert Akkermanc1652e22001-03-27 12:17:16 +00001156 tprintf ("[????????] ");
1157 return;
1158 }
1159 tprintf("[%08lx] ", pc);
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001160# elif defined(MIPS)
Wichert Akkerman75c422b2001-04-10 10:22:50 +00001161 long pc;
1162
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001163 if (upeek(tcp, REG_EPC, &pc) < 0) {
Wichert Akkerman75c422b2001-04-10 10:22:50 +00001164 tprintf ("[????????] ");
1165 return;
1166 }
1167 tprintf("[%08lx] ", pc);
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001168# elif defined(SH)
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001169 long pc;
Wichert Akkermanccef6372002-05-01 16:39:22 +00001170
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001171 if (upeek(tcp, 4*REG_PC, &pc) < 0) {
1172 tprintf ("[????????] ");
1173 return;
1174 }
1175 tprintf("[%08lx] ", pc);
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001176# elif defined(SH64)
Roland McGrathe1e584b2003-06-02 19:18:58 +00001177 long pc;
1178
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001179 if (upeek(tcp, REG_PC, &pc) < 0) {
Roland McGrath7a918832005-02-02 20:55:23 +00001180 tprintf ("[????????????????] ");
Roland McGrathe1e584b2003-06-02 19:18:58 +00001181 return;
1182 }
1183 tprintf("[%08lx] ", pc);
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001184# elif defined(ARM)
Roland McGrathef388682003-06-03 23:28:59 +00001185 long pc;
Roland McGrathe1e584b2003-06-02 19:18:58 +00001186
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001187 if (upeek(tcp, 4*15, &pc) < 0) {
Roland McGrath7a918832005-02-02 20:55:23 +00001188 PRINTBADPC;
Roland McGrathef388682003-06-03 23:28:59 +00001189 return;
1190 }
1191 tprintf("[%08lx] ", pc);
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00001192# elif defined(AVR32)
1193 long pc;
1194
1195 if (upeek(tcp, REG_PC, &pc) < 0) {
1196 tprintf("[????????] ");
1197 return;
1198 }
1199 tprintf("[%08lx] ", pc);
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001200# elif defined(BFIN)
Dmitry V. Levin87ea1f42008-11-10 22:21:41 +00001201 long pc;
1202
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001203 if (upeek(tcp, PT_PC, &pc) < 0) {
Dmitry V. Levin87ea1f42008-11-10 22:21:41 +00001204 PRINTBADPC;
1205 return;
1206 }
1207 tprintf("[%08lx] ", pc);
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001208#elif defined(CRISV10)
1209 long pc;
1210
Edgar E. Iglesiaseeb9ce32009-10-05 14:41:02 +00001211 if (upeek(tcp, 4*PT_IRP, &pc) < 0) {
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001212 PRINTBADPC;
1213 return;
1214 }
1215 tprintf("[%08lx] ", pc);
1216#elif defined(CRISV32)
1217 long pc;
1218
Edgar E. Iglesiaseeb9ce32009-10-05 14:41:02 +00001219 if (upeek(tcp, 4*PT_ERP, &pc) < 0) {
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001220 PRINTBADPC;
1221 return;
1222 }
1223 tprintf("[%08lx] ", pc);
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001224# endif /* architecture */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001225#endif /* LINUX */
1226
1227#ifdef SUNOS4
1228 struct regs regs;
1229
Roland McGratheb9e2e82009-06-02 16:49:22 -07001230 if (ptrace(PTRACE_GETREGS, tcp->pid, (char *) &regs, 0) < 0) {
1231 perror("printcall: ptrace(PTRACE_GETREGS, ...)");
Roland McGrath7a918832005-02-02 20:55:23 +00001232 PRINTBADPC;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001233 return;
1234 }
1235 tprintf("[%08x] ", regs.r_o7);
1236#endif /* SUNOS4 */
1237
1238#ifdef SVR4
1239 /* XXX */
Roland McGrath7a918832005-02-02 20:55:23 +00001240 PRINTBADPC;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001241#endif
1242
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001243#ifdef FREEBSD
1244 struct reg regs;
1245 pread(tcp->pfd_reg, &regs, sizeof(regs), 0);
1246 tprintf("[%08x] ", regs.r_eip);
1247#endif /* FREEBSD */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001248}
1249
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001250
1251/*
1252 * These #if's are huge, please indent them correctly.
1253 * It's easy to get confused otherwise.
1254 */
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001255#ifndef USE_PROCFS
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001256
Dmitry V. Levine5e60852009-12-31 22:50:49 +00001257#ifdef LINUX
Roland McGrathd81f1d92003-01-09 06:53:34 +00001258
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001259# include "syscall.h"
Roland McGrath3291ef22008-05-20 00:34:34 +00001260
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001261# include <sys/syscall.h>
1262# ifndef CLONE_PTRACE
1263# define CLONE_PTRACE 0x00002000
1264# endif
1265# ifndef CLONE_VFORK
1266# define CLONE_VFORK 0x00004000
1267# endif
1268# ifndef CLONE_VM
1269# define CLONE_VM 0x00000100
1270# endif
1271# ifndef CLONE_STOPPED
1272# define CLONE_STOPPED 0x02000000
1273# endif
Roland McGrathd81f1d92003-01-09 06:53:34 +00001274
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001275# ifdef IA64
Roland McGrathd81f1d92003-01-09 06:53:34 +00001276
Roland McGrath08267b82004-02-20 22:56:43 +00001277/* We don't have fork()/vfork() syscalls on ia64 itself, but the ia32
1278 subsystem has them for x86... */
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001279# define SYS_fork 2
1280# define SYS_vfork 190
Roland McGrath08267b82004-02-20 22:56:43 +00001281
Roland McGrathd81f1d92003-01-09 06:53:34 +00001282typedef unsigned long *arg_setup_state;
1283
1284static int
1285arg_setup(struct tcb *tcp, arg_setup_state *state)
1286{
Jan Kratochvil1f942712008-08-06 21:38:52 +00001287 unsigned long cfm, sof, sol;
1288 long bsp;
Roland McGrathd81f1d92003-01-09 06:53:34 +00001289
Jan Kratochvil1f942712008-08-06 21:38:52 +00001290 if (ia32) {
1291 /* Satisfy a false GCC warning. */
1292 *state = NULL;
Roland McGrath08267b82004-02-20 22:56:43 +00001293 return 0;
Jan Kratochvil1f942712008-08-06 21:38:52 +00001294 }
Roland McGrath08267b82004-02-20 22:56:43 +00001295
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001296 if (upeek(tcp, PT_AR_BSP, &bsp) < 0)
Roland McGrathd81f1d92003-01-09 06:53:34 +00001297 return -1;
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001298 if (upeek(tcp, PT_CFM, (long *) &cfm) < 0)
Roland McGrathd81f1d92003-01-09 06:53:34 +00001299 return -1;
1300
1301 sof = (cfm >> 0) & 0x7f;
1302 sol = (cfm >> 7) & 0x7f;
Jan Kratochvil1f942712008-08-06 21:38:52 +00001303 bsp = (long) ia64_rse_skip_regs((unsigned long *) bsp, -sof + sol);
Roland McGrathd81f1d92003-01-09 06:53:34 +00001304
Jan Kratochvil1f942712008-08-06 21:38:52 +00001305 *state = (unsigned long *) bsp;
Roland McGrathd81f1d92003-01-09 06:53:34 +00001306 return 0;
1307}
1308
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001309# define arg_finish_change(tcp, state) 0
Roland McGrathd81f1d92003-01-09 06:53:34 +00001310
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001311# ifdef SYS_fork
Roland McGrathd81f1d92003-01-09 06:53:34 +00001312static int
1313get_arg0 (struct tcb *tcp, arg_setup_state *state, long *valp)
1314{
Roland McGrath08267b82004-02-20 22:56:43 +00001315 int ret;
1316
1317 if (ia32)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001318 ret = upeek (tcp, PT_R11, valp);
Roland McGrath08267b82004-02-20 22:56:43 +00001319 else
1320 ret = umoven (tcp,
1321 (unsigned long) ia64_rse_skip_regs(*state, 0),
1322 sizeof(long), (void *) valp);
1323 return ret;
Roland McGrathd81f1d92003-01-09 06:53:34 +00001324}
1325
1326static int
1327get_arg1 (struct tcb *tcp, arg_setup_state *state, long *valp)
1328{
Roland McGrath08267b82004-02-20 22:56:43 +00001329 int ret;
1330
1331 if (ia32)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001332 ret = upeek (tcp, PT_R9, valp);
Roland McGrath08267b82004-02-20 22:56:43 +00001333 else
1334 ret = umoven (tcp,
1335 (unsigned long) ia64_rse_skip_regs(*state, 1),
1336 sizeof(long), (void *) valp);
1337 return ret;
Roland McGrathd81f1d92003-01-09 06:53:34 +00001338}
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001339# endif
Roland McGrathd81f1d92003-01-09 06:53:34 +00001340
1341static int
1342set_arg0 (struct tcb *tcp, arg_setup_state *state, long val)
1343{
Roland McGrath08267b82004-02-20 22:56:43 +00001344 int req = PTRACE_POKEDATA;
1345 void *ap;
1346
1347 if (ia32) {
1348 ap = (void *) (intptr_t) PT_R11; /* r11 == EBX */
1349 req = PTRACE_POKEUSER;
1350 } else
1351 ap = ia64_rse_skip_regs(*state, 0);
Roland McGratheb9e2e82009-06-02 16:49:22 -07001352 errno = 0;
1353 ptrace(req, tcp->pid, ap, val);
1354 return errno ? -1 : 0;
Roland McGrathd81f1d92003-01-09 06:53:34 +00001355}
1356
1357static int
1358set_arg1 (struct tcb *tcp, arg_setup_state *state, long val)
1359{
Roland McGrath08267b82004-02-20 22:56:43 +00001360 int req = PTRACE_POKEDATA;
1361 void *ap;
1362
1363 if (ia32) {
1364 ap = (void *) (intptr_t) PT_R9; /* r9 == ECX */
1365 req = PTRACE_POKEUSER;
1366 } else
1367 ap = ia64_rse_skip_regs(*state, 1);
Roland McGratheb9e2e82009-06-02 16:49:22 -07001368 errno = 0;
1369 ptrace(req, tcp->pid, ap, val);
1370 return errno ? -1 : 0;
Roland McGrathd81f1d92003-01-09 06:53:34 +00001371}
1372
Roland McGrathb659f872008-07-18 01:19:36 +00001373/* ia64 does not return the input arguments from functions (and syscalls)
1374 according to ia64 RSE (Register Stack Engine) behavior. */
1375
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001376# define restore_arg0(tcp, state, val) ((void) (state), 0)
1377# define restore_arg1(tcp, state, val) ((void) (state), 0)
Roland McGrathb659f872008-07-18 01:19:36 +00001378
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001379# elif defined (SPARC) || defined (SPARC64)
Roland McGrathd81f1d92003-01-09 06:53:34 +00001380
Mike Frysinger8566c502009-10-12 11:05:14 -04001381typedef struct pt_regs arg_setup_state;
Roland McGrathd81f1d92003-01-09 06:53:34 +00001382
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001383# define arg_setup(tcp, state) \
Roland McGratheb9e2e82009-06-02 16:49:22 -07001384 (ptrace (PTRACE_GETREGS, tcp->pid, (char *) (state), 0))
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001385# define arg_finish_change(tcp, state) \
Roland McGratheb9e2e82009-06-02 16:49:22 -07001386 (ptrace (PTRACE_SETREGS, tcp->pid, (char *) (state), 0))
Roland McGrathd81f1d92003-01-09 06:53:34 +00001387
Mike Frysinger8566c502009-10-12 11:05:14 -04001388# define get_arg0(tcp, state, valp) (*(valp) = (state)->u_regs[U_REG_O0], 0)
1389# define get_arg1(tcp, state, valp) (*(valp) = (state)->u_regs[U_REG_O1], 0)
1390# define set_arg0(tcp, state, val) ((state)->u_regs[U_REG_O0] = (val), 0)
1391# define set_arg1(tcp, state, val) ((state)->u_regs[U_REG_O1] = (val), 0)
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001392# define restore_arg0(tcp, state, val) 0
Roland McGrathd81f1d92003-01-09 06:53:34 +00001393
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001394# else /* other architectures */
Roland McGrathd81f1d92003-01-09 06:53:34 +00001395
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001396# if defined S390 || defined S390X
Roland McGrath7b308222003-01-20 09:04:36 +00001397/* Note: this is only true for the `clone' system call, which handles
1398 arguments specially. We could as well say that its first two arguments
1399 are swapped relative to other architectures, but that would just be
1400 another #ifdef in the calls. */
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001401# define arg0_offset PT_GPR3
1402# define arg1_offset PT_ORIGGPR2
1403# define restore_arg0(tcp, state, val) ((void) (state), 0)
1404# define restore_arg1(tcp, state, val) ((void) (state), 0)
1405# define arg0_index 1
1406# define arg1_index 0
1407# elif defined (ALPHA) || defined (MIPS)
1408# define arg0_offset REG_A0
1409# define arg1_offset (REG_A0+1)
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00001410# elif defined (AVR32)
1411# define arg0_offset (REG_R12)
1412# define arg1_offset (REG_R11)
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001413# elif defined (POWERPC)
1414# define arg0_offset (sizeof(unsigned long)*PT_R3)
1415# define arg1_offset (sizeof(unsigned long)*PT_R4)
1416# define restore_arg0(tcp, state, val) ((void) (state), 0)
1417# elif defined (HPPA)
1418# define arg0_offset PT_GR26
1419# define arg1_offset (PT_GR26-4)
1420# elif defined (X86_64)
1421# define arg0_offset ((long)(8*(current_personality ? RBX : RDI)))
1422# define arg1_offset ((long)(8*(current_personality ? RCX : RSI)))
1423# elif defined (SH)
1424# define arg0_offset (4*(REG_REG0+4))
1425# define arg1_offset (4*(REG_REG0+5))
1426# elif defined (SH64)
1427 /* ABI defines arg0 & 1 in r2 & r3 */
1428# define arg0_offset (REG_OFFSET+16)
1429# define arg1_offset (REG_OFFSET+24)
1430# define restore_arg0(tcp, state, val) 0
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001431# elif defined CRISV10 || defined CRISV32
1432# define arg0_offset (4*PT_R11)
1433# define arg1_offset (4*PT_ORIG_R10)
1434# define restore_arg0(tcp, state, val) 0
1435# define restore_arg1(tcp, state, val) 0
1436# define arg0_index 1
1437# define arg1_index 0
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001438# else
1439# define arg0_offset 0
1440# define arg1_offset 4
1441# if defined ARM
1442# define restore_arg0(tcp, state, val) 0
1443# endif
1444# endif
Roland McGrathd81f1d92003-01-09 06:53:34 +00001445
1446typedef int arg_setup_state;
1447
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001448# define arg_setup(tcp, state) (0)
1449# define arg_finish_change(tcp, state) 0
1450# define get_arg0(tcp, cookie, valp) \
1451 (upeek ((tcp), arg0_offset, (valp)))
1452# define get_arg1(tcp, cookie, valp) \
1453 (upeek ((tcp), arg1_offset, (valp)))
Roland McGrathd81f1d92003-01-09 06:53:34 +00001454
1455static int
Roland McGratheb9e2e82009-06-02 16:49:22 -07001456set_arg0 (struct tcb *tcp, void *cookie, long val)
Roland McGrathd81f1d92003-01-09 06:53:34 +00001457{
Roland McGratheb9e2e82009-06-02 16:49:22 -07001458 return ptrace (PTRACE_POKEUSER, tcp->pid, (char*)arg0_offset, val);
Roland McGrathd81f1d92003-01-09 06:53:34 +00001459}
1460
1461static int
Roland McGratheb9e2e82009-06-02 16:49:22 -07001462set_arg1 (struct tcb *tcp, void *cookie, long val)
Roland McGrathd81f1d92003-01-09 06:53:34 +00001463{
Roland McGratheb9e2e82009-06-02 16:49:22 -07001464 return ptrace (PTRACE_POKEUSER, tcp->pid, (char*)arg1_offset, val);
Roland McGrathd81f1d92003-01-09 06:53:34 +00001465}
1466
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001467# endif /* architectures */
Roland McGrathd81f1d92003-01-09 06:53:34 +00001468
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001469# ifndef restore_arg0
1470# define restore_arg0(tcp, state, val) set_arg0((tcp), (state), (val))
1471# endif
1472# ifndef restore_arg1
1473# define restore_arg1(tcp, state, val) set_arg1((tcp), (state), (val))
1474# endif
Roland McGrathd81f1d92003-01-09 06:53:34 +00001475
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001476# ifndef arg0_index
1477# define arg0_index 0
1478# define arg1_index 1
1479# endif
Roland McGrath90d0afd2004-03-01 21:05:16 +00001480
Roland McGrathd81f1d92003-01-09 06:53:34 +00001481int
Denys Vlasenko418d66a2009-01-17 01:52:54 +00001482setbpt(struct tcb *tcp)
Roland McGrathd81f1d92003-01-09 06:53:34 +00001483{
Roland McGrath3291ef22008-05-20 00:34:34 +00001484 static int clone_scno[SUPPORTED_PERSONALITIES] = { SYS_clone };
Roland McGrathd81f1d92003-01-09 06:53:34 +00001485 arg_setup_state state;
1486
1487 if (tcp->flags & TCB_BPTSET) {
1488 fprintf(stderr, "PANIC: TCB already set in pid %u\n", tcp->pid);
1489 return -1;
1490 }
1491
Roland McGrath3291ef22008-05-20 00:34:34 +00001492 /*
1493 * It's a silly kludge to initialize this with a search at runtime.
1494 * But it's better than maintaining another magic thing in the
1495 * godforsaken tables.
1496 */
1497 if (clone_scno[current_personality] == 0) {
1498 int i;
1499 for (i = 0; i < nsyscalls; ++i)
1500 if (sysent[i].sys_func == sys_clone) {
1501 clone_scno[current_personality] = i;
1502 break;
1503 }
1504 }
1505
Roland McGrath76989d72005-06-07 23:21:31 +00001506 switch (known_scno(tcp)) {
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001507# ifdef SYS_vfork
Roland McGrath9383c6c2003-01-18 00:19:31 +00001508 case SYS_vfork:
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001509# endif
1510# ifdef SYS_fork
Roland McGrathd81f1d92003-01-09 06:53:34 +00001511 case SYS_fork:
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001512# endif
1513# if defined SYS_fork || defined SYS_vfork
Roland McGrathd81f1d92003-01-09 06:53:34 +00001514 if (arg_setup (tcp, &state) < 0
1515 || get_arg0 (tcp, &state, &tcp->inst[0]) < 0
1516 || get_arg1 (tcp, &state, &tcp->inst[1]) < 0
Roland McGrath3291ef22008-05-20 00:34:34 +00001517 || change_syscall(tcp, clone_scno[current_personality]) < 0
Roland McGrathd81f1d92003-01-09 06:53:34 +00001518 || set_arg0 (tcp, &state, CLONE_PTRACE|SIGCHLD) < 0
1519 || set_arg1 (tcp, &state, 0) < 0
1520 || arg_finish_change (tcp, &state) < 0)
1521 return -1;
Roland McGrathc9dc3c12004-03-01 20:57:09 +00001522 tcp->u_arg[arg0_index] = CLONE_PTRACE|SIGCHLD;
1523 tcp->u_arg[arg1_index] = 0;
Roland McGrathd81f1d92003-01-09 06:53:34 +00001524 tcp->flags |= TCB_BPTSET;
1525 return 0;
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001526# endif
Roland McGrathd81f1d92003-01-09 06:53:34 +00001527
1528 case SYS_clone:
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001529# ifdef SYS_clone2
Roland McGrathd81f1d92003-01-09 06:53:34 +00001530 case SYS_clone2:
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001531# endif
Jan Kratochvil8fc95752008-08-06 21:43:35 +00001532 /* ia64 calls directly `clone (CLONE_VFORK | CLONE_VM)'
1533 contrary to x86 SYS_vfork above. Even on x86 we turn the
1534 vfork semantics into plain fork - each application must not
1535 depend on the vfork specifics according to POSIX. We would
1536 hang waiting for the parent resume otherwise. We need to
1537 clear also CLONE_VM but only in the CLONE_VFORK case as
1538 otherwise we would break pthread_create. */
1539
Roland McGrathd6ff0d52008-07-18 01:09:44 +00001540 if ((arg_setup (tcp, &state) < 0
1541 || set_arg0 (tcp, &state,
1542 (tcp->u_arg[arg0_index] | CLONE_PTRACE)
Jan Kratochvil8fc95752008-08-06 21:43:35 +00001543 & ~(tcp->u_arg[arg0_index] & CLONE_VFORK
1544 ? CLONE_VFORK | CLONE_VM : 0)) < 0
Roland McGrathd6ff0d52008-07-18 01:09:44 +00001545 || arg_finish_change (tcp, &state) < 0))
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00001546 return -1;
Roland McGrathd81f1d92003-01-09 06:53:34 +00001547 tcp->flags |= TCB_BPTSET;
Roland McGrathc9dc3c12004-03-01 20:57:09 +00001548 tcp->inst[0] = tcp->u_arg[arg0_index];
1549 tcp->inst[1] = tcp->u_arg[arg1_index];
Roland McGrathd81f1d92003-01-09 06:53:34 +00001550 return 0;
1551
1552 default:
1553 fprintf(stderr, "PANIC: setbpt for syscall %ld on %u???\n",
1554 tcp->scno, tcp->pid);
1555 break;
1556 }
1557
1558 return -1;
1559}
1560
1561int
1562clearbpt(tcp)
1563struct tcb *tcp;
1564{
1565 arg_setup_state state;
1566 if (arg_setup (tcp, &state) < 0
Roland McGrathe1df47f2003-01-14 09:46:15 +00001567 || restore_arg0 (tcp, &state, tcp->inst[0]) < 0
1568 || restore_arg1 (tcp, &state, tcp->inst[1]) < 0
Roland McGrathd81f1d92003-01-09 06:53:34 +00001569 || arg_finish_change (tcp, &state))
Andreas Schwab46ed50d2009-11-11 13:54:04 +01001570 if (errno != ESRCH) return -1;
Roland McGrathd81f1d92003-01-09 06:53:34 +00001571 tcp->flags &= ~TCB_BPTSET;
1572 return 0;
1573}
1574
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001575# else /* !defined LINUX */
Roland McGrathd81f1d92003-01-09 06:53:34 +00001576
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001577int
1578setbpt(tcp)
1579struct tcb *tcp;
1580{
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001581# ifdef SUNOS4
1582# ifdef SPARC /* This code is slightly sparc specific */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001583
Wichert Akkermane6f876c1999-06-22 15:28:30 +00001584 struct regs regs;
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001585# define BPT 0x91d02001 /* ta 1 */
1586# define LOOP 0x10800000 /* ba 0 */
1587# define LOOPA 0x30800000 /* ba,a 0 */
1588# define NOP 0x01000000
1589# if LOOPA
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001590 static int loopdeloop[1] = {LOOPA};
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001591# else
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001592 static int loopdeloop[2] = {LOOP, NOP};
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001593# endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001594
1595 if (tcp->flags & TCB_BPTSET) {
1596 fprintf(stderr, "PANIC: TCB already set in pid %u\n", tcp->pid);
1597 return -1;
1598 }
Roland McGratheb9e2e82009-06-02 16:49:22 -07001599 if (ptrace(PTRACE_GETREGS, tcp->pid, (char *)&regs, 0) < 0) {
1600 perror("setbpt: ptrace(PTRACE_GETREGS, ...)");
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001601 return -1;
1602 }
1603 tcp->baddr = regs.r_o7 + 8;
Roland McGratheb9e2e82009-06-02 16:49:22 -07001604 if (ptrace(PTRACE_READTEXT, tcp->pid, (char *)tcp->baddr,
1605 sizeof tcp->inst, (char *)tcp->inst) < 0) {
1606 perror("setbpt: ptrace(PTRACE_READTEXT, ...)");
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001607 return -1;
1608 }
1609
1610 /*
1611 * XXX - BRUTAL MODE ON
1612 * We cannot set a real BPT in the child, since it will not be
1613 * traced at the moment it will reach the trap and would probably
1614 * die with a core dump.
1615 * Thus, we are force our way in by taking out two instructions
1616 * and insert an eternal loop in stead, in expectance of the SIGSTOP
1617 * generated by out PTRACE_ATTACH.
1618 * Of cause, if we evaporate ourselves in the middle of all this...
1619 */
Roland McGratheb9e2e82009-06-02 16:49:22 -07001620 if (ptrace(PTRACE_WRITETEXT, tcp->pid, (char *) tcp->baddr,
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001621 sizeof loopdeloop, (char *) loopdeloop) < 0) {
Roland McGratheb9e2e82009-06-02 16:49:22 -07001622 perror("setbpt: ptrace(PTRACE_WRITETEXT, ...)");
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001623 return -1;
1624 }
1625 tcp->flags |= TCB_BPTSET;
1626
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001627# endif /* SPARC */
1628# endif /* SUNOS4 */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001629
1630 return 0;
1631}
1632
1633int
1634clearbpt(tcp)
1635struct tcb *tcp;
1636{
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001637# ifdef SUNOS4
1638# ifdef SPARC
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001639
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001640# if !LOOPA
Wichert Akkermane6f876c1999-06-22 15:28:30 +00001641 struct regs regs;
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001642# endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001643
1644 if (!(tcp->flags & TCB_BPTSET)) {
1645 fprintf(stderr, "PANIC: TCB not set in pid %u\n", tcp->pid);
1646 return -1;
1647 }
Roland McGratheb9e2e82009-06-02 16:49:22 -07001648 if (ptrace(PTRACE_WRITETEXT, tcp->pid, (char *) tcp->baddr,
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001649 sizeof tcp->inst, (char *) tcp->inst) < 0) {
Roland McGratheb9e2e82009-06-02 16:49:22 -07001650 perror("clearbtp: ptrace(PTRACE_WRITETEXT, ...)");
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001651 return -1;
1652 }
1653 tcp->flags &= ~TCB_BPTSET;
1654
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001655# if !LOOPA
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001656 /*
1657 * Since we don't have a single instruction breakpoint, we may have
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001658 * to adjust the program counter after removing our `breakpoint'.
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001659 */
Roland McGratheb9e2e82009-06-02 16:49:22 -07001660 if (ptrace(PTRACE_GETREGS, tcp->pid, (char *)&regs, 0) < 0) {
1661 perror("clearbpt: ptrace(PTRACE_GETREGS, ...)");
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001662 return -1;
1663 }
Roland McGratheb9e2e82009-06-02 16:49:22 -07001664 if ((regs.r_pc < tcp->baddr) ||
1665 (regs.r_pc > tcp->baddr + 4)) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001666 /* The breakpoint has not been reached yet */
1667 if (debug)
1668 fprintf(stderr,
1669 "NOTE: PC not at bpt (pc %#x baddr %#x)\n",
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001670 regs.r_pc, tcp->baddr);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001671 return 0;
1672 }
1673 if (regs.r_pc != tcp->baddr)
1674 if (debug)
1675 fprintf(stderr, "NOTE: PC adjusted (%#x -> %#x\n",
1676 regs.r_pc, tcp->baddr);
1677
1678 regs.r_pc = tcp->baddr;
Roland McGratheb9e2e82009-06-02 16:49:22 -07001679 if (ptrace(PTRACE_SETREGS, tcp->pid, (char *)&regs, 0) < 0) {
1680 perror("clearbpt: ptrace(PTRACE_SETREGS, ...)");
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001681 return -1;
1682 }
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001683# endif /* LOOPA */
1684# endif /* SPARC */
1685# endif /* SUNOS4 */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001686
1687 return 0;
1688}
1689
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001690# endif /* !defined LINUX */
Roland McGrathd81f1d92003-01-09 06:53:34 +00001691
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001692#endif /* !USE_PROCFS */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001693
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001694
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001695#ifdef SUNOS4
1696
1697static int
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001698getex(tcp, hdr)
1699struct tcb *tcp;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001700struct exec *hdr;
1701{
1702 int n;
1703
1704 for (n = 0; n < sizeof *hdr; n += 4) {
1705 long res;
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001706 if (upeek(tcp, uoff(u_exdata) + n, &res) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001707 return -1;
1708 memcpy(((char *) hdr) + n, &res, 4);
1709 }
1710 if (debug) {
1711 fprintf(stderr, "[struct exec: magic: %o version %u Mach %o\n",
1712 hdr->a_magic, hdr->a_toolversion, hdr->a_machtype);
1713 fprintf(stderr, "Text %lu Data %lu Bss %lu Syms %lu Entry %#lx]\n",
1714 hdr->a_text, hdr->a_data, hdr->a_bss, hdr->a_syms, hdr->a_entry);
1715 }
1716 return 0;
1717}
1718
1719int
1720fixvfork(tcp)
1721struct tcb *tcp;
1722{
1723 int pid = tcp->pid;
1724 /*
1725 * Change `vfork' in a freshly exec'ed dynamically linked
1726 * executable's (internal) symbol table to plain old `fork'
1727 */
1728
1729 struct exec hdr;
1730 struct link_dynamic dyn;
1731 struct link_dynamic_2 ld;
1732 char *strtab, *cp;
1733
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001734 if (getex(tcp, &hdr) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001735 return -1;
1736 if (!hdr.a_dynamic)
1737 return -1;
1738
1739 if (umove(tcp, (int) N_DATADDR(hdr), &dyn) < 0) {
1740 fprintf(stderr, "Cannot read DYNAMIC\n");
1741 return -1;
1742 }
1743 if (umove(tcp, (int) dyn.ld_un.ld_2, &ld) < 0) {
1744 fprintf(stderr, "Cannot read link_dynamic_2\n");
1745 return -1;
1746 }
1747 if ((strtab = malloc((unsigned)ld.ld_symb_size)) == NULL) {
Roland McGrath46100d02005-06-01 18:55:42 +00001748 fprintf(stderr, "out of memory\n");
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001749 return -1;
1750 }
Roland McGratheb9e2e82009-06-02 16:49:22 -07001751 if (umoven(tcp, (int)ld.ld_symbols+(int)N_TXTADDR(hdr),
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001752 (int)ld.ld_symb_size, strtab) < 0)
1753 goto err;
1754
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001755 for (cp = strtab; cp < strtab + ld.ld_symb_size; ) {
1756 if (strcmp(cp, "_vfork") == 0) {
1757 if (debug)
1758 fprintf(stderr, "fixvfork: FOUND _vfork\n");
1759 strcpy(cp, "_fork");
1760 break;
1761 }
1762 cp += strlen(cp)+1;
1763 }
1764 if (cp < strtab + ld.ld_symb_size)
1765 /*
1766 * Write entire symbol table back to avoid
1767 * memory alignment bugs in ptrace
1768 */
Roland McGratheb9e2e82009-06-02 16:49:22 -07001769 if (tload(pid, (int)ld.ld_symbols+(int)N_TXTADDR(hdr),
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001770 (int)ld.ld_symb_size, strtab) < 0)
1771 goto err;
1772
1773 free(strtab);
1774 return 0;
1775
1776err:
1777 free(strtab);
1778 return -1;
1779}
1780
1781#endif /* SUNOS4 */