blob: bd12c0f7b1480a404e26e82bf0a2e81a041cbba4 [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) \
254 || (defined(LINUX) && defined(POWERPC) && !defined(__powerpc64__)) \
255 || defined (LINUX_MIPSO32)
256 /* Align 64bit argument to 64bit boundary. */
257 if (llarg % 2) llarg++;
258# endif
259# if defined LINUX && defined X86_64
260 if (current_personality == 0) {
261 tprintf(format, tcp->u_arg[llarg]);
262 llarg++;
263 } else {
264 tprintf(format, LONG_LONG(tcp->u_arg[llarg], tcp->u_arg[llarg + 1]));
265 llarg += 2;
266 }
267# elif defined IA64 || defined ALPHA || (defined POWERPC && defined __powerpc64__)
268 tprintf(format, tcp->u_arg[llarg]);
269 llarg++;
270# elif defined LINUX_MIPSN32
271 tprintf(format, tcp->ext_arg[llarg]);
272 llarg++;
273# else
274 tprintf(format, LONG_LONG(tcp->u_arg[llarg], tcp->u_arg[llarg + 1]));
275 llarg += 2;
276# endif
277 return llarg;
278}
279#endif
280
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000281/*
282 * Interpret `xlat' as an array of flags
283 * print the entries whose bits are on in `flags'
284 * return # of flags printed.
285 */
286int
287addflags(xlat, flags)
Roland McGrathd9f816f2004-09-04 03:39:20 +0000288const struct xlat *xlat;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000289int flags;
290{
291 int n;
292
293 for (n = 0; xlat->str; xlat++) {
294 if (xlat->val && (flags & xlat->val) == xlat->val) {
295 tprintf("|%s", xlat->str);
296 flags &= ~xlat->val;
297 n++;
298 }
299 }
300 if (flags) {
301 tprintf("|%#x", flags);
302 n++;
303 }
304 return n;
305}
306
Roland McGratha6c0d8c2007-11-01 21:46:22 +0000307/*
308 * Interpret `xlat' as an array of flags/
309 * Print to static string the entries whose bits are on in `flags'
310 * Return static string.
311 */
312const char *
313sprintflags(const char *prefix, const struct xlat *xlat, int flags)
314{
315 static char outstr[1024];
316 int found = 0;
317
318 strcpy(outstr, prefix);
319
320 for (; xlat->str; xlat++) {
321 if ((flags & xlat->val) == xlat->val) {
322 if (found)
323 strcat(outstr, "|");
324 strcat(outstr, xlat->str);
325 flags &= ~xlat->val;
326 found = 1;
327 }
328 }
329 if (flags) {
330 if (found)
331 strcat(outstr, "|");
332 sprintf(outstr + strlen(outstr), "%#x", flags);
333 }
334
335 return outstr;
336}
337
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000338int
Roland McGrathb2dee132005-06-01 19:02:36 +0000339printflags(xlat, flags, dflt)
Roland McGrathd9f816f2004-09-04 03:39:20 +0000340const struct xlat *xlat;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000341int flags;
Roland McGrathb2dee132005-06-01 19:02:36 +0000342const char *dflt;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000343{
344 int n;
345 char *sep;
346
347 if (flags == 0 && xlat->val == 0) {
348 tprintf("%s", xlat->str);
349 return 1;
350 }
351
352 sep = "";
353 for (n = 0; xlat->str; xlat++) {
354 if (xlat->val && (flags & xlat->val) == xlat->val) {
355 tprintf("%s%s", sep, xlat->str);
356 flags &= ~xlat->val;
357 sep = "|";
358 n++;
359 }
360 }
Roland McGrathb2dee132005-06-01 19:02:36 +0000361
362 if (n) {
363 if (flags) {
364 tprintf("%s%#x", sep, flags);
365 n++;
366 }
367 } else {
368 if (flags) {
369 tprintf("%#x", flags);
370 if (dflt)
371 tprintf(" /* %s */", dflt);
372 } else {
373 if (dflt)
374 tprintf("0");
375 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000376 }
Roland McGrathb2dee132005-06-01 19:02:36 +0000377
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000378 return n;
379}
380
381void
382printnum(tcp, addr, fmt)
383struct tcb *tcp;
384long addr;
385char *fmt;
386{
Roland McGratheb285352003-01-14 09:59:00 +0000387 long num;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000388
389 if (!addr) {
390 tprintf("NULL");
391 return;
392 }
393 if (umove(tcp, addr, &num) < 0) {
394 tprintf("%#lx", addr);
395 return;
396 }
397 tprintf("[");
398 tprintf(fmt, num);
399 tprintf("]");
400}
401
Roland McGrath6bc12202003-11-13 22:32:27 +0000402void
Roland McGrath9814a942005-07-04 23:28:10 +0000403printnum_int(tcp, addr, fmt)
404struct tcb *tcp;
405long addr;
406char *fmt;
407{
408 int num;
409
410 if (!addr) {
411 tprintf("NULL");
412 return;
413 }
414 if (umove(tcp, addr, &num) < 0) {
415 tprintf("%#lx", addr);
416 return;
417 }
418 tprintf("[");
419 tprintf(fmt, num);
420 tprintf("]");
421}
422
423void
Roland McGrath6bc12202003-11-13 22:32:27 +0000424printuid(text, uid)
425const char *text;
426unsigned long uid;
427{
428 tprintf("%s", text);
429 tprintf((uid == -1) ? "%ld" : "%lu", uid);
430}
431
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000432static char path[MAXPATHLEN + 1];
433
Dmitry V. Levina501f142008-11-10 23:19:13 +0000434/*
435 * Quote string `instr' of length `size'
436 * Write up to (3 + `size' * 4) bytes to `outstr' buffer.
437 * If `len' < 0, treat `instr' as a NUL-terminated string
438 * and quote at most (`size' - 1) bytes.
439 */
Roland McGrath6d970322007-11-01 23:53:59 +0000440static int
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000441string_quote(const char *instr, char *outstr, int len, int size)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000442{
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000443 const unsigned char *ustr = (const unsigned char *) instr;
444 char *s = outstr;
445 int usehex = 0, c, i;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000446
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000447 if (xflag > 1)
448 usehex = 1;
449 else if (xflag) {
Dmitry V. Levina501f142008-11-10 23:19:13 +0000450 /* Check for presence of symbol which require
451 to hex-quote the whole string. */
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000452 for (i = 0; i < size; ++i) {
453 c = ustr[i];
Dmitry V. Levina501f142008-11-10 23:19:13 +0000454 /* Check for NUL-terminated string. */
455 if (len < 0) {
456 if (c == '\0')
457 break;
458 /* Quote at most size - 1 bytes. */
459 if (i == size - 1)
460 continue;
461 }
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000462 if (!isprint(c) && !isspace(c)) {
463 usehex = 1;
464 break;
465 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000466 }
467 }
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000468
469 *s++ = '\"';
470
471 if (usehex) {
Dmitry V. Levina501f142008-11-10 23:19:13 +0000472 /* Hex-quote the whole string. */
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000473 for (i = 0; i < size; ++i) {
474 c = ustr[i];
Dmitry V. Levina501f142008-11-10 23:19:13 +0000475 /* Check for NUL-terminated string. */
476 if (len < 0) {
477 if (c == '\0')
478 break;
479 /* Quote at most size - 1 bytes. */
480 if (i == size - 1)
481 continue;
482 }
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000483 sprintf(s, "\\x%02x", c);
484 s += 4;
485 }
486 } else {
487 for (i = 0; i < size; ++i) {
488 c = ustr[i];
Dmitry V. Levina501f142008-11-10 23:19:13 +0000489 /* Check for NUL-terminated string. */
490 if (len < 0) {
491 if (c == '\0')
492 break;
493 /* Quote at most size - 1 bytes. */
494 if (i == size - 1)
495 continue;
496 }
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000497 switch (c) {
498 case '\"': case '\\':
499 *s++ = '\\';
500 *s++ = c;
501 break;
502 case '\f':
503 *s++ = '\\';
504 *s++ = 'f';
505 break;
506 case '\n':
507 *s++ = '\\';
508 *s++ = 'n';
509 break;
510 case '\r':
511 *s++ = '\\';
512 *s++ = 'r';
513 break;
514 case '\t':
515 *s++ = '\\';
516 *s++ = 't';
517 break;
518 case '\v':
519 *s++ = '\\';
520 *s++ = 'v';
521 break;
522 default:
523 if (isprint(c))
524 *s++ = c;
525 else if (i + 1 < size
526 && isdigit(ustr[i + 1])) {
527 sprintf(s, "\\%03o", c);
528 s += 4;
529 } else {
530 sprintf(s, "\\%o", c);
531 s += strlen(s);
532 }
533 break;
534 }
535 }
536 }
537
538 *s++ = '\"';
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000539 *s = '\0';
Roland McGrath6d970322007-11-01 23:53:59 +0000540
541 /* Return nonzero if the string was unterminated. */
542 return i == size;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000543}
544
Dmitry V. Levina501f142008-11-10 23:19:13 +0000545/*
546 * Print path string specified by address `addr' and length `n'.
547 * If path length exceeds `n', append `...' to the output.
548 */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000549void
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000550printpathn(struct tcb *tcp, long addr, int n)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000551{
Dmitry V. Levina501f142008-11-10 23:19:13 +0000552 if (!addr) {
Roland McGrath371ed8f2005-02-06 01:55:07 +0000553 tprintf("NULL");
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000554 return;
555 }
556
Dmitry V. Levina501f142008-11-10 23:19:13 +0000557 /* Cap path length to the path buffer size,
558 and NUL-terminate the buffer. */
559 if (n > sizeof path - 1)
560 n = sizeof path - 1;
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000561 path[n] = '\0';
Dmitry V. Levina501f142008-11-10 23:19:13 +0000562
563 /* Fetch one byte more to find out whether path length > n. */
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000564 if (umovestr(tcp, addr, n + 1, path) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000565 tprintf("%#lx", addr);
566 else {
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000567 static char outstr[4*(sizeof path - 1) + sizeof "\"...\""];
568 int trunc = (path[n] != '\0');
569
570 if (trunc)
571 path[n] = '\0';
Dmitry V. Levina501f142008-11-10 23:19:13 +0000572 (void) string_quote(path, outstr, -1, n + 1);
573 if (trunc)
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000574 strcat(outstr, "...");
575 tprintf("%s", outstr);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000576 }
577}
578
579void
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000580printpath(struct tcb *tcp, long addr)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000581{
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000582 printpathn(tcp, addr, sizeof path - 1);
583}
584
Dmitry V. Levina501f142008-11-10 23:19:13 +0000585/*
586 * Print string specified by address `addr' and length `len'.
587 * If `len' < 0, treat the string as a NUL-terminated string.
588 * If string length exceeds `max_strlen', append `...' to the output.
589 */
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000590void
591printstr(struct tcb *tcp, long addr, int len)
592{
593 static char *str = NULL;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000594 static char *outstr;
Roland McGrath6d970322007-11-01 23:53:59 +0000595 int size;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000596
597 if (!addr) {
598 tprintf("NULL");
599 return;
600 }
Dmitry V. Levina501f142008-11-10 23:19:13 +0000601 /* Allocate static buffers if they are not allocated yet. */
602 if (!str)
603 str = malloc(max_strlen + 1);
604 if (!outstr)
605 outstr = malloc(4 * max_strlen + sizeof "\"...\"");
606 if (!str || !outstr) {
607 fprintf(stderr, "out of memory\n");
608 tprintf("%#lx", addr);
609 return;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000610 }
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000611
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000612 if (len < 0) {
Dmitry V. Levina501f142008-11-10 23:19:13 +0000613 /*
614 * Treat as a NUL-terminated string: fetch one byte more
615 * because string_quote() quotes one byte less.
616 */
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000617 size = max_strlen + 1;
Dmitry V. Levina501f142008-11-10 23:19:13 +0000618 str[max_strlen] = '\0';
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000619 if (umovestr(tcp, addr, size, str) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000620 tprintf("%#lx", addr);
621 return;
622 }
623 }
624 else {
Dmitry V. Levina501f142008-11-10 23:19:13 +0000625 size = MIN(len, max_strlen);
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000626 if (umoven(tcp, addr, size, str) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000627 tprintf("%#lx", addr);
628 return;
629 }
630 }
631
Dmitry V. Levina501f142008-11-10 23:19:13 +0000632 if (string_quote(str, outstr, len, size) &&
633 (len < 0 || len > max_strlen))
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000634 strcat(outstr, "...");
Roland McGratha503dcf2007-08-02 02:06:26 +0000635
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000636 tprintf("%s", outstr);
637}
638
John Hughes1d08dcf2001-07-10 13:48:44 +0000639#if HAVE_SYS_UIO_H
640void
641dumpiov(tcp, len, addr)
642struct tcb * tcp;
643int len;
644long addr;
645{
Dmitry V. Levin4ebb4e32006-12-13 17:08:08 +0000646#if defined(LINUX) && SUPPORTED_PERSONALITIES > 1
647 union {
648 struct { u_int32_t base; u_int32_t len; } *iov32;
649 struct { u_int64_t base; u_int64_t len; } *iov64;
650 } iovu;
651#define iov iovu.iov64
652#define sizeof_iov \
653 (personality_wordsize[current_personality] == 4 \
654 ? sizeof(*iovu.iov32) : sizeof(*iovu.iov64))
655#define iov_iov_base(i) \
656 (personality_wordsize[current_personality] == 4 \
657 ? (u_int64_t) iovu.iov32[i].base : iovu.iov64[i].base)
658#define iov_iov_len(i) \
659 (personality_wordsize[current_personality] == 4 \
660 ? (u_int64_t) iovu.iov32[i].len : iovu.iov64[i].len)
661#else
John Hughes1d08dcf2001-07-10 13:48:44 +0000662 struct iovec *iov;
Dmitry V. Levin4ebb4e32006-12-13 17:08:08 +0000663#define sizeof_iov sizeof(*iov)
664#define iov_iov_base(i) iov[i].iov_base
665#define iov_iov_len(i) iov[i].iov_len
666#endif
John Hughes1d08dcf2001-07-10 13:48:44 +0000667 int i;
Roland McGrathaa524c82005-06-01 19:22:06 +0000668 unsigned long size;
John Hughes1d08dcf2001-07-10 13:48:44 +0000669
Dmitry V. Levin4ebb4e32006-12-13 17:08:08 +0000670 size = sizeof_iov * (unsigned long) len;
671 if (size / sizeof_iov != len
672 || (iov = malloc(size)) == NULL) {
Roland McGrathaa524c82005-06-01 19:22:06 +0000673 fprintf(stderr, "out of memory\n");
John Hughes1d08dcf2001-07-10 13:48:44 +0000674 return;
675 }
Roland McGrathaa524c82005-06-01 19:22:06 +0000676 if (umoven(tcp, addr, size, (char *) iov) >= 0) {
John Hughes1d08dcf2001-07-10 13:48:44 +0000677 for (i = 0; i < len; i++) {
Denys Vlasenkoadedb512008-12-30 18:47:55 +0000678 /* include the buffer number to make it easy to
679 * match up the trace with the source */
680 tprintf(" * %lu bytes in buffer %d\n",
681 (unsigned long)iov_iov_len(i), i);
682 dumpstr(tcp, (long) iov_iov_base(i),
683 iov_iov_len(i));
684 }
John Hughes1d08dcf2001-07-10 13:48:44 +0000685 }
686 free((char *) iov);
Dmitry V. Levin4ebb4e32006-12-13 17:08:08 +0000687#undef sizeof_iov
688#undef iov_iov_base
689#undef iov_iov_len
690#undef iov
John Hughes1d08dcf2001-07-10 13:48:44 +0000691}
692#endif
693
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000694void
695dumpstr(tcp, addr, len)
696struct tcb *tcp;
697long addr;
698int len;
699{
700 static int strsize = -1;
701 static unsigned char *str;
702 static char outstr[80];
703 char *s;
704 int i, j;
705
706 if (strsize < len) {
707 if (str)
708 free(str);
709 if ((str = malloc(len)) == NULL) {
Roland McGrath46100d02005-06-01 18:55:42 +0000710 fprintf(stderr, "out of memory\n");
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000711 return;
712 }
713 strsize = len;
714 }
715
716 if (umoven(tcp, addr, len, (char *) str) < 0)
717 return;
718
719 for (i = 0; i < len; i += 16) {
720 s = outstr;
721 sprintf(s, " | %05x ", i);
722 s += 9;
723 for (j = 0; j < 16; j++) {
724 if (j == 8)
725 *s++ = ' ';
726 if (i + j < len) {
727 sprintf(s, " %02x", str[i + j]);
728 s += 3;
729 }
730 else {
731 *s++ = ' '; *s++ = ' '; *s++ = ' ';
732 }
733 }
734 *s++ = ' '; *s++ = ' ';
735 for (j = 0; j < 16; j++) {
736 if (j == 8)
737 *s++ = ' ';
738 if (i + j < len) {
739 if (isprint(str[i + j]))
740 *s++ = str[i + j];
741 else
742 *s++ = '.';
743 }
744 else
745 *s++ = ' ';
746 }
747 tprintf("%s |\n", outstr);
748 }
749}
750
751#define PAGMASK (~(PAGSIZ - 1))
752/*
753 * move `len' bytes of data from process `pid'
754 * at address `addr' to our space at `laddr'
755 */
756int
Denys Vlasenkoef2fbf82009-01-06 21:45:06 +0000757umoven(struct tcb *tcp, long addr, int len, char *laddr)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000758{
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000759#ifdef LINUX
Roland McGratheb9e2e82009-06-02 16:49:22 -0700760 int pid = tcp->pid;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000761 int n, m;
Wichert Akkerman5daa0281999-03-15 19:49:42 +0000762 int started = 0;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000763 union {
764 long val;
765 char x[sizeof(long)];
766 } u;
767
768 if (addr & (sizeof(long) - 1)) {
769 /* addr not a multiple of sizeof(long) */
770 n = addr - (addr & -sizeof(long)); /* residue */
771 addr &= -sizeof(long); /* residue */
Roland McGratheb9e2e82009-06-02 16:49:22 -0700772 errno = 0;
773 u.val = ptrace(PTRACE_PEEKDATA, pid, (char *) addr, 0);
774 if (errno) {
775 if (started && (errno==EPERM || errno==EIO)) {
776 /* Ran into 'end of memory' - stupid "printpath" */
777 return 0;
778 }
779 /* But if not started, we had a bogus address. */
780 if (addr != 0 && errno != EIO && errno != ESRCH)
781 perror("ptrace: umoven");
782 return -1;
783 }
Wichert Akkerman5daa0281999-03-15 19:49:42 +0000784 started = 1;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000785 memcpy(laddr, &u.x[n], m = MIN(sizeof(long) - n, len));
786 addr += sizeof(long), laddr += m, len -= m;
787 }
788 while (len) {
Roland McGratheb9e2e82009-06-02 16:49:22 -0700789 errno = 0;
790 u.val = ptrace(PTRACE_PEEKDATA, pid, (char *) addr, 0);
791 if (errno) {
792 if (started && (errno==EPERM || errno==EIO)) {
793 /* Ran into 'end of memory' - stupid "printpath" */
794 return 0;
795 }
796 if (addr != 0 && errno != EIO && errno != ESRCH)
797 perror("ptrace: umoven");
798 return -1;
799 }
Wichert Akkerman5daa0281999-03-15 19:49:42 +0000800 started = 1;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000801 memcpy(laddr, u.x, m = MIN(sizeof(long), len));
802 addr += sizeof(long), laddr += m, len -= m;
803 }
804#endif /* LINUX */
805
806#ifdef SUNOS4
807 int pid = tcp->pid;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000808 int n;
809
810 while (len) {
811 n = MIN(len, PAGSIZ);
812 n = MIN(n, ((addr + PAGSIZ) & PAGMASK) - addr);
Roland McGratheb9e2e82009-06-02 16:49:22 -0700813 if (ptrace(PTRACE_READDATA, pid,
814 (char *) addr, len, laddr) < 0) {
815 if (errno != ESRCH) {
816 perror("umoven: ptrace(PTRACE_READDATA, ...)");
817 abort();
818 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000819 return -1;
820 }
821 len -= n;
822 addr += n;
823 laddr += n;
824 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000825#endif /* SUNOS4 */
826
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000827#ifdef USE_PROCFS
Wichert Akkermanea78f0f1999-11-29 15:34:02 +0000828#ifdef HAVE_MP_PROCFS
John Hughesaa09c6b2001-05-15 14:53:43 +0000829 int fd = tcp->pfd_as;
Wichert Akkerman9ce1a631999-08-29 23:15:07 +0000830#else
John Hughesaa09c6b2001-05-15 14:53:43 +0000831 int fd = tcp->pfd;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000832#endif
John Hughesaa09c6b2001-05-15 14:53:43 +0000833 lseek(fd, addr, SEEK_SET);
834 if (read(fd, laddr, len) == -1)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000835 return -1;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000836#endif /* USE_PROCFS */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000837
838 return 0;
839}
840
841/*
842 * like `umove' but make the additional effort of looking
843 * for a terminating zero byte.
844 */
845int
Denys Vlasenkoef2fbf82009-01-06 21:45:06 +0000846umovestr(struct tcb *tcp, long addr, int len, char *laddr)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000847{
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000848#ifdef USE_PROCFS
John Hughesaa09c6b2001-05-15 14:53:43 +0000849#ifdef HAVE_MP_PROCFS
850 int fd = tcp->pfd_as;
851#else
852 int fd = tcp->pfd;
853#endif
854 /* Some systems (e.g. FreeBSD) can be upset if we read off the
855 end of valid memory, avoid this by trying to read up
856 to page boundaries. But we don't know what a page is (and
857 getpagesize(2) (if it exists) doesn't necessarily return
858 hardware page size). Assume all pages >= 1024 (a-historical
859 I know) */
860
861 int page = 1024; /* How to find this? */
862 int move = page - (addr & (page - 1));
863 int left = len;
864
865 lseek(fd, addr, SEEK_SET);
866
867 while (left) {
868 if (move > left) move = left;
John Hughes9cecf7f2001-10-16 10:20:22 +0000869 if ((move = read(fd, laddr, move)) <= 0)
John Hughesaa09c6b2001-05-15 14:53:43 +0000870 return left != len ? 0 : -1;
871 if (memchr (laddr, 0, move)) break;
872 left -= move;
873 laddr += move;
874 addr += move;
875 move = page;
876 }
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000877#else /* !USE_PROCFS */
Wichert Akkerman5daa0281999-03-15 19:49:42 +0000878 int started = 0;
Roland McGratheb9e2e82009-06-02 16:49:22 -0700879 int pid = tcp->pid;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000880 int i, n, m;
881 union {
882 long val;
883 char x[sizeof(long)];
884 } u;
885
886 if (addr & (sizeof(long) - 1)) {
887 /* addr not a multiple of sizeof(long) */
888 n = addr - (addr & -sizeof(long)); /* residue */
889 addr &= -sizeof(long); /* residue */
Roland McGratheb9e2e82009-06-02 16:49:22 -0700890 errno = 0;
891 u.val = ptrace(PTRACE_PEEKDATA, pid, (char *)addr, 0);
892 if (errno) {
893 if (started && (errno==EPERM || errno==EIO)) {
894 /* Ran into 'end of memory' - stupid "printpath" */
895 return 0;
896 }
897 if (addr != 0 && errno != EIO && errno != ESRCH)
898 perror("umovestr");
899 return -1;
900 }
Wichert Akkerman5daa0281999-03-15 19:49:42 +0000901 started = 1;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000902 memcpy(laddr, &u.x[n], m = MIN(sizeof(long)-n,len));
903 while (n & (sizeof(long) - 1))
904 if (u.x[n++] == '\0')
905 return 0;
906 addr += sizeof(long), laddr += m, len -= m;
907 }
908 while (len) {
Roland McGratheb9e2e82009-06-02 16:49:22 -0700909 errno = 0;
910 u.val = ptrace(PTRACE_PEEKDATA, pid, (char *)addr, 0);
911 if (errno) {
912 if (started && (errno==EPERM || errno==EIO)) {
913 /* Ran into 'end of memory' - stupid "printpath" */
914 return 0;
915 }
916 if (addr != 0 && errno != EIO && errno != ESRCH)
917 perror("umovestr");
918 return -1;
919 }
Wichert Akkerman5daa0281999-03-15 19:49:42 +0000920 started = 1;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000921 memcpy(laddr, u.x, m = MIN(sizeof(long), len));
922 for (i = 0; i < sizeof(long); i++)
923 if (u.x[i] == '\0')
924 return 0;
925
926 addr += sizeof(long), laddr += m, len -= m;
927 }
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000928#endif /* !USE_PROCFS */
John Hughesaa09c6b2001-05-15 14:53:43 +0000929 return 0;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000930}
931
932#ifdef LINUX
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +0000933# if !defined (SPARC) && !defined(SPARC64)
934# define PTRACE_WRITETEXT 101
935# define PTRACE_WRITEDATA 102
936# endif /* !SPARC && !SPARC64 */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000937#endif /* LINUX */
938
939#ifdef SUNOS4
940
941static int
Roland McGratheb9e2e82009-06-02 16:49:22 -0700942uload(cmd, pid, addr, len, laddr)
943int cmd;
944int pid;
945long addr;
946int len;
947char *laddr;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000948{
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000949 int peek, poke;
950 int n, m;
951 union {
952 long val;
953 char x[sizeof(long)];
954 } u;
955
956 if (cmd == PTRACE_WRITETEXT) {
957 peek = PTRACE_PEEKTEXT;
958 poke = PTRACE_POKETEXT;
959 }
960 else {
961 peek = PTRACE_PEEKDATA;
962 poke = PTRACE_POKEDATA;
963 }
964 if (addr & (sizeof(long) - 1)) {
965 /* addr not a multiple of sizeof(long) */
966 n = addr - (addr & -sizeof(long)); /* residue */
967 addr &= -sizeof(long);
Roland McGratheb9e2e82009-06-02 16:49:22 -0700968 errno = 0;
969 u.val = ptrace(peek, pid, (char *) addr, 0);
970 if (errno) {
971 perror("uload: POKE");
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000972 return -1;
973 }
Roland McGratheb9e2e82009-06-02 16:49:22 -0700974 memcpy(&u.x[n], laddr, m = MIN(sizeof(long) - n, len));
975 if (ptrace(poke, pid, (char *)addr, u.val) < 0) {
976 perror("uload: POKE");
977 return -1;
978 }
979 addr += sizeof(long), laddr += m, len -= m;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000980 }
981 while (len) {
982 if (len < sizeof(long))
Roland McGratheb9e2e82009-06-02 16:49:22 -0700983 u.val = ptrace(peek, pid, (char *) addr, 0);
984 memcpy(u.x, laddr, m = MIN(sizeof(long), len));
985 if (ptrace(poke, pid, (char *) addr, u.val) < 0) {
986 perror("uload: POKE");
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000987 return -1;
988 }
Roland McGratheb9e2e82009-06-02 16:49:22 -0700989 addr += sizeof(long), laddr += m, len -= m;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000990 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000991 return 0;
992}
993
Roland McGratheb9e2e82009-06-02 16:49:22 -0700994int
995tload(pid, addr, len, laddr)
996int pid;
997int addr, len;
998char *laddr;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000999{
Roland McGratheb9e2e82009-06-02 16:49:22 -07001000 return uload(PTRACE_WRITETEXT, pid, addr, len, laddr);
1001}
1002
1003int
1004dload(pid, addr, len, laddr)
1005int pid;
1006int addr;
1007int len;
1008char *laddr;
1009{
1010 return uload(PTRACE_WRITEDATA, pid, addr, len, laddr);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001011}
1012
1013#endif /* SUNOS4 */
1014
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001015#ifndef USE_PROCFS
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001016
1017int
Roland McGratheb9e2e82009-06-02 16:49:22 -07001018upeek(tcp, off, res)
1019struct tcb *tcp;
1020long off;
1021long *res;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001022{
1023 long val;
1024
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001025# ifdef SUNOS4_KERNEL_ARCH_KLUDGE
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001026 {
1027 static int is_sun4m = -1;
1028 struct utsname name;
1029
1030 /* Round up the usual suspects. */
1031 if (is_sun4m == -1) {
1032 if (uname(&name) < 0) {
1033 perror("upeek: uname?");
1034 exit(1);
1035 }
1036 is_sun4m = strcmp(name.machine, "sun4m") == 0;
1037 if (is_sun4m) {
Roland McGrathd9f816f2004-09-04 03:39:20 +00001038 const struct xlat *x;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001039
1040 for (x = struct_user_offsets; x->str; x++)
1041 x->val += 1024;
1042 }
1043 }
1044 if (is_sun4m)
1045 off += 1024;
1046 }
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001047# endif /* SUNOS4_KERNEL_ARCH_KLUDGE */
Roland McGratheb9e2e82009-06-02 16:49:22 -07001048 errno = 0;
Denys Vlasenko732d1bf2008-12-17 19:21:59 +00001049 val = do_ptrace(PTRACE_PEEKUSER, tcp, (char *) off, 0);
Roland McGratheb9e2e82009-06-02 16:49:22 -07001050 if (val == -1 && errno) {
1051 if (errno != ESRCH) {
1052 char buf[60];
1053 sprintf(buf,"upeek: ptrace(PTRACE_PEEKUSER,%d,%lu,0)", tcp->pid, off);
1054 perror(buf);
1055 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001056 return -1;
Roland McGratheb9e2e82009-06-02 16:49:22 -07001057 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001058 *res = val;
1059 return 0;
1060}
1061
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001062#endif /* !USE_PROCFS */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001063
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001064void
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001065printcall(struct tcb *tcp)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001066{
Roland McGrath7a918832005-02-02 20:55:23 +00001067#define PRINTBADPC tprintf(sizeof(long) == 4 ? "[????????] " : \
1068 sizeof(long) == 8 ? "[????????????????] " : \
1069 NULL /* crash */)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001070
1071#ifdef LINUX
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001072# ifdef I386
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001073 long eip;
1074
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001075 if (upeek(tcp, 4*EIP, &eip) < 0) {
Roland McGrath7a918832005-02-02 20:55:23 +00001076 PRINTBADPC;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001077 return;
1078 }
1079 tprintf("[%08lx] ", eip);
Roland McGratheac26fc2005-02-02 02:48:53 +00001080
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001081# elif defined(S390) || defined(S390X)
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001082 long psw;
Roland McGratheb9e2e82009-06-02 16:49:22 -07001083 if(upeek(tcp,PT_PSWADDR,&psw) < 0) {
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001084 PRINTBADPC;
1085 return;
1086 }
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001087# ifdef S390
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001088 tprintf("[%08lx] ", psw);
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001089# elif S390X
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001090 tprintf("[%16lx] ", psw);
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001091# endif
Roland McGratheac26fc2005-02-02 02:48:53 +00001092
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001093# elif defined(X86_64)
Michal Ludvig0e035502002-09-23 15:41:01 +00001094 long rip;
1095
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001096 if (upeek(tcp, 8*RIP, &rip) < 0) {
Roland McGrath7a918832005-02-02 20:55:23 +00001097 PRINTBADPC;
Michal Ludvig0e035502002-09-23 15:41:01 +00001098 return;
1099 }
1100 tprintf("[%16lx] ", rip);
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001101# elif defined(IA64)
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00001102 long ip;
1103
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001104 if (upeek(tcp, PT_B0, &ip) < 0) {
Roland McGrath7a918832005-02-02 20:55:23 +00001105 PRINTBADPC;
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00001106 return;
1107 }
1108 tprintf("[%08lx] ", ip);
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001109# elif defined(POWERPC)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001110 long pc;
1111
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001112 if (upeek(tcp, sizeof(unsigned long)*PT_NIP, &pc) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001113 tprintf ("[????????] ");
1114 return;
1115 }
1116 tprintf("[%08lx] ", pc);
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001117# elif defined(M68K)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001118 long pc;
1119
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001120 if (upeek(tcp, 4*PT_PC, &pc) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001121 tprintf ("[????????] ");
1122 return;
1123 }
1124 tprintf("[%08lx] ", pc);
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001125# elif defined(ALPHA)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001126 long pc;
1127
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001128 if (upeek(tcp, REG_PC, &pc) < 0) {
Roland McGrath7a918832005-02-02 20:55:23 +00001129 tprintf ("[????????????????] ");
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001130 return;
1131 }
1132 tprintf("[%08lx] ", pc);
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001133# elif defined(SPARC) || defined(SPARC64)
Mike Frysinger8566c502009-10-12 11:05:14 -04001134 struct pt_regs regs;
Roland McGratheb9e2e82009-06-02 16:49:22 -07001135 if (ptrace(PTRACE_GETREGS,tcp->pid,(char *)&regs,0) < 0) {
Roland McGrath7a918832005-02-02 20:55:23 +00001136 PRINTBADPC;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001137 return;
1138 }
Mike Frysinger8566c502009-10-12 11:05:14 -04001139# if defined(SPARC64)
1140 tprintf("[%08lx] ", regs.tpc);
1141# else
1142 tprintf("[%08lx] ", regs.pc);
1143# endif
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001144# elif defined(HPPA)
Wichert Akkermanc1652e22001-03-27 12:17:16 +00001145 long pc;
1146
Roland McGratheb9e2e82009-06-02 16:49:22 -07001147 if(upeek(tcp,PT_IAOQ0,&pc) < 0) {
Wichert Akkermanc1652e22001-03-27 12:17:16 +00001148 tprintf ("[????????] ");
1149 return;
1150 }
1151 tprintf("[%08lx] ", pc);
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001152# elif defined(MIPS)
Wichert Akkerman75c422b2001-04-10 10:22:50 +00001153 long pc;
1154
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001155 if (upeek(tcp, REG_EPC, &pc) < 0) {
Wichert Akkerman75c422b2001-04-10 10:22:50 +00001156 tprintf ("[????????] ");
1157 return;
1158 }
1159 tprintf("[%08lx] ", pc);
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001160# elif defined(SH)
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001161 long pc;
Wichert Akkermanccef6372002-05-01 16:39:22 +00001162
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001163 if (upeek(tcp, 4*REG_PC, &pc) < 0) {
1164 tprintf ("[????????] ");
1165 return;
1166 }
1167 tprintf("[%08lx] ", pc);
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001168# elif defined(SH64)
Roland McGrathe1e584b2003-06-02 19:18:58 +00001169 long pc;
1170
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001171 if (upeek(tcp, REG_PC, &pc) < 0) {
Roland McGrath7a918832005-02-02 20:55:23 +00001172 tprintf ("[????????????????] ");
Roland McGrathe1e584b2003-06-02 19:18:58 +00001173 return;
1174 }
1175 tprintf("[%08lx] ", pc);
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001176# elif defined(ARM)
Roland McGrathef388682003-06-03 23:28:59 +00001177 long pc;
Roland McGrathe1e584b2003-06-02 19:18:58 +00001178
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001179 if (upeek(tcp, 4*15, &pc) < 0) {
Roland McGrath7a918832005-02-02 20:55:23 +00001180 PRINTBADPC;
Roland McGrathef388682003-06-03 23:28:59 +00001181 return;
1182 }
1183 tprintf("[%08lx] ", pc);
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00001184# elif defined(AVR32)
1185 long pc;
1186
1187 if (upeek(tcp, REG_PC, &pc) < 0) {
1188 tprintf("[????????] ");
1189 return;
1190 }
1191 tprintf("[%08lx] ", pc);
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001192# elif defined(BFIN)
Dmitry V. Levin87ea1f42008-11-10 22:21:41 +00001193 long pc;
1194
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001195 if (upeek(tcp, PT_PC, &pc) < 0) {
Dmitry V. Levin87ea1f42008-11-10 22:21:41 +00001196 PRINTBADPC;
1197 return;
1198 }
1199 tprintf("[%08lx] ", pc);
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001200#elif defined(CRISV10)
1201 long pc;
1202
Edgar E. Iglesiaseeb9ce32009-10-05 14:41:02 +00001203 if (upeek(tcp, 4*PT_IRP, &pc) < 0) {
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001204 PRINTBADPC;
1205 return;
1206 }
1207 tprintf("[%08lx] ", pc);
1208#elif defined(CRISV32)
1209 long pc;
1210
Edgar E. Iglesiaseeb9ce32009-10-05 14:41:02 +00001211 if (upeek(tcp, 4*PT_ERP, &pc) < 0) {
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001212 PRINTBADPC;
1213 return;
1214 }
1215 tprintf("[%08lx] ", pc);
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001216# endif /* architecture */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001217#endif /* LINUX */
1218
1219#ifdef SUNOS4
1220 struct regs regs;
1221
Roland McGratheb9e2e82009-06-02 16:49:22 -07001222 if (ptrace(PTRACE_GETREGS, tcp->pid, (char *) &regs, 0) < 0) {
1223 perror("printcall: ptrace(PTRACE_GETREGS, ...)");
Roland McGrath7a918832005-02-02 20:55:23 +00001224 PRINTBADPC;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001225 return;
1226 }
1227 tprintf("[%08x] ", regs.r_o7);
1228#endif /* SUNOS4 */
1229
1230#ifdef SVR4
1231 /* XXX */
Roland McGrath7a918832005-02-02 20:55:23 +00001232 PRINTBADPC;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001233#endif
1234
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001235#ifdef FREEBSD
1236 struct reg regs;
1237 pread(tcp->pfd_reg, &regs, sizeof(regs), 0);
1238 tprintf("[%08x] ", regs.r_eip);
1239#endif /* FREEBSD */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001240}
1241
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001242
1243/*
1244 * These #if's are huge, please indent them correctly.
1245 * It's easy to get confused otherwise.
1246 */
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001247#ifndef USE_PROCFS
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001248
Dmitry V. Levine5e60852009-12-31 22:50:49 +00001249#ifdef LINUX
Roland McGrathd81f1d92003-01-09 06:53:34 +00001250
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001251# include "syscall.h"
Roland McGrath3291ef22008-05-20 00:34:34 +00001252
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001253# include <sys/syscall.h>
1254# ifndef CLONE_PTRACE
1255# define CLONE_PTRACE 0x00002000
1256# endif
1257# ifndef CLONE_VFORK
1258# define CLONE_VFORK 0x00004000
1259# endif
1260# ifndef CLONE_VM
1261# define CLONE_VM 0x00000100
1262# endif
1263# ifndef CLONE_STOPPED
1264# define CLONE_STOPPED 0x02000000
1265# endif
Roland McGrathd81f1d92003-01-09 06:53:34 +00001266
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001267# ifdef IA64
Roland McGrathd81f1d92003-01-09 06:53:34 +00001268
Roland McGrath08267b82004-02-20 22:56:43 +00001269/* We don't have fork()/vfork() syscalls on ia64 itself, but the ia32
1270 subsystem has them for x86... */
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001271# define SYS_fork 2
1272# define SYS_vfork 190
Roland McGrath08267b82004-02-20 22:56:43 +00001273
Roland McGrathd81f1d92003-01-09 06:53:34 +00001274typedef unsigned long *arg_setup_state;
1275
1276static int
1277arg_setup(struct tcb *tcp, arg_setup_state *state)
1278{
Jan Kratochvil1f942712008-08-06 21:38:52 +00001279 unsigned long cfm, sof, sol;
1280 long bsp;
Roland McGrathd81f1d92003-01-09 06:53:34 +00001281
Jan Kratochvil1f942712008-08-06 21:38:52 +00001282 if (ia32) {
1283 /* Satisfy a false GCC warning. */
1284 *state = NULL;
Roland McGrath08267b82004-02-20 22:56:43 +00001285 return 0;
Jan Kratochvil1f942712008-08-06 21:38:52 +00001286 }
Roland McGrath08267b82004-02-20 22:56:43 +00001287
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001288 if (upeek(tcp, PT_AR_BSP, &bsp) < 0)
Roland McGrathd81f1d92003-01-09 06:53:34 +00001289 return -1;
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001290 if (upeek(tcp, PT_CFM, (long *) &cfm) < 0)
Roland McGrathd81f1d92003-01-09 06:53:34 +00001291 return -1;
1292
1293 sof = (cfm >> 0) & 0x7f;
1294 sol = (cfm >> 7) & 0x7f;
Jan Kratochvil1f942712008-08-06 21:38:52 +00001295 bsp = (long) ia64_rse_skip_regs((unsigned long *) bsp, -sof + sol);
Roland McGrathd81f1d92003-01-09 06:53:34 +00001296
Jan Kratochvil1f942712008-08-06 21:38:52 +00001297 *state = (unsigned long *) bsp;
Roland McGrathd81f1d92003-01-09 06:53:34 +00001298 return 0;
1299}
1300
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001301# define arg_finish_change(tcp, state) 0
Roland McGrathd81f1d92003-01-09 06:53:34 +00001302
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001303# ifdef SYS_fork
Roland McGrathd81f1d92003-01-09 06:53:34 +00001304static int
1305get_arg0 (struct tcb *tcp, arg_setup_state *state, long *valp)
1306{
Roland McGrath08267b82004-02-20 22:56:43 +00001307 int ret;
1308
1309 if (ia32)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001310 ret = upeek (tcp, PT_R11, valp);
Roland McGrath08267b82004-02-20 22:56:43 +00001311 else
1312 ret = umoven (tcp,
1313 (unsigned long) ia64_rse_skip_regs(*state, 0),
1314 sizeof(long), (void *) valp);
1315 return ret;
Roland McGrathd81f1d92003-01-09 06:53:34 +00001316}
1317
1318static int
1319get_arg1 (struct tcb *tcp, arg_setup_state *state, long *valp)
1320{
Roland McGrath08267b82004-02-20 22:56:43 +00001321 int ret;
1322
1323 if (ia32)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001324 ret = upeek (tcp, PT_R9, valp);
Roland McGrath08267b82004-02-20 22:56:43 +00001325 else
1326 ret = umoven (tcp,
1327 (unsigned long) ia64_rse_skip_regs(*state, 1),
1328 sizeof(long), (void *) valp);
1329 return ret;
Roland McGrathd81f1d92003-01-09 06:53:34 +00001330}
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001331# endif
Roland McGrathd81f1d92003-01-09 06:53:34 +00001332
1333static int
1334set_arg0 (struct tcb *tcp, arg_setup_state *state, long val)
1335{
Roland McGrath08267b82004-02-20 22:56:43 +00001336 int req = PTRACE_POKEDATA;
1337 void *ap;
1338
1339 if (ia32) {
1340 ap = (void *) (intptr_t) PT_R11; /* r11 == EBX */
1341 req = PTRACE_POKEUSER;
1342 } else
1343 ap = ia64_rse_skip_regs(*state, 0);
Roland McGratheb9e2e82009-06-02 16:49:22 -07001344 errno = 0;
1345 ptrace(req, tcp->pid, ap, val);
1346 return errno ? -1 : 0;
Roland McGrathd81f1d92003-01-09 06:53:34 +00001347}
1348
1349static int
1350set_arg1 (struct tcb *tcp, arg_setup_state *state, long val)
1351{
Roland McGrath08267b82004-02-20 22:56:43 +00001352 int req = PTRACE_POKEDATA;
1353 void *ap;
1354
1355 if (ia32) {
1356 ap = (void *) (intptr_t) PT_R9; /* r9 == ECX */
1357 req = PTRACE_POKEUSER;
1358 } else
1359 ap = ia64_rse_skip_regs(*state, 1);
Roland McGratheb9e2e82009-06-02 16:49:22 -07001360 errno = 0;
1361 ptrace(req, tcp->pid, ap, val);
1362 return errno ? -1 : 0;
Roland McGrathd81f1d92003-01-09 06:53:34 +00001363}
1364
Roland McGrathb659f872008-07-18 01:19:36 +00001365/* ia64 does not return the input arguments from functions (and syscalls)
1366 according to ia64 RSE (Register Stack Engine) behavior. */
1367
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001368# define restore_arg0(tcp, state, val) ((void) (state), 0)
1369# define restore_arg1(tcp, state, val) ((void) (state), 0)
Roland McGrathb659f872008-07-18 01:19:36 +00001370
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001371# elif defined (SPARC) || defined (SPARC64)
Roland McGrathd81f1d92003-01-09 06:53:34 +00001372
Mike Frysinger8566c502009-10-12 11:05:14 -04001373typedef struct pt_regs arg_setup_state;
Roland McGrathd81f1d92003-01-09 06:53:34 +00001374
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001375# define arg_setup(tcp, state) \
Roland McGratheb9e2e82009-06-02 16:49:22 -07001376 (ptrace (PTRACE_GETREGS, tcp->pid, (char *) (state), 0))
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001377# define arg_finish_change(tcp, state) \
Roland McGratheb9e2e82009-06-02 16:49:22 -07001378 (ptrace (PTRACE_SETREGS, tcp->pid, (char *) (state), 0))
Roland McGrathd81f1d92003-01-09 06:53:34 +00001379
Mike Frysinger8566c502009-10-12 11:05:14 -04001380# define get_arg0(tcp, state, valp) (*(valp) = (state)->u_regs[U_REG_O0], 0)
1381# define get_arg1(tcp, state, valp) (*(valp) = (state)->u_regs[U_REG_O1], 0)
1382# define set_arg0(tcp, state, val) ((state)->u_regs[U_REG_O0] = (val), 0)
1383# define set_arg1(tcp, state, val) ((state)->u_regs[U_REG_O1] = (val), 0)
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001384# define restore_arg0(tcp, state, val) 0
Roland McGrathd81f1d92003-01-09 06:53:34 +00001385
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001386# else /* other architectures */
Roland McGrathd81f1d92003-01-09 06:53:34 +00001387
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001388# if defined S390 || defined S390X
Roland McGrath7b308222003-01-20 09:04:36 +00001389/* Note: this is only true for the `clone' system call, which handles
1390 arguments specially. We could as well say that its first two arguments
1391 are swapped relative to other architectures, but that would just be
1392 another #ifdef in the calls. */
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001393# define arg0_offset PT_GPR3
1394# define arg1_offset PT_ORIGGPR2
1395# define restore_arg0(tcp, state, val) ((void) (state), 0)
1396# define restore_arg1(tcp, state, val) ((void) (state), 0)
1397# define arg0_index 1
1398# define arg1_index 0
1399# elif defined (ALPHA) || defined (MIPS)
1400# define arg0_offset REG_A0
1401# define arg1_offset (REG_A0+1)
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00001402# elif defined (AVR32)
1403# define arg0_offset (REG_R12)
1404# define arg1_offset (REG_R11)
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001405# elif defined (POWERPC)
1406# define arg0_offset (sizeof(unsigned long)*PT_R3)
1407# define arg1_offset (sizeof(unsigned long)*PT_R4)
1408# define restore_arg0(tcp, state, val) ((void) (state), 0)
1409# elif defined (HPPA)
1410# define arg0_offset PT_GR26
1411# define arg1_offset (PT_GR26-4)
1412# elif defined (X86_64)
1413# define arg0_offset ((long)(8*(current_personality ? RBX : RDI)))
1414# define arg1_offset ((long)(8*(current_personality ? RCX : RSI)))
1415# elif defined (SH)
1416# define arg0_offset (4*(REG_REG0+4))
1417# define arg1_offset (4*(REG_REG0+5))
1418# elif defined (SH64)
1419 /* ABI defines arg0 & 1 in r2 & r3 */
1420# define arg0_offset (REG_OFFSET+16)
1421# define arg1_offset (REG_OFFSET+24)
1422# define restore_arg0(tcp, state, val) 0
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001423# elif defined CRISV10 || defined CRISV32
1424# define arg0_offset (4*PT_R11)
1425# define arg1_offset (4*PT_ORIG_R10)
1426# define restore_arg0(tcp, state, val) 0
1427# define restore_arg1(tcp, state, val) 0
1428# define arg0_index 1
1429# define arg1_index 0
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001430# else
1431# define arg0_offset 0
1432# define arg1_offset 4
1433# if defined ARM
1434# define restore_arg0(tcp, state, val) 0
1435# endif
1436# endif
Roland McGrathd81f1d92003-01-09 06:53:34 +00001437
1438typedef int arg_setup_state;
1439
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001440# define arg_setup(tcp, state) (0)
1441# define arg_finish_change(tcp, state) 0
1442# define get_arg0(tcp, cookie, valp) \
1443 (upeek ((tcp), arg0_offset, (valp)))
1444# define get_arg1(tcp, cookie, valp) \
1445 (upeek ((tcp), arg1_offset, (valp)))
Roland McGrathd81f1d92003-01-09 06:53:34 +00001446
1447static int
Roland McGratheb9e2e82009-06-02 16:49:22 -07001448set_arg0 (struct tcb *tcp, void *cookie, long val)
Roland McGrathd81f1d92003-01-09 06:53:34 +00001449{
Roland McGratheb9e2e82009-06-02 16:49:22 -07001450 return ptrace (PTRACE_POKEUSER, tcp->pid, (char*)arg0_offset, val);
Roland McGrathd81f1d92003-01-09 06:53:34 +00001451}
1452
1453static int
Roland McGratheb9e2e82009-06-02 16:49:22 -07001454set_arg1 (struct tcb *tcp, void *cookie, long val)
Roland McGrathd81f1d92003-01-09 06:53:34 +00001455{
Roland McGratheb9e2e82009-06-02 16:49:22 -07001456 return ptrace (PTRACE_POKEUSER, tcp->pid, (char*)arg1_offset, val);
Roland McGrathd81f1d92003-01-09 06:53:34 +00001457}
1458
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001459# endif /* architectures */
Roland McGrathd81f1d92003-01-09 06:53:34 +00001460
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001461# ifndef restore_arg0
1462# define restore_arg0(tcp, state, val) set_arg0((tcp), (state), (val))
1463# endif
1464# ifndef restore_arg1
1465# define restore_arg1(tcp, state, val) set_arg1((tcp), (state), (val))
1466# endif
Roland McGrathd81f1d92003-01-09 06:53:34 +00001467
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001468# ifndef arg0_index
1469# define arg0_index 0
1470# define arg1_index 1
1471# endif
Roland McGrath90d0afd2004-03-01 21:05:16 +00001472
Roland McGrathd81f1d92003-01-09 06:53:34 +00001473int
Denys Vlasenko418d66a2009-01-17 01:52:54 +00001474setbpt(struct tcb *tcp)
Roland McGrathd81f1d92003-01-09 06:53:34 +00001475{
Roland McGrath3291ef22008-05-20 00:34:34 +00001476 static int clone_scno[SUPPORTED_PERSONALITIES] = { SYS_clone };
Roland McGrathd81f1d92003-01-09 06:53:34 +00001477 arg_setup_state state;
1478
1479 if (tcp->flags & TCB_BPTSET) {
1480 fprintf(stderr, "PANIC: TCB already set in pid %u\n", tcp->pid);
1481 return -1;
1482 }
1483
Roland McGrath3291ef22008-05-20 00:34:34 +00001484 /*
1485 * It's a silly kludge to initialize this with a search at runtime.
1486 * But it's better than maintaining another magic thing in the
1487 * godforsaken tables.
1488 */
1489 if (clone_scno[current_personality] == 0) {
1490 int i;
1491 for (i = 0; i < nsyscalls; ++i)
1492 if (sysent[i].sys_func == sys_clone) {
1493 clone_scno[current_personality] = i;
1494 break;
1495 }
1496 }
1497
Roland McGrath76989d72005-06-07 23:21:31 +00001498 switch (known_scno(tcp)) {
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001499# ifdef SYS_vfork
Roland McGrath9383c6c2003-01-18 00:19:31 +00001500 case SYS_vfork:
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001501# endif
1502# ifdef SYS_fork
Roland McGrathd81f1d92003-01-09 06:53:34 +00001503 case SYS_fork:
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001504# endif
1505# if defined SYS_fork || defined SYS_vfork
Roland McGrathd81f1d92003-01-09 06:53:34 +00001506 if (arg_setup (tcp, &state) < 0
1507 || get_arg0 (tcp, &state, &tcp->inst[0]) < 0
1508 || get_arg1 (tcp, &state, &tcp->inst[1]) < 0
Roland McGrath3291ef22008-05-20 00:34:34 +00001509 || change_syscall(tcp, clone_scno[current_personality]) < 0
Roland McGrathd81f1d92003-01-09 06:53:34 +00001510 || set_arg0 (tcp, &state, CLONE_PTRACE|SIGCHLD) < 0
1511 || set_arg1 (tcp, &state, 0) < 0
1512 || arg_finish_change (tcp, &state) < 0)
1513 return -1;
Roland McGrathc9dc3c12004-03-01 20:57:09 +00001514 tcp->u_arg[arg0_index] = CLONE_PTRACE|SIGCHLD;
1515 tcp->u_arg[arg1_index] = 0;
Roland McGrathd81f1d92003-01-09 06:53:34 +00001516 tcp->flags |= TCB_BPTSET;
1517 return 0;
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001518# endif
Roland McGrathd81f1d92003-01-09 06:53:34 +00001519
1520 case SYS_clone:
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001521# ifdef SYS_clone2
Roland McGrathd81f1d92003-01-09 06:53:34 +00001522 case SYS_clone2:
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001523# endif
Jan Kratochvil8fc95752008-08-06 21:43:35 +00001524 /* ia64 calls directly `clone (CLONE_VFORK | CLONE_VM)'
1525 contrary to x86 SYS_vfork above. Even on x86 we turn the
1526 vfork semantics into plain fork - each application must not
1527 depend on the vfork specifics according to POSIX. We would
1528 hang waiting for the parent resume otherwise. We need to
1529 clear also CLONE_VM but only in the CLONE_VFORK case as
1530 otherwise we would break pthread_create. */
1531
Roland McGrathd6ff0d52008-07-18 01:09:44 +00001532 if ((arg_setup (tcp, &state) < 0
1533 || set_arg0 (tcp, &state,
1534 (tcp->u_arg[arg0_index] | CLONE_PTRACE)
Jan Kratochvil8fc95752008-08-06 21:43:35 +00001535 & ~(tcp->u_arg[arg0_index] & CLONE_VFORK
1536 ? CLONE_VFORK | CLONE_VM : 0)) < 0
Roland McGrathd6ff0d52008-07-18 01:09:44 +00001537 || arg_finish_change (tcp, &state) < 0))
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00001538 return -1;
Roland McGrathd81f1d92003-01-09 06:53:34 +00001539 tcp->flags |= TCB_BPTSET;
Roland McGrathc9dc3c12004-03-01 20:57:09 +00001540 tcp->inst[0] = tcp->u_arg[arg0_index];
1541 tcp->inst[1] = tcp->u_arg[arg1_index];
Roland McGrathd81f1d92003-01-09 06:53:34 +00001542 return 0;
1543
1544 default:
1545 fprintf(stderr, "PANIC: setbpt for syscall %ld on %u???\n",
1546 tcp->scno, tcp->pid);
1547 break;
1548 }
1549
1550 return -1;
1551}
1552
1553int
1554clearbpt(tcp)
1555struct tcb *tcp;
1556{
1557 arg_setup_state state;
1558 if (arg_setup (tcp, &state) < 0
Roland McGrathe1df47f2003-01-14 09:46:15 +00001559 || restore_arg0 (tcp, &state, tcp->inst[0]) < 0
1560 || restore_arg1 (tcp, &state, tcp->inst[1]) < 0
Roland McGrathd81f1d92003-01-09 06:53:34 +00001561 || arg_finish_change (tcp, &state))
Andreas Schwab46ed50d2009-11-11 13:54:04 +01001562 if (errno != ESRCH) return -1;
Roland McGrathd81f1d92003-01-09 06:53:34 +00001563 tcp->flags &= ~TCB_BPTSET;
1564 return 0;
1565}
1566
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001567# else /* !defined LINUX */
Roland McGrathd81f1d92003-01-09 06:53:34 +00001568
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001569int
1570setbpt(tcp)
1571struct tcb *tcp;
1572{
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001573# ifdef SUNOS4
1574# ifdef SPARC /* This code is slightly sparc specific */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001575
Wichert Akkermane6f876c1999-06-22 15:28:30 +00001576 struct regs regs;
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001577# define BPT 0x91d02001 /* ta 1 */
1578# define LOOP 0x10800000 /* ba 0 */
1579# define LOOPA 0x30800000 /* ba,a 0 */
1580# define NOP 0x01000000
1581# if LOOPA
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001582 static int loopdeloop[1] = {LOOPA};
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001583# else
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001584 static int loopdeloop[2] = {LOOP, NOP};
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001585# endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001586
1587 if (tcp->flags & TCB_BPTSET) {
1588 fprintf(stderr, "PANIC: TCB already set in pid %u\n", tcp->pid);
1589 return -1;
1590 }
Roland McGratheb9e2e82009-06-02 16:49:22 -07001591 if (ptrace(PTRACE_GETREGS, tcp->pid, (char *)&regs, 0) < 0) {
1592 perror("setbpt: ptrace(PTRACE_GETREGS, ...)");
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001593 return -1;
1594 }
1595 tcp->baddr = regs.r_o7 + 8;
Roland McGratheb9e2e82009-06-02 16:49:22 -07001596 if (ptrace(PTRACE_READTEXT, tcp->pid, (char *)tcp->baddr,
1597 sizeof tcp->inst, (char *)tcp->inst) < 0) {
1598 perror("setbpt: ptrace(PTRACE_READTEXT, ...)");
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001599 return -1;
1600 }
1601
1602 /*
1603 * XXX - BRUTAL MODE ON
1604 * We cannot set a real BPT in the child, since it will not be
1605 * traced at the moment it will reach the trap and would probably
1606 * die with a core dump.
1607 * Thus, we are force our way in by taking out two instructions
1608 * and insert an eternal loop in stead, in expectance of the SIGSTOP
1609 * generated by out PTRACE_ATTACH.
1610 * Of cause, if we evaporate ourselves in the middle of all this...
1611 */
Roland McGratheb9e2e82009-06-02 16:49:22 -07001612 if (ptrace(PTRACE_WRITETEXT, tcp->pid, (char *) tcp->baddr,
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001613 sizeof loopdeloop, (char *) loopdeloop) < 0) {
Roland McGratheb9e2e82009-06-02 16:49:22 -07001614 perror("setbpt: ptrace(PTRACE_WRITETEXT, ...)");
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001615 return -1;
1616 }
1617 tcp->flags |= TCB_BPTSET;
1618
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001619# endif /* SPARC */
1620# endif /* SUNOS4 */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001621
1622 return 0;
1623}
1624
1625int
1626clearbpt(tcp)
1627struct tcb *tcp;
1628{
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001629# ifdef SUNOS4
1630# ifdef SPARC
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001631
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001632# if !LOOPA
Wichert Akkermane6f876c1999-06-22 15:28:30 +00001633 struct regs regs;
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001634# endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001635
1636 if (!(tcp->flags & TCB_BPTSET)) {
1637 fprintf(stderr, "PANIC: TCB not set in pid %u\n", tcp->pid);
1638 return -1;
1639 }
Roland McGratheb9e2e82009-06-02 16:49:22 -07001640 if (ptrace(PTRACE_WRITETEXT, tcp->pid, (char *) tcp->baddr,
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001641 sizeof tcp->inst, (char *) tcp->inst) < 0) {
Roland McGratheb9e2e82009-06-02 16:49:22 -07001642 perror("clearbtp: ptrace(PTRACE_WRITETEXT, ...)");
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001643 return -1;
1644 }
1645 tcp->flags &= ~TCB_BPTSET;
1646
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001647# if !LOOPA
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001648 /*
1649 * Since we don't have a single instruction breakpoint, we may have
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001650 * to adjust the program counter after removing our `breakpoint'.
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001651 */
Roland McGratheb9e2e82009-06-02 16:49:22 -07001652 if (ptrace(PTRACE_GETREGS, tcp->pid, (char *)&regs, 0) < 0) {
1653 perror("clearbpt: ptrace(PTRACE_GETREGS, ...)");
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001654 return -1;
1655 }
Roland McGratheb9e2e82009-06-02 16:49:22 -07001656 if ((regs.r_pc < tcp->baddr) ||
1657 (regs.r_pc > tcp->baddr + 4)) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001658 /* The breakpoint has not been reached yet */
1659 if (debug)
1660 fprintf(stderr,
1661 "NOTE: PC not at bpt (pc %#x baddr %#x)\n",
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001662 regs.r_pc, tcp->baddr);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001663 return 0;
1664 }
1665 if (regs.r_pc != tcp->baddr)
1666 if (debug)
1667 fprintf(stderr, "NOTE: PC adjusted (%#x -> %#x\n",
1668 regs.r_pc, tcp->baddr);
1669
1670 regs.r_pc = tcp->baddr;
Roland McGratheb9e2e82009-06-02 16:49:22 -07001671 if (ptrace(PTRACE_SETREGS, tcp->pid, (char *)&regs, 0) < 0) {
1672 perror("clearbpt: ptrace(PTRACE_SETREGS, ...)");
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001673 return -1;
1674 }
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001675# endif /* LOOPA */
1676# endif /* SPARC */
1677# endif /* SUNOS4 */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001678
1679 return 0;
1680}
1681
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001682# endif /* !defined LINUX */
Roland McGrathd81f1d92003-01-09 06:53:34 +00001683
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001684#endif /* !USE_PROCFS */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001685
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001686
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001687#ifdef SUNOS4
1688
1689static int
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001690getex(tcp, hdr)
1691struct tcb *tcp;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001692struct exec *hdr;
1693{
1694 int n;
1695
1696 for (n = 0; n < sizeof *hdr; n += 4) {
1697 long res;
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001698 if (upeek(tcp, uoff(u_exdata) + n, &res) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001699 return -1;
1700 memcpy(((char *) hdr) + n, &res, 4);
1701 }
1702 if (debug) {
1703 fprintf(stderr, "[struct exec: magic: %o version %u Mach %o\n",
1704 hdr->a_magic, hdr->a_toolversion, hdr->a_machtype);
1705 fprintf(stderr, "Text %lu Data %lu Bss %lu Syms %lu Entry %#lx]\n",
1706 hdr->a_text, hdr->a_data, hdr->a_bss, hdr->a_syms, hdr->a_entry);
1707 }
1708 return 0;
1709}
1710
1711int
1712fixvfork(tcp)
1713struct tcb *tcp;
1714{
1715 int pid = tcp->pid;
1716 /*
1717 * Change `vfork' in a freshly exec'ed dynamically linked
1718 * executable's (internal) symbol table to plain old `fork'
1719 */
1720
1721 struct exec hdr;
1722 struct link_dynamic dyn;
1723 struct link_dynamic_2 ld;
1724 char *strtab, *cp;
1725
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001726 if (getex(tcp, &hdr) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001727 return -1;
1728 if (!hdr.a_dynamic)
1729 return -1;
1730
1731 if (umove(tcp, (int) N_DATADDR(hdr), &dyn) < 0) {
1732 fprintf(stderr, "Cannot read DYNAMIC\n");
1733 return -1;
1734 }
1735 if (umove(tcp, (int) dyn.ld_un.ld_2, &ld) < 0) {
1736 fprintf(stderr, "Cannot read link_dynamic_2\n");
1737 return -1;
1738 }
1739 if ((strtab = malloc((unsigned)ld.ld_symb_size)) == NULL) {
Roland McGrath46100d02005-06-01 18:55:42 +00001740 fprintf(stderr, "out of memory\n");
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001741 return -1;
1742 }
Roland McGratheb9e2e82009-06-02 16:49:22 -07001743 if (umoven(tcp, (int)ld.ld_symbols+(int)N_TXTADDR(hdr),
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001744 (int)ld.ld_symb_size, strtab) < 0)
1745 goto err;
1746
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001747 for (cp = strtab; cp < strtab + ld.ld_symb_size; ) {
1748 if (strcmp(cp, "_vfork") == 0) {
1749 if (debug)
1750 fprintf(stderr, "fixvfork: FOUND _vfork\n");
1751 strcpy(cp, "_fork");
1752 break;
1753 }
1754 cp += strlen(cp)+1;
1755 }
1756 if (cp < strtab + ld.ld_symb_size)
1757 /*
1758 * Write entire symbol table back to avoid
1759 * memory alignment bugs in ptrace
1760 */
Roland McGratheb9e2e82009-06-02 16:49:22 -07001761 if (tload(pid, (int)ld.ld_symbols+(int)N_TXTADDR(hdr),
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001762 (int)ld.ld_symb_size, strtab) < 0)
1763 goto err;
1764
1765 free(strtab);
1766 return 0;
1767
1768err:
1769 free(strtab);
1770 return -1;
1771}
1772
1773#endif /* SUNOS4 */