blob: d05f777682c5b6450c50ebaed956ef1caa1e9fb8 [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
Denys Vlasenko12014262011-05-30 14:00:14 +020097tv_nz(struct timeval *a)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +000098{
99 return a->tv_sec || a->tv_usec;
100}
101
102int
Denys Vlasenko12014262011-05-30 14:00:14 +0200103tv_cmp(struct timeval *a, struct timeval *b)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000104{
105 if (a->tv_sec < b->tv_sec
106 || (a->tv_sec == b->tv_sec && a->tv_usec < b->tv_usec))
107 return -1;
108 if (a->tv_sec > b->tv_sec
109 || (a->tv_sec == b->tv_sec && a->tv_usec > b->tv_usec))
110 return 1;
111 return 0;
112}
113
114double
Denys Vlasenko12014262011-05-30 14:00:14 +0200115tv_float(struct timeval *tv)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000116{
117 return tv->tv_sec + tv->tv_usec/1000000.0;
118}
119
120void
Denys Vlasenko12014262011-05-30 14:00:14 +0200121tv_add(struct timeval *tv, struct timeval *a, struct timeval *b)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000122{
123 tv->tv_sec = a->tv_sec + b->tv_sec;
124 tv->tv_usec = a->tv_usec + b->tv_usec;
Roland McGrath58372f52007-07-24 01:38:22 +0000125 if (tv->tv_usec >= 1000000) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000126 tv->tv_sec++;
127 tv->tv_usec -= 1000000;
128 }
129}
130
131void
Denys Vlasenko12014262011-05-30 14:00:14 +0200132tv_sub(struct timeval *tv, struct timeval *a, struct timeval *b)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000133{
134 tv->tv_sec = a->tv_sec - b->tv_sec;
135 tv->tv_usec = a->tv_usec - b->tv_usec;
136 if (((long) tv->tv_usec) < 0) {
137 tv->tv_sec--;
138 tv->tv_usec += 1000000;
139 }
140}
141
142void
Denys Vlasenko12014262011-05-30 14:00:14 +0200143tv_div(struct timeval *tv, struct timeval *a, int n)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000144{
145 tv->tv_usec = (a->tv_sec % n * 1000000 + a->tv_usec + n / 2) / n;
146 tv->tv_sec = a->tv_sec / n + tv->tv_usec / 1000000;
147 tv->tv_usec %= 1000000;
148}
149
150void
Denys Vlasenko12014262011-05-30 14:00:14 +0200151tv_mul(struct timeval *tv, struct timeval *a, int n)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000152{
153 tv->tv_usec = a->tv_usec * n;
Dmitry V. Levinfefdd972007-06-29 21:25:56 +0000154 tv->tv_sec = a->tv_sec * n + tv->tv_usec / 1000000;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000155 tv->tv_usec %= 1000000;
156}
157
Dmitry V. Levinab9008b2007-01-11 22:05:04 +0000158const char *
159xlookup(const struct xlat *xlat, int val)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000160{
161 for (; xlat->str != NULL; xlat++)
162 if (xlat->val == val)
163 return xlat->str;
164 return NULL;
165}
166
167/*
Roland McGratheb9e2e82009-06-02 16:49:22 -0700168 * Generic ptrace wrapper which tracks ESRCH errors
169 * by setting tcp->ptrace_errno to ESRCH.
Denys Vlasenko732d1bf2008-12-17 19:21:59 +0000170 *
171 * We assume that ESRCH indicates likely process death (SIGKILL?),
172 * modulo bugs where process somehow ended up not stopped.
173 * Unfortunately kernel uses ESRCH for that case too. Oh well.
Roland McGratheb9e2e82009-06-02 16:49:22 -0700174 *
175 * Currently used by upeek() only.
176 * TODO: use this in all other ptrace() calls while decoding.
Denys Vlasenko732d1bf2008-12-17 19:21:59 +0000177 */
Denys Vlasenko4dedd562009-02-24 15:17:53 +0000178long
Roland McGratheb9e2e82009-06-02 16:49:22 -0700179do_ptrace(int request, struct tcb *tcp, void *addr, void *data)
Denys Vlasenko4dedd562009-02-24 15:17:53 +0000180{
Denys Vlasenko732d1bf2008-12-17 19:21:59 +0000181 long l;
182
183 errno = 0;
Mike Frysinger09a13c22009-10-07 01:13:39 -0400184 l = ptrace(request, tcp->pid, addr, (long) data);
Roland McGratheb9e2e82009-06-02 16:49:22 -0700185 /* Non-ESRCH errors might be our invalid reg/mem accesses,
186 * we do not record them. */
187 if (errno == ESRCH)
188 tcp->ptrace_errno = ESRCH;
Denys Vlasenko732d1bf2008-12-17 19:21:59 +0000189 return l;
190}
191
192/*
193 * Used when we want to unblock stopped traced process.
194 * Should be only used with PTRACE_CONT, PTRACE_DETACH and PTRACE_SYSCALL.
195 * Returns 0 on success or if error was ESRCH
196 * (presumably process was killed while we talk to it).
197 * Otherwise prints error message and returns -1.
198 */
199int
Roland McGratheb9e2e82009-06-02 16:49:22 -0700200ptrace_restart(int op, struct tcb *tcp, int sig)
Denys Vlasenko732d1bf2008-12-17 19:21:59 +0000201{
202 int err;
Roland McGratheb9e2e82009-06-02 16:49:22 -0700203 const char *msg;
Denys Vlasenko732d1bf2008-12-17 19:21:59 +0000204
205 errno = 0;
Mike Frysinger09a13c22009-10-07 01:13:39 -0400206 ptrace(op, tcp->pid, (void *) 1, (long) sig);
Denys Vlasenko732d1bf2008-12-17 19:21:59 +0000207 err = errno;
208 if (!err || err == ESRCH)
209 return 0;
210
211 tcp->ptrace_errno = err;
Roland McGratheb9e2e82009-06-02 16:49:22 -0700212 msg = "SYSCALL";
213 if (op == PTRACE_CONT)
214 msg = "CONT";
215 if (op == PTRACE_DETACH)
216 msg = "DETACH";
217 fprintf(stderr, "strace: ptrace(PTRACE_%s,1,%d): %s\n",
218 msg, sig, strerror(err));
Denys Vlasenko732d1bf2008-12-17 19:21:59 +0000219 return -1;
220}
221
222/*
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000223 * Print entry in struct xlat table, if there.
224 */
225void
Dmitry V. Levinab9008b2007-01-11 22:05:04 +0000226printxval(const struct xlat *xlat, int val, const char *dflt)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000227{
Dmitry V. Levinab9008b2007-01-11 22:05:04 +0000228 const char *str = xlookup(xlat, val);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000229
230 if (str)
231 tprintf("%s", str);
232 else
233 tprintf("%#x /* %s */", val, dflt);
234}
235
Andreas Schwabb5600fc2009-11-04 17:08:34 +0100236#if HAVE_LONG_LONG
237/*
238 * Print 64bit argument at position llarg and return the index of the next
239 * argument.
240 */
241int
242printllval(struct tcb *tcp, const char *format, int llarg)
243{
244# if defined(FREEBSD) \
Andreas Schwabd69fa492010-07-12 21:39:57 +0200245 || (defined(LINUX) && defined(POWERPC) && !defined(POWERPC64)) \
Dmitry V. Levin7a5b08f2011-05-28 20:47:43 +0000246 || defined(LINUX_MIPSO32) \
247 || defined(__ARM_EABI__)
Andreas Schwabb5600fc2009-11-04 17:08:34 +0100248 /* Align 64bit argument to 64bit boundary. */
249 if (llarg % 2) llarg++;
250# endif
Andreas Schwabd69fa492010-07-12 21:39:57 +0200251# if defined LINUX && (defined X86_64 || defined POWERPC64)
Andreas Schwabb5600fc2009-11-04 17:08:34 +0100252 if (current_personality == 0) {
253 tprintf(format, tcp->u_arg[llarg]);
254 llarg++;
255 } else {
Andreas Schwabd69fa492010-07-12 21:39:57 +0200256# ifdef POWERPC64
257 /* Align 64bit argument to 64bit boundary. */
258 if (llarg % 2) llarg++;
259# endif
Andreas Schwabb5600fc2009-11-04 17:08:34 +0100260 tprintf(format, LONG_LONG(tcp->u_arg[llarg], tcp->u_arg[llarg + 1]));
261 llarg += 2;
262 }
Andreas Schwabd69fa492010-07-12 21:39:57 +0200263# elif defined IA64 || defined ALPHA
Andreas Schwabb5600fc2009-11-04 17:08:34 +0100264 tprintf(format, tcp->u_arg[llarg]);
265 llarg++;
266# elif defined LINUX_MIPSN32
267 tprintf(format, tcp->ext_arg[llarg]);
268 llarg++;
269# else
270 tprintf(format, LONG_LONG(tcp->u_arg[llarg], tcp->u_arg[llarg + 1]));
271 llarg += 2;
272# endif
273 return llarg;
274}
275#endif
276
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000277/*
278 * Interpret `xlat' as an array of flags
279 * print the entries whose bits are on in `flags'
280 * return # of flags printed.
281 */
282int
Denys Vlasenko12014262011-05-30 14:00:14 +0200283addflags(const struct xlat *xlat, int flags)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000284{
285 int n;
286
287 for (n = 0; xlat->str; xlat++) {
288 if (xlat->val && (flags & xlat->val) == xlat->val) {
289 tprintf("|%s", xlat->str);
290 flags &= ~xlat->val;
291 n++;
292 }
293 }
294 if (flags) {
295 tprintf("|%#x", flags);
296 n++;
297 }
298 return n;
299}
300
Roland McGratha6c0d8c2007-11-01 21:46:22 +0000301/*
302 * Interpret `xlat' as an array of flags/
303 * Print to static string the entries whose bits are on in `flags'
304 * Return static string.
305 */
306const char *
307sprintflags(const char *prefix, const struct xlat *xlat, int flags)
308{
309 static char outstr[1024];
310 int found = 0;
311
312 strcpy(outstr, prefix);
313
314 for (; xlat->str; xlat++) {
315 if ((flags & xlat->val) == xlat->val) {
316 if (found)
317 strcat(outstr, "|");
318 strcat(outstr, xlat->str);
319 flags &= ~xlat->val;
320 found = 1;
321 }
322 }
323 if (flags) {
324 if (found)
325 strcat(outstr, "|");
326 sprintf(outstr + strlen(outstr), "%#x", flags);
327 }
328
329 return outstr;
330}
331
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000332int
Dmitry V. Levin30145dd2010-09-06 22:08:24 +0000333printflags(const struct xlat *xlat, int flags, const char *dflt)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000334{
335 int n;
Dmitry V. Levin30145dd2010-09-06 22:08:24 +0000336 const char *sep;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000337
338 if (flags == 0 && xlat->val == 0) {
339 tprintf("%s", xlat->str);
340 return 1;
341 }
342
343 sep = "";
344 for (n = 0; xlat->str; xlat++) {
345 if (xlat->val && (flags & xlat->val) == xlat->val) {
346 tprintf("%s%s", sep, xlat->str);
347 flags &= ~xlat->val;
348 sep = "|";
349 n++;
350 }
351 }
Roland McGrathb2dee132005-06-01 19:02:36 +0000352
353 if (n) {
354 if (flags) {
355 tprintf("%s%#x", sep, flags);
356 n++;
357 }
358 } else {
359 if (flags) {
360 tprintf("%#x", flags);
361 if (dflt)
362 tprintf(" /* %s */", dflt);
363 } else {
364 if (dflt)
365 tprintf("0");
366 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000367 }
Roland McGrathb2dee132005-06-01 19:02:36 +0000368
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000369 return n;
370}
371
372void
Dmitry V. Levin30145dd2010-09-06 22:08:24 +0000373printnum(struct tcb *tcp, long addr, const char *fmt)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000374{
Roland McGratheb285352003-01-14 09:59:00 +0000375 long num;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000376
377 if (!addr) {
378 tprintf("NULL");
379 return;
380 }
381 if (umove(tcp, addr, &num) < 0) {
382 tprintf("%#lx", addr);
383 return;
384 }
385 tprintf("[");
386 tprintf(fmt, num);
387 tprintf("]");
388}
389
Roland McGrath6bc12202003-11-13 22:32:27 +0000390void
Dmitry V. Levin30145dd2010-09-06 22:08:24 +0000391printnum_int(struct tcb *tcp, long addr, const char *fmt)
Roland McGrath9814a942005-07-04 23:28:10 +0000392{
393 int num;
394
395 if (!addr) {
396 tprintf("NULL");
397 return;
398 }
399 if (umove(tcp, addr, &num) < 0) {
400 tprintf("%#lx", addr);
401 return;
402 }
403 tprintf("[");
404 tprintf(fmt, num);
405 tprintf("]");
406}
407
408void
Dmitry V. Levin31382132011-03-04 05:08:02 +0300409printfd(struct tcb *tcp, int fd)
410{
Grant Edwards8a082772011-04-07 20:25:40 +0000411 const char *p;
412
413 if (show_fd_path && (p = getfdpath(tcp, fd)))
414 tprintf("%d<%s>", fd, p);
415 else
416 tprintf("%d", fd);
Dmitry V. Levin31382132011-03-04 05:08:02 +0300417}
418
419void
Denys Vlasenko12014262011-05-30 14:00:14 +0200420printuid(const char *text, unsigned long uid)
Roland McGrath6bc12202003-11-13 22:32:27 +0000421{
422 tprintf("%s", text);
423 tprintf((uid == -1) ? "%ld" : "%lu", uid);
424}
425
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000426static char path[MAXPATHLEN + 1];
427
Dmitry V. Levina501f142008-11-10 23:19:13 +0000428/*
429 * Quote string `instr' of length `size'
430 * Write up to (3 + `size' * 4) bytes to `outstr' buffer.
431 * If `len' < 0, treat `instr' as a NUL-terminated string
432 * and quote at most (`size' - 1) bytes.
433 */
Roland McGrath6d970322007-11-01 23:53:59 +0000434static int
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000435string_quote(const char *instr, char *outstr, int len, int size)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000436{
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000437 const unsigned char *ustr = (const unsigned char *) instr;
438 char *s = outstr;
439 int usehex = 0, c, i;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000440
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000441 if (xflag > 1)
442 usehex = 1;
443 else if (xflag) {
Dmitry V. Levina501f142008-11-10 23:19:13 +0000444 /* Check for presence of symbol which require
445 to hex-quote the whole string. */
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000446 for (i = 0; i < size; ++i) {
447 c = ustr[i];
Dmitry V. Levina501f142008-11-10 23:19:13 +0000448 /* Check for NUL-terminated string. */
449 if (len < 0) {
450 if (c == '\0')
451 break;
452 /* Quote at most size - 1 bytes. */
453 if (i == size - 1)
454 continue;
455 }
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000456 if (!isprint(c) && !isspace(c)) {
457 usehex = 1;
458 break;
459 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000460 }
461 }
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000462
463 *s++ = '\"';
464
465 if (usehex) {
Dmitry V. Levina501f142008-11-10 23:19:13 +0000466 /* Hex-quote the whole string. */
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000467 for (i = 0; i < size; ++i) {
468 c = ustr[i];
Dmitry V. Levina501f142008-11-10 23:19:13 +0000469 /* Check for NUL-terminated string. */
470 if (len < 0) {
471 if (c == '\0')
472 break;
473 /* Quote at most size - 1 bytes. */
474 if (i == size - 1)
475 continue;
476 }
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000477 sprintf(s, "\\x%02x", c);
478 s += 4;
479 }
480 } else {
481 for (i = 0; i < size; ++i) {
482 c = ustr[i];
Dmitry V. Levina501f142008-11-10 23:19:13 +0000483 /* Check for NUL-terminated string. */
484 if (len < 0) {
485 if (c == '\0')
486 break;
487 /* Quote at most size - 1 bytes. */
488 if (i == size - 1)
489 continue;
490 }
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000491 switch (c) {
492 case '\"': case '\\':
493 *s++ = '\\';
494 *s++ = c;
495 break;
496 case '\f':
497 *s++ = '\\';
498 *s++ = 'f';
499 break;
500 case '\n':
501 *s++ = '\\';
502 *s++ = 'n';
503 break;
504 case '\r':
505 *s++ = '\\';
506 *s++ = 'r';
507 break;
508 case '\t':
509 *s++ = '\\';
510 *s++ = 't';
511 break;
512 case '\v':
513 *s++ = '\\';
514 *s++ = 'v';
515 break;
516 default:
517 if (isprint(c))
518 *s++ = c;
519 else if (i + 1 < size
520 && isdigit(ustr[i + 1])) {
521 sprintf(s, "\\%03o", c);
522 s += 4;
523 } else {
524 sprintf(s, "\\%o", c);
525 s += strlen(s);
526 }
527 break;
528 }
529 }
530 }
531
532 *s++ = '\"';
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000533 *s = '\0';
Roland McGrath6d970322007-11-01 23:53:59 +0000534
535 /* Return nonzero if the string was unterminated. */
536 return i == size;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000537}
538
Dmitry V. Levina501f142008-11-10 23:19:13 +0000539/*
540 * Print path string specified by address `addr' and length `n'.
541 * If path length exceeds `n', append `...' to the output.
542 */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000543void
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000544printpathn(struct tcb *tcp, long addr, int n)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000545{
Dmitry V. Levina501f142008-11-10 23:19:13 +0000546 if (!addr) {
Roland McGrath371ed8f2005-02-06 01:55:07 +0000547 tprintf("NULL");
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000548 return;
549 }
550
Dmitry V. Levina501f142008-11-10 23:19:13 +0000551 /* Cap path length to the path buffer size,
552 and NUL-terminate the buffer. */
553 if (n > sizeof path - 1)
554 n = sizeof path - 1;
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000555 path[n] = '\0';
Dmitry V. Levina501f142008-11-10 23:19:13 +0000556
557 /* Fetch one byte more to find out whether path length > n. */
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000558 if (umovestr(tcp, addr, n + 1, path) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000559 tprintf("%#lx", addr);
560 else {
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000561 static char outstr[4*(sizeof path - 1) + sizeof "\"...\""];
562 int trunc = (path[n] != '\0');
563
564 if (trunc)
565 path[n] = '\0';
Dmitry V. Levina501f142008-11-10 23:19:13 +0000566 (void) string_quote(path, outstr, -1, n + 1);
567 if (trunc)
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000568 strcat(outstr, "...");
569 tprintf("%s", outstr);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000570 }
571}
572
573void
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000574printpath(struct tcb *tcp, long addr)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000575{
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000576 printpathn(tcp, addr, sizeof path - 1);
577}
578
Dmitry V. Levina501f142008-11-10 23:19:13 +0000579/*
580 * Print string specified by address `addr' and length `len'.
581 * If `len' < 0, treat the string as a NUL-terminated string.
582 * If string length exceeds `max_strlen', append `...' to the output.
583 */
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000584void
585printstr(struct tcb *tcp, long addr, int len)
586{
587 static char *str = NULL;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000588 static char *outstr;
Roland McGrath6d970322007-11-01 23:53:59 +0000589 int size;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000590
591 if (!addr) {
592 tprintf("NULL");
593 return;
594 }
Dmitry V. Levina501f142008-11-10 23:19:13 +0000595 /* Allocate static buffers if they are not allocated yet. */
596 if (!str)
597 str = malloc(max_strlen + 1);
598 if (!outstr)
599 outstr = malloc(4 * max_strlen + sizeof "\"...\"");
600 if (!str || !outstr) {
601 fprintf(stderr, "out of memory\n");
602 tprintf("%#lx", addr);
603 return;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000604 }
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000605
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000606 if (len < 0) {
Dmitry V. Levina501f142008-11-10 23:19:13 +0000607 /*
608 * Treat as a NUL-terminated string: fetch one byte more
609 * because string_quote() quotes one byte less.
610 */
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000611 size = max_strlen + 1;
Dmitry V. Levina501f142008-11-10 23:19:13 +0000612 str[max_strlen] = '\0';
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000613 if (umovestr(tcp, addr, size, str) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000614 tprintf("%#lx", addr);
615 return;
616 }
617 }
618 else {
Dmitry V. Levina501f142008-11-10 23:19:13 +0000619 size = MIN(len, max_strlen);
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000620 if (umoven(tcp, addr, size, str) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000621 tprintf("%#lx", addr);
622 return;
623 }
624 }
625
Dmitry V. Levina501f142008-11-10 23:19:13 +0000626 if (string_quote(str, outstr, len, size) &&
627 (len < 0 || len > max_strlen))
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000628 strcat(outstr, "...");
Roland McGratha503dcf2007-08-02 02:06:26 +0000629
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000630 tprintf("%s", outstr);
631}
632
John Hughes1d08dcf2001-07-10 13:48:44 +0000633#if HAVE_SYS_UIO_H
634void
Denys Vlasenko12014262011-05-30 14:00:14 +0200635dumpiov(struct tcb *tcp, int len, long addr)
John Hughes1d08dcf2001-07-10 13:48:44 +0000636{
Dmitry V. Levin4ebb4e32006-12-13 17:08:08 +0000637#if defined(LINUX) && SUPPORTED_PERSONALITIES > 1
638 union {
639 struct { u_int32_t base; u_int32_t len; } *iov32;
640 struct { u_int64_t base; u_int64_t len; } *iov64;
641 } iovu;
642#define iov iovu.iov64
643#define sizeof_iov \
644 (personality_wordsize[current_personality] == 4 \
645 ? sizeof(*iovu.iov32) : sizeof(*iovu.iov64))
646#define iov_iov_base(i) \
647 (personality_wordsize[current_personality] == 4 \
648 ? (u_int64_t) iovu.iov32[i].base : iovu.iov64[i].base)
649#define iov_iov_len(i) \
650 (personality_wordsize[current_personality] == 4 \
651 ? (u_int64_t) iovu.iov32[i].len : iovu.iov64[i].len)
652#else
John Hughes1d08dcf2001-07-10 13:48:44 +0000653 struct iovec *iov;
Dmitry V. Levin4ebb4e32006-12-13 17:08:08 +0000654#define sizeof_iov sizeof(*iov)
655#define iov_iov_base(i) iov[i].iov_base
656#define iov_iov_len(i) iov[i].iov_len
657#endif
John Hughes1d08dcf2001-07-10 13:48:44 +0000658 int i;
Roland McGrathaa524c82005-06-01 19:22:06 +0000659 unsigned long size;
John Hughes1d08dcf2001-07-10 13:48:44 +0000660
Dmitry V. Levin4ebb4e32006-12-13 17:08:08 +0000661 size = sizeof_iov * (unsigned long) len;
662 if (size / sizeof_iov != len
663 || (iov = malloc(size)) == NULL) {
Roland McGrathaa524c82005-06-01 19:22:06 +0000664 fprintf(stderr, "out of memory\n");
John Hughes1d08dcf2001-07-10 13:48:44 +0000665 return;
666 }
Roland McGrathaa524c82005-06-01 19:22:06 +0000667 if (umoven(tcp, addr, size, (char *) iov) >= 0) {
John Hughes1d08dcf2001-07-10 13:48:44 +0000668 for (i = 0; i < len; i++) {
Denys Vlasenkoadedb512008-12-30 18:47:55 +0000669 /* include the buffer number to make it easy to
670 * match up the trace with the source */
671 tprintf(" * %lu bytes in buffer %d\n",
672 (unsigned long)iov_iov_len(i), i);
673 dumpstr(tcp, (long) iov_iov_base(i),
674 iov_iov_len(i));
675 }
John Hughes1d08dcf2001-07-10 13:48:44 +0000676 }
677 free((char *) iov);
Dmitry V. Levin4ebb4e32006-12-13 17:08:08 +0000678#undef sizeof_iov
679#undef iov_iov_base
680#undef iov_iov_len
681#undef iov
John Hughes1d08dcf2001-07-10 13:48:44 +0000682}
683#endif
684
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000685void
Denys Vlasenko12014262011-05-30 14:00:14 +0200686dumpstr(struct tcb *tcp, long addr, int len)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000687{
688 static int strsize = -1;
689 static unsigned char *str;
690 static char outstr[80];
691 char *s;
692 int i, j;
693
694 if (strsize < len) {
695 if (str)
696 free(str);
697 if ((str = malloc(len)) == NULL) {
Roland McGrath46100d02005-06-01 18:55:42 +0000698 fprintf(stderr, "out of memory\n");
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000699 return;
700 }
701 strsize = len;
702 }
703
704 if (umoven(tcp, addr, len, (char *) str) < 0)
705 return;
706
707 for (i = 0; i < len; i += 16) {
708 s = outstr;
709 sprintf(s, " | %05x ", i);
710 s += 9;
711 for (j = 0; j < 16; j++) {
712 if (j == 8)
713 *s++ = ' ';
714 if (i + j < len) {
715 sprintf(s, " %02x", str[i + j]);
716 s += 3;
717 }
718 else {
719 *s++ = ' '; *s++ = ' '; *s++ = ' ';
720 }
721 }
722 *s++ = ' '; *s++ = ' ';
723 for (j = 0; j < 16; j++) {
724 if (j == 8)
725 *s++ = ' ';
726 if (i + j < len) {
727 if (isprint(str[i + j]))
728 *s++ = str[i + j];
729 else
730 *s++ = '.';
731 }
732 else
733 *s++ = ' ';
734 }
735 tprintf("%s |\n", outstr);
736 }
737}
738
739#define PAGMASK (~(PAGSIZ - 1))
740/*
741 * move `len' bytes of data from process `pid'
742 * at address `addr' to our space at `laddr'
743 */
744int
Denys Vlasenkoef2fbf82009-01-06 21:45:06 +0000745umoven(struct tcb *tcp, long addr, int len, char *laddr)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000746{
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000747#ifdef LINUX
Roland McGratheb9e2e82009-06-02 16:49:22 -0700748 int pid = tcp->pid;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000749 int n, m;
Wichert Akkerman5daa0281999-03-15 19:49:42 +0000750 int started = 0;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000751 union {
752 long val;
753 char x[sizeof(long)];
754 } u;
755
756 if (addr & (sizeof(long) - 1)) {
757 /* addr not a multiple of sizeof(long) */
758 n = addr - (addr & -sizeof(long)); /* residue */
759 addr &= -sizeof(long); /* residue */
Roland McGratheb9e2e82009-06-02 16:49:22 -0700760 errno = 0;
761 u.val = ptrace(PTRACE_PEEKDATA, pid, (char *) addr, 0);
762 if (errno) {
763 if (started && (errno==EPERM || errno==EIO)) {
764 /* Ran into 'end of memory' - stupid "printpath" */
765 return 0;
766 }
767 /* But if not started, we had a bogus address. */
768 if (addr != 0 && errno != EIO && errno != ESRCH)
769 perror("ptrace: umoven");
770 return -1;
771 }
Wichert Akkerman5daa0281999-03-15 19:49:42 +0000772 started = 1;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000773 memcpy(laddr, &u.x[n], m = MIN(sizeof(long) - n, len));
774 addr += sizeof(long), laddr += m, len -= m;
775 }
776 while (len) {
Roland McGratheb9e2e82009-06-02 16:49:22 -0700777 errno = 0;
778 u.val = ptrace(PTRACE_PEEKDATA, pid, (char *) addr, 0);
779 if (errno) {
780 if (started && (errno==EPERM || errno==EIO)) {
781 /* Ran into 'end of memory' - stupid "printpath" */
782 return 0;
783 }
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, m = MIN(sizeof(long), len));
790 addr += sizeof(long), laddr += m, len -= m;
791 }
792#endif /* LINUX */
793
794#ifdef SUNOS4
795 int pid = tcp->pid;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000796 int n;
797
798 while (len) {
799 n = MIN(len, PAGSIZ);
800 n = MIN(n, ((addr + PAGSIZ) & PAGMASK) - addr);
Roland McGratheb9e2e82009-06-02 16:49:22 -0700801 if (ptrace(PTRACE_READDATA, pid,
802 (char *) addr, len, laddr) < 0) {
803 if (errno != ESRCH) {
804 perror("umoven: ptrace(PTRACE_READDATA, ...)");
805 abort();
806 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000807 return -1;
808 }
809 len -= n;
810 addr += n;
811 laddr += n;
812 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000813#endif /* SUNOS4 */
814
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000815#ifdef USE_PROCFS
Wichert Akkermanea78f0f1999-11-29 15:34:02 +0000816#ifdef HAVE_MP_PROCFS
John Hughesaa09c6b2001-05-15 14:53:43 +0000817 int fd = tcp->pfd_as;
Wichert Akkerman9ce1a631999-08-29 23:15:07 +0000818#else
John Hughesaa09c6b2001-05-15 14:53:43 +0000819 int fd = tcp->pfd;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000820#endif
John Hughesaa09c6b2001-05-15 14:53:43 +0000821 lseek(fd, addr, SEEK_SET);
822 if (read(fd, laddr, len) == -1)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000823 return -1;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000824#endif /* USE_PROCFS */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000825
826 return 0;
827}
828
829/*
830 * like `umove' but make the additional effort of looking
831 * for a terminating zero byte.
832 */
833int
Denys Vlasenkoef2fbf82009-01-06 21:45:06 +0000834umovestr(struct tcb *tcp, long addr, int len, char *laddr)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000835{
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000836#ifdef USE_PROCFS
John Hughesaa09c6b2001-05-15 14:53:43 +0000837#ifdef HAVE_MP_PROCFS
838 int fd = tcp->pfd_as;
839#else
840 int fd = tcp->pfd;
841#endif
842 /* Some systems (e.g. FreeBSD) can be upset if we read off the
843 end of valid memory, avoid this by trying to read up
844 to page boundaries. But we don't know what a page is (and
845 getpagesize(2) (if it exists) doesn't necessarily return
846 hardware page size). Assume all pages >= 1024 (a-historical
847 I know) */
848
849 int page = 1024; /* How to find this? */
850 int move = page - (addr & (page - 1));
851 int left = len;
852
853 lseek(fd, addr, SEEK_SET);
854
855 while (left) {
856 if (move > left) move = left;
John Hughes9cecf7f2001-10-16 10:20:22 +0000857 if ((move = read(fd, laddr, move)) <= 0)
John Hughesaa09c6b2001-05-15 14:53:43 +0000858 return left != len ? 0 : -1;
859 if (memchr (laddr, 0, move)) break;
860 left -= move;
861 laddr += move;
862 addr += move;
863 move = page;
864 }
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000865#else /* !USE_PROCFS */
Wichert Akkerman5daa0281999-03-15 19:49:42 +0000866 int started = 0;
Roland McGratheb9e2e82009-06-02 16:49:22 -0700867 int pid = tcp->pid;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000868 int i, n, m;
869 union {
870 long val;
871 char x[sizeof(long)];
872 } u;
873
874 if (addr & (sizeof(long) - 1)) {
875 /* addr not a multiple of sizeof(long) */
876 n = addr - (addr & -sizeof(long)); /* residue */
877 addr &= -sizeof(long); /* residue */
Roland McGratheb9e2e82009-06-02 16:49:22 -0700878 errno = 0;
879 u.val = ptrace(PTRACE_PEEKDATA, pid, (char *)addr, 0);
880 if (errno) {
881 if (started && (errno==EPERM || errno==EIO)) {
882 /* Ran into 'end of memory' - stupid "printpath" */
883 return 0;
884 }
885 if (addr != 0 && errno != EIO && errno != ESRCH)
886 perror("umovestr");
887 return -1;
888 }
Wichert Akkerman5daa0281999-03-15 19:49:42 +0000889 started = 1;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000890 memcpy(laddr, &u.x[n], m = MIN(sizeof(long)-n,len));
891 while (n & (sizeof(long) - 1))
892 if (u.x[n++] == '\0')
893 return 0;
894 addr += sizeof(long), laddr += m, len -= m;
895 }
896 while (len) {
Roland McGratheb9e2e82009-06-02 16:49:22 -0700897 errno = 0;
898 u.val = ptrace(PTRACE_PEEKDATA, pid, (char *)addr, 0);
899 if (errno) {
900 if (started && (errno==EPERM || errno==EIO)) {
901 /* Ran into 'end of memory' - stupid "printpath" */
902 return 0;
903 }
904 if (addr != 0 && errno != EIO && errno != ESRCH)
905 perror("umovestr");
906 return -1;
907 }
Wichert Akkerman5daa0281999-03-15 19:49:42 +0000908 started = 1;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000909 memcpy(laddr, u.x, m = MIN(sizeof(long), len));
910 for (i = 0; i < sizeof(long); i++)
911 if (u.x[i] == '\0')
912 return 0;
913
914 addr += sizeof(long), laddr += m, len -= m;
915 }
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000916#endif /* !USE_PROCFS */
John Hughesaa09c6b2001-05-15 14:53:43 +0000917 return 0;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000918}
919
920#ifdef LINUX
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +0000921# if !defined (SPARC) && !defined(SPARC64)
922# define PTRACE_WRITETEXT 101
923# define PTRACE_WRITEDATA 102
924# endif /* !SPARC && !SPARC64 */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000925#endif /* LINUX */
926
927#ifdef SUNOS4
928
929static int
Denys Vlasenko12014262011-05-30 14:00:14 +0200930uload(int cmd, int pid, long addr, int len, char *laddr)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000931{
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000932 int peek, poke;
933 int n, m;
934 union {
935 long val;
936 char x[sizeof(long)];
937 } u;
938
939 if (cmd == PTRACE_WRITETEXT) {
940 peek = PTRACE_PEEKTEXT;
941 poke = PTRACE_POKETEXT;
942 }
943 else {
944 peek = PTRACE_PEEKDATA;
945 poke = PTRACE_POKEDATA;
946 }
947 if (addr & (sizeof(long) - 1)) {
948 /* addr not a multiple of sizeof(long) */
949 n = addr - (addr & -sizeof(long)); /* residue */
950 addr &= -sizeof(long);
Roland McGratheb9e2e82009-06-02 16:49:22 -0700951 errno = 0;
952 u.val = ptrace(peek, pid, (char *) addr, 0);
953 if (errno) {
954 perror("uload: POKE");
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000955 return -1;
956 }
Roland McGratheb9e2e82009-06-02 16:49:22 -0700957 memcpy(&u.x[n], laddr, m = MIN(sizeof(long) - n, len));
958 if (ptrace(poke, pid, (char *)addr, u.val) < 0) {
959 perror("uload: POKE");
960 return -1;
961 }
962 addr += sizeof(long), laddr += m, len -= m;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000963 }
964 while (len) {
965 if (len < sizeof(long))
Roland McGratheb9e2e82009-06-02 16:49:22 -0700966 u.val = ptrace(peek, pid, (char *) addr, 0);
967 memcpy(u.x, laddr, m = MIN(sizeof(long), len));
968 if (ptrace(poke, pid, (char *) addr, u.val) < 0) {
969 perror("uload: POKE");
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000970 return -1;
971 }
Roland McGratheb9e2e82009-06-02 16:49:22 -0700972 addr += sizeof(long), laddr += m, len -= m;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000973 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000974 return 0;
975}
976
Roland McGratheb9e2e82009-06-02 16:49:22 -0700977int
Denys Vlasenko12014262011-05-30 14:00:14 +0200978tload(int pid, int addr, int len, char *laddr)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000979{
Roland McGratheb9e2e82009-06-02 16:49:22 -0700980 return uload(PTRACE_WRITETEXT, pid, addr, len, laddr);
981}
982
983int
Denys Vlasenko12014262011-05-30 14:00:14 +0200984dload(int pid, int addr, int len, char *laddr)
Roland McGratheb9e2e82009-06-02 16:49:22 -0700985{
986 return uload(PTRACE_WRITEDATA, pid, addr, len, laddr);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000987}
988
989#endif /* SUNOS4 */
990
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000991#ifndef USE_PROCFS
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000992
993int
Denys Vlasenko12014262011-05-30 14:00:14 +0200994upeek(struct tcb *tcp, long off, long *res)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000995{
996 long val;
997
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +0000998# ifdef SUNOS4_KERNEL_ARCH_KLUDGE
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000999 {
1000 static int is_sun4m = -1;
1001 struct utsname name;
1002
1003 /* Round up the usual suspects. */
1004 if (is_sun4m == -1) {
1005 if (uname(&name) < 0) {
1006 perror("upeek: uname?");
1007 exit(1);
1008 }
1009 is_sun4m = strcmp(name.machine, "sun4m") == 0;
1010 if (is_sun4m) {
Roland McGrathd9f816f2004-09-04 03:39:20 +00001011 const struct xlat *x;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001012
1013 for (x = struct_user_offsets; x->str; x++)
1014 x->val += 1024;
1015 }
1016 }
1017 if (is_sun4m)
1018 off += 1024;
1019 }
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001020# endif /* SUNOS4_KERNEL_ARCH_KLUDGE */
Roland McGratheb9e2e82009-06-02 16:49:22 -07001021 errno = 0;
Denys Vlasenko732d1bf2008-12-17 19:21:59 +00001022 val = do_ptrace(PTRACE_PEEKUSER, tcp, (char *) off, 0);
Roland McGratheb9e2e82009-06-02 16:49:22 -07001023 if (val == -1 && errno) {
1024 if (errno != ESRCH) {
1025 char buf[60];
1026 sprintf(buf,"upeek: ptrace(PTRACE_PEEKUSER,%d,%lu,0)", tcp->pid, off);
1027 perror(buf);
1028 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001029 return -1;
Roland McGratheb9e2e82009-06-02 16:49:22 -07001030 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001031 *res = val;
1032 return 0;
1033}
1034
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001035#endif /* !USE_PROCFS */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001036
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001037void
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001038printcall(struct tcb *tcp)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001039{
Roland McGrath7a918832005-02-02 20:55:23 +00001040#define PRINTBADPC tprintf(sizeof(long) == 4 ? "[????????] " : \
1041 sizeof(long) == 8 ? "[????????????????] " : \
1042 NULL /* crash */)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001043
1044#ifdef LINUX
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001045# ifdef I386
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001046 long eip;
1047
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001048 if (upeek(tcp, 4*EIP, &eip) < 0) {
Roland McGrath7a918832005-02-02 20:55:23 +00001049 PRINTBADPC;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001050 return;
1051 }
1052 tprintf("[%08lx] ", eip);
Roland McGratheac26fc2005-02-02 02:48:53 +00001053
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001054# elif defined(S390) || defined(S390X)
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001055 long psw;
Roland McGratheb9e2e82009-06-02 16:49:22 -07001056 if(upeek(tcp,PT_PSWADDR,&psw) < 0) {
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001057 PRINTBADPC;
1058 return;
1059 }
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001060# ifdef S390
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001061 tprintf("[%08lx] ", psw);
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001062# elif S390X
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001063 tprintf("[%16lx] ", psw);
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001064# endif
Roland McGratheac26fc2005-02-02 02:48:53 +00001065
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001066# elif defined(X86_64)
Michal Ludvig0e035502002-09-23 15:41:01 +00001067 long rip;
1068
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001069 if (upeek(tcp, 8*RIP, &rip) < 0) {
Roland McGrath7a918832005-02-02 20:55:23 +00001070 PRINTBADPC;
Michal Ludvig0e035502002-09-23 15:41:01 +00001071 return;
1072 }
1073 tprintf("[%16lx] ", rip);
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001074# elif defined(IA64)
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00001075 long ip;
1076
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001077 if (upeek(tcp, PT_B0, &ip) < 0) {
Roland McGrath7a918832005-02-02 20:55:23 +00001078 PRINTBADPC;
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00001079 return;
1080 }
1081 tprintf("[%08lx] ", ip);
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001082# elif defined(POWERPC)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001083 long pc;
1084
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001085 if (upeek(tcp, sizeof(unsigned long)*PT_NIP, &pc) < 0) {
Andreas Schwabd69fa492010-07-12 21:39:57 +02001086 PRINTBADPC;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001087 return;
1088 }
Andreas Schwabd69fa492010-07-12 21:39:57 +02001089# ifdef POWERPC64
1090 tprintf("[%016lx] ", pc);
1091# else
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001092 tprintf("[%08lx] ", pc);
Andreas Schwabd69fa492010-07-12 21:39:57 +02001093# endif
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001094# elif defined(M68K)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001095 long pc;
1096
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001097 if (upeek(tcp, 4*PT_PC, &pc) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001098 tprintf ("[????????] ");
1099 return;
1100 }
1101 tprintf("[%08lx] ", pc);
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001102# elif defined(ALPHA)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001103 long pc;
1104
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001105 if (upeek(tcp, REG_PC, &pc) < 0) {
Roland McGrath7a918832005-02-02 20:55:23 +00001106 tprintf ("[????????????????] ");
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001107 return;
1108 }
1109 tprintf("[%08lx] ", pc);
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001110# elif defined(SPARC) || defined(SPARC64)
Mike Frysinger8566c502009-10-12 11:05:14 -04001111 struct pt_regs regs;
Roland McGratheb9e2e82009-06-02 16:49:22 -07001112 if (ptrace(PTRACE_GETREGS,tcp->pid,(char *)&regs,0) < 0) {
Roland McGrath7a918832005-02-02 20:55:23 +00001113 PRINTBADPC;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001114 return;
1115 }
Mike Frysinger8566c502009-10-12 11:05:14 -04001116# if defined(SPARC64)
1117 tprintf("[%08lx] ", regs.tpc);
1118# else
1119 tprintf("[%08lx] ", regs.pc);
1120# endif
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001121# elif defined(HPPA)
Wichert Akkermanc1652e22001-03-27 12:17:16 +00001122 long pc;
1123
Roland McGratheb9e2e82009-06-02 16:49:22 -07001124 if(upeek(tcp,PT_IAOQ0,&pc) < 0) {
Wichert Akkermanc1652e22001-03-27 12:17:16 +00001125 tprintf ("[????????] ");
1126 return;
1127 }
1128 tprintf("[%08lx] ", pc);
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001129# elif defined(MIPS)
Wichert Akkerman75c422b2001-04-10 10:22:50 +00001130 long pc;
1131
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001132 if (upeek(tcp, REG_EPC, &pc) < 0) {
Wichert Akkerman75c422b2001-04-10 10:22:50 +00001133 tprintf ("[????????] ");
1134 return;
1135 }
1136 tprintf("[%08lx] ", pc);
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001137# elif defined(SH)
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001138 long pc;
Wichert Akkermanccef6372002-05-01 16:39:22 +00001139
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001140 if (upeek(tcp, 4*REG_PC, &pc) < 0) {
1141 tprintf ("[????????] ");
1142 return;
1143 }
1144 tprintf("[%08lx] ", pc);
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001145# elif defined(SH64)
Roland McGrathe1e584b2003-06-02 19:18:58 +00001146 long pc;
1147
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001148 if (upeek(tcp, REG_PC, &pc) < 0) {
Roland McGrath7a918832005-02-02 20:55:23 +00001149 tprintf ("[????????????????] ");
Roland McGrathe1e584b2003-06-02 19:18:58 +00001150 return;
1151 }
1152 tprintf("[%08lx] ", pc);
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001153# elif defined(ARM)
Roland McGrathef388682003-06-03 23:28:59 +00001154 long pc;
Roland McGrathe1e584b2003-06-02 19:18:58 +00001155
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001156 if (upeek(tcp, 4*15, &pc) < 0) {
Roland McGrath7a918832005-02-02 20:55:23 +00001157 PRINTBADPC;
Roland McGrathef388682003-06-03 23:28:59 +00001158 return;
1159 }
1160 tprintf("[%08lx] ", pc);
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00001161# elif defined(AVR32)
1162 long pc;
1163
1164 if (upeek(tcp, REG_PC, &pc) < 0) {
1165 tprintf("[????????] ");
1166 return;
1167 }
1168 tprintf("[%08lx] ", pc);
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001169# elif defined(BFIN)
Dmitry V. Levin87ea1f42008-11-10 22:21:41 +00001170 long pc;
1171
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001172 if (upeek(tcp, PT_PC, &pc) < 0) {
Dmitry V. Levin87ea1f42008-11-10 22:21:41 +00001173 PRINTBADPC;
1174 return;
1175 }
1176 tprintf("[%08lx] ", pc);
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001177#elif defined(CRISV10)
1178 long pc;
1179
Edgar E. Iglesiaseeb9ce32009-10-05 14:41:02 +00001180 if (upeek(tcp, 4*PT_IRP, &pc) < 0) {
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001181 PRINTBADPC;
1182 return;
1183 }
1184 tprintf("[%08lx] ", pc);
1185#elif defined(CRISV32)
1186 long pc;
1187
Edgar E. Iglesiaseeb9ce32009-10-05 14:41:02 +00001188 if (upeek(tcp, 4*PT_ERP, &pc) < 0) {
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001189 PRINTBADPC;
1190 return;
1191 }
1192 tprintf("[%08lx] ", pc);
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001193# endif /* architecture */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001194#endif /* LINUX */
1195
1196#ifdef SUNOS4
1197 struct regs regs;
1198
Roland McGratheb9e2e82009-06-02 16:49:22 -07001199 if (ptrace(PTRACE_GETREGS, tcp->pid, (char *) &regs, 0) < 0) {
1200 perror("printcall: ptrace(PTRACE_GETREGS, ...)");
Roland McGrath7a918832005-02-02 20:55:23 +00001201 PRINTBADPC;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001202 return;
1203 }
1204 tprintf("[%08x] ", regs.r_o7);
1205#endif /* SUNOS4 */
1206
1207#ifdef SVR4
1208 /* XXX */
Roland McGrath7a918832005-02-02 20:55:23 +00001209 PRINTBADPC;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001210#endif
1211
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001212#ifdef FREEBSD
1213 struct reg regs;
1214 pread(tcp->pfd_reg, &regs, sizeof(regs), 0);
1215 tprintf("[%08x] ", regs.r_eip);
1216#endif /* FREEBSD */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001217}
1218
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001219
1220/*
1221 * These #if's are huge, please indent them correctly.
1222 * It's easy to get confused otherwise.
1223 */
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001224#ifndef USE_PROCFS
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001225
Dmitry V. Levine5e60852009-12-31 22:50:49 +00001226#ifdef LINUX
Roland McGrathd81f1d92003-01-09 06:53:34 +00001227
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001228# include "syscall.h"
Roland McGrath3291ef22008-05-20 00:34:34 +00001229
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001230# include <sys/syscall.h>
1231# ifndef CLONE_PTRACE
1232# define CLONE_PTRACE 0x00002000
1233# endif
1234# ifndef CLONE_VFORK
1235# define CLONE_VFORK 0x00004000
1236# endif
1237# ifndef CLONE_VM
1238# define CLONE_VM 0x00000100
1239# endif
1240# ifndef CLONE_STOPPED
1241# define CLONE_STOPPED 0x02000000
1242# endif
Roland McGrathd81f1d92003-01-09 06:53:34 +00001243
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001244# ifdef IA64
Roland McGrathd81f1d92003-01-09 06:53:34 +00001245
Roland McGrath08267b82004-02-20 22:56:43 +00001246/* We don't have fork()/vfork() syscalls on ia64 itself, but the ia32
1247 subsystem has them for x86... */
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001248# define SYS_fork 2
1249# define SYS_vfork 190
Roland McGrath08267b82004-02-20 22:56:43 +00001250
Roland McGrathd81f1d92003-01-09 06:53:34 +00001251typedef unsigned long *arg_setup_state;
1252
1253static int
1254arg_setup(struct tcb *tcp, arg_setup_state *state)
1255{
Jan Kratochvil1f942712008-08-06 21:38:52 +00001256 unsigned long cfm, sof, sol;
1257 long bsp;
Roland McGrathd81f1d92003-01-09 06:53:34 +00001258
Jan Kratochvil1f942712008-08-06 21:38:52 +00001259 if (ia32) {
1260 /* Satisfy a false GCC warning. */
1261 *state = NULL;
Roland McGrath08267b82004-02-20 22:56:43 +00001262 return 0;
Jan Kratochvil1f942712008-08-06 21:38:52 +00001263 }
Roland McGrath08267b82004-02-20 22:56:43 +00001264
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001265 if (upeek(tcp, PT_AR_BSP, &bsp) < 0)
Roland McGrathd81f1d92003-01-09 06:53:34 +00001266 return -1;
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001267 if (upeek(tcp, PT_CFM, (long *) &cfm) < 0)
Roland McGrathd81f1d92003-01-09 06:53:34 +00001268 return -1;
1269
1270 sof = (cfm >> 0) & 0x7f;
1271 sol = (cfm >> 7) & 0x7f;
Jan Kratochvil1f942712008-08-06 21:38:52 +00001272 bsp = (long) ia64_rse_skip_regs((unsigned long *) bsp, -sof + sol);
Roland McGrathd81f1d92003-01-09 06:53:34 +00001273
Jan Kratochvil1f942712008-08-06 21:38:52 +00001274 *state = (unsigned long *) bsp;
Roland McGrathd81f1d92003-01-09 06:53:34 +00001275 return 0;
1276}
1277
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001278# define arg_finish_change(tcp, state) 0
Roland McGrathd81f1d92003-01-09 06:53:34 +00001279
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001280# ifdef SYS_fork
Roland McGrathd81f1d92003-01-09 06:53:34 +00001281static int
Denys Vlasenko12014262011-05-30 14:00:14 +02001282get_arg0(struct tcb *tcp, arg_setup_state *state, long *valp)
Roland McGrathd81f1d92003-01-09 06:53:34 +00001283{
Roland McGrath08267b82004-02-20 22:56:43 +00001284 int ret;
1285
1286 if (ia32)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001287 ret = upeek (tcp, PT_R11, valp);
Roland McGrath08267b82004-02-20 22:56:43 +00001288 else
1289 ret = umoven (tcp,
1290 (unsigned long) ia64_rse_skip_regs(*state, 0),
1291 sizeof(long), (void *) valp);
1292 return ret;
Roland McGrathd81f1d92003-01-09 06:53:34 +00001293}
1294
1295static int
Denys Vlasenko12014262011-05-30 14:00:14 +02001296get_arg1(struct tcb *tcp, arg_setup_state *state, long *valp)
Roland McGrathd81f1d92003-01-09 06:53:34 +00001297{
Roland McGrath08267b82004-02-20 22:56:43 +00001298 int ret;
1299
1300 if (ia32)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001301 ret = upeek (tcp, PT_R9, valp);
Roland McGrath08267b82004-02-20 22:56:43 +00001302 else
1303 ret = umoven (tcp,
1304 (unsigned long) ia64_rse_skip_regs(*state, 1),
1305 sizeof(long), (void *) valp);
1306 return ret;
Roland McGrathd81f1d92003-01-09 06:53:34 +00001307}
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001308# endif
Roland McGrathd81f1d92003-01-09 06:53:34 +00001309
1310static int
Denys Vlasenko12014262011-05-30 14:00:14 +02001311set_arg0(struct tcb *tcp, arg_setup_state *state, long val)
Roland McGrathd81f1d92003-01-09 06:53:34 +00001312{
Roland McGrath08267b82004-02-20 22:56:43 +00001313 int req = PTRACE_POKEDATA;
1314 void *ap;
1315
1316 if (ia32) {
1317 ap = (void *) (intptr_t) PT_R11; /* r11 == EBX */
1318 req = PTRACE_POKEUSER;
1319 } else
1320 ap = ia64_rse_skip_regs(*state, 0);
Roland McGratheb9e2e82009-06-02 16:49:22 -07001321 errno = 0;
1322 ptrace(req, tcp->pid, ap, val);
1323 return errno ? -1 : 0;
Roland McGrathd81f1d92003-01-09 06:53:34 +00001324}
1325
1326static int
Denys Vlasenko12014262011-05-30 14:00:14 +02001327set_arg1(struct tcb *tcp, arg_setup_state *state, long val)
Roland McGrathd81f1d92003-01-09 06:53:34 +00001328{
Roland McGrath08267b82004-02-20 22:56:43 +00001329 int req = PTRACE_POKEDATA;
1330 void *ap;
1331
1332 if (ia32) {
1333 ap = (void *) (intptr_t) PT_R9; /* r9 == ECX */
1334 req = PTRACE_POKEUSER;
1335 } else
1336 ap = ia64_rse_skip_regs(*state, 1);
Roland McGratheb9e2e82009-06-02 16:49:22 -07001337 errno = 0;
1338 ptrace(req, tcp->pid, ap, val);
1339 return errno ? -1 : 0;
Roland McGrathd81f1d92003-01-09 06:53:34 +00001340}
1341
Roland McGrathb659f872008-07-18 01:19:36 +00001342/* ia64 does not return the input arguments from functions (and syscalls)
1343 according to ia64 RSE (Register Stack Engine) behavior. */
1344
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001345# define restore_arg0(tcp, state, val) ((void) (state), 0)
1346# define restore_arg1(tcp, state, val) ((void) (state), 0)
Roland McGrathb659f872008-07-18 01:19:36 +00001347
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001348# elif defined (SPARC) || defined (SPARC64)
Roland McGrathd81f1d92003-01-09 06:53:34 +00001349
Mike Frysinger8566c502009-10-12 11:05:14 -04001350typedef struct pt_regs arg_setup_state;
Roland McGrathd81f1d92003-01-09 06:53:34 +00001351
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001352# define arg_setup(tcp, state) \
Roland McGratheb9e2e82009-06-02 16:49:22 -07001353 (ptrace (PTRACE_GETREGS, tcp->pid, (char *) (state), 0))
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001354# define arg_finish_change(tcp, state) \
Roland McGratheb9e2e82009-06-02 16:49:22 -07001355 (ptrace (PTRACE_SETREGS, tcp->pid, (char *) (state), 0))
Roland McGrathd81f1d92003-01-09 06:53:34 +00001356
Mike Frysinger8566c502009-10-12 11:05:14 -04001357# define get_arg0(tcp, state, valp) (*(valp) = (state)->u_regs[U_REG_O0], 0)
1358# define get_arg1(tcp, state, valp) (*(valp) = (state)->u_regs[U_REG_O1], 0)
1359# define set_arg0(tcp, state, val) ((state)->u_regs[U_REG_O0] = (val), 0)
1360# define set_arg1(tcp, state, val) ((state)->u_regs[U_REG_O1] = (val), 0)
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001361# define restore_arg0(tcp, state, val) 0
Roland McGrathd81f1d92003-01-09 06:53:34 +00001362
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001363# else /* other architectures */
Roland McGrathd81f1d92003-01-09 06:53:34 +00001364
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001365# if defined S390 || defined S390X
Roland McGrath7b308222003-01-20 09:04:36 +00001366/* Note: this is only true for the `clone' system call, which handles
1367 arguments specially. We could as well say that its first two arguments
1368 are swapped relative to other architectures, but that would just be
1369 another #ifdef in the calls. */
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001370# define arg0_offset PT_GPR3
1371# define arg1_offset PT_ORIGGPR2
1372# define restore_arg0(tcp, state, val) ((void) (state), 0)
1373# define restore_arg1(tcp, state, val) ((void) (state), 0)
1374# define arg0_index 1
1375# define arg1_index 0
1376# elif defined (ALPHA) || defined (MIPS)
1377# define arg0_offset REG_A0
1378# define arg1_offset (REG_A0+1)
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00001379# elif defined (AVR32)
1380# define arg0_offset (REG_R12)
1381# define arg1_offset (REG_R11)
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001382# elif defined (POWERPC)
1383# define arg0_offset (sizeof(unsigned long)*PT_R3)
1384# define arg1_offset (sizeof(unsigned long)*PT_R4)
1385# define restore_arg0(tcp, state, val) ((void) (state), 0)
1386# elif defined (HPPA)
1387# define arg0_offset PT_GR26
1388# define arg1_offset (PT_GR26-4)
1389# elif defined (X86_64)
1390# define arg0_offset ((long)(8*(current_personality ? RBX : RDI)))
1391# define arg1_offset ((long)(8*(current_personality ? RCX : RSI)))
1392# elif defined (SH)
1393# define arg0_offset (4*(REG_REG0+4))
1394# define arg1_offset (4*(REG_REG0+5))
1395# elif defined (SH64)
1396 /* ABI defines arg0 & 1 in r2 & r3 */
1397# define arg0_offset (REG_OFFSET+16)
1398# define arg1_offset (REG_OFFSET+24)
1399# define restore_arg0(tcp, state, val) 0
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001400# elif defined CRISV10 || defined CRISV32
1401# define arg0_offset (4*PT_R11)
1402# define arg1_offset (4*PT_ORIG_R10)
1403# define restore_arg0(tcp, state, val) 0
1404# define restore_arg1(tcp, state, val) 0
1405# define arg0_index 1
1406# define arg1_index 0
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001407# else
1408# define arg0_offset 0
1409# define arg1_offset 4
1410# if defined ARM
1411# define restore_arg0(tcp, state, val) 0
1412# endif
1413# endif
Roland McGrathd81f1d92003-01-09 06:53:34 +00001414
1415typedef int arg_setup_state;
1416
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001417# define arg_setup(tcp, state) (0)
1418# define arg_finish_change(tcp, state) 0
1419# define get_arg0(tcp, cookie, valp) \
1420 (upeek ((tcp), arg0_offset, (valp)))
1421# define get_arg1(tcp, cookie, valp) \
1422 (upeek ((tcp), arg1_offset, (valp)))
Roland McGrathd81f1d92003-01-09 06:53:34 +00001423
1424static int
Denys Vlasenko12014262011-05-30 14:00:14 +02001425set_arg0(struct tcb *tcp, void *cookie, long val)
Roland McGrathd81f1d92003-01-09 06:53:34 +00001426{
Roland McGratheb9e2e82009-06-02 16:49:22 -07001427 return ptrace (PTRACE_POKEUSER, tcp->pid, (char*)arg0_offset, val);
Roland McGrathd81f1d92003-01-09 06:53:34 +00001428}
1429
1430static int
Denys Vlasenko12014262011-05-30 14:00:14 +02001431set_arg1(struct tcb *tcp, void *cookie, long val)
Roland McGrathd81f1d92003-01-09 06:53:34 +00001432{
Roland McGratheb9e2e82009-06-02 16:49:22 -07001433 return ptrace (PTRACE_POKEUSER, tcp->pid, (char*)arg1_offset, val);
Roland McGrathd81f1d92003-01-09 06:53:34 +00001434}
1435
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001436# endif /* architectures */
Roland McGrathd81f1d92003-01-09 06:53:34 +00001437
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001438# ifndef restore_arg0
1439# define restore_arg0(tcp, state, val) set_arg0((tcp), (state), (val))
1440# endif
1441# ifndef restore_arg1
1442# define restore_arg1(tcp, state, val) set_arg1((tcp), (state), (val))
1443# endif
Roland McGrathd81f1d92003-01-09 06:53:34 +00001444
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001445# ifndef arg0_index
1446# define arg0_index 0
1447# define arg1_index 1
1448# endif
Roland McGrath90d0afd2004-03-01 21:05:16 +00001449
Roland McGrathd81f1d92003-01-09 06:53:34 +00001450int
Denys Vlasenko418d66a2009-01-17 01:52:54 +00001451setbpt(struct tcb *tcp)
Roland McGrathd81f1d92003-01-09 06:53:34 +00001452{
Roland McGrath3291ef22008-05-20 00:34:34 +00001453 static int clone_scno[SUPPORTED_PERSONALITIES] = { SYS_clone };
Roland McGrathd81f1d92003-01-09 06:53:34 +00001454 arg_setup_state state;
1455
1456 if (tcp->flags & TCB_BPTSET) {
1457 fprintf(stderr, "PANIC: TCB already set in pid %u\n", tcp->pid);
1458 return -1;
1459 }
1460
Roland McGrath3291ef22008-05-20 00:34:34 +00001461 /*
1462 * It's a silly kludge to initialize this with a search at runtime.
1463 * But it's better than maintaining another magic thing in the
1464 * godforsaken tables.
1465 */
1466 if (clone_scno[current_personality] == 0) {
1467 int i;
1468 for (i = 0; i < nsyscalls; ++i)
1469 if (sysent[i].sys_func == sys_clone) {
1470 clone_scno[current_personality] = i;
1471 break;
1472 }
1473 }
1474
Roland McGrath76989d72005-06-07 23:21:31 +00001475 switch (known_scno(tcp)) {
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001476# ifdef SYS_vfork
Roland McGrath9383c6c2003-01-18 00:19:31 +00001477 case SYS_vfork:
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001478# endif
1479# ifdef SYS_fork
Roland McGrathd81f1d92003-01-09 06:53:34 +00001480 case SYS_fork:
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001481# endif
1482# if defined SYS_fork || defined SYS_vfork
Roland McGrathd81f1d92003-01-09 06:53:34 +00001483 if (arg_setup (tcp, &state) < 0
1484 || get_arg0 (tcp, &state, &tcp->inst[0]) < 0
1485 || get_arg1 (tcp, &state, &tcp->inst[1]) < 0
Roland McGrath3291ef22008-05-20 00:34:34 +00001486 || change_syscall(tcp, clone_scno[current_personality]) < 0
Roland McGrathd81f1d92003-01-09 06:53:34 +00001487 || set_arg0 (tcp, &state, CLONE_PTRACE|SIGCHLD) < 0
1488 || set_arg1 (tcp, &state, 0) < 0
1489 || arg_finish_change (tcp, &state) < 0)
1490 return -1;
Roland McGrathc9dc3c12004-03-01 20:57:09 +00001491 tcp->u_arg[arg0_index] = CLONE_PTRACE|SIGCHLD;
1492 tcp->u_arg[arg1_index] = 0;
Roland McGrathd81f1d92003-01-09 06:53:34 +00001493 tcp->flags |= TCB_BPTSET;
1494 return 0;
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001495# endif
Roland McGrathd81f1d92003-01-09 06:53:34 +00001496
1497 case SYS_clone:
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001498# ifdef SYS_clone2
Roland McGrathd81f1d92003-01-09 06:53:34 +00001499 case SYS_clone2:
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001500# endif
Jan Kratochvil8fc95752008-08-06 21:43:35 +00001501 /* ia64 calls directly `clone (CLONE_VFORK | CLONE_VM)'
1502 contrary to x86 SYS_vfork above. Even on x86 we turn the
1503 vfork semantics into plain fork - each application must not
1504 depend on the vfork specifics according to POSIX. We would
1505 hang waiting for the parent resume otherwise. We need to
1506 clear also CLONE_VM but only in the CLONE_VFORK case as
1507 otherwise we would break pthread_create. */
1508
Roland McGrathd6ff0d52008-07-18 01:09:44 +00001509 if ((arg_setup (tcp, &state) < 0
1510 || set_arg0 (tcp, &state,
1511 (tcp->u_arg[arg0_index] | CLONE_PTRACE)
Jan Kratochvil8fc95752008-08-06 21:43:35 +00001512 & ~(tcp->u_arg[arg0_index] & CLONE_VFORK
1513 ? CLONE_VFORK | CLONE_VM : 0)) < 0
Roland McGrathd6ff0d52008-07-18 01:09:44 +00001514 || arg_finish_change (tcp, &state) < 0))
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00001515 return -1;
Roland McGrathd81f1d92003-01-09 06:53:34 +00001516 tcp->flags |= TCB_BPTSET;
Roland McGrathc9dc3c12004-03-01 20:57:09 +00001517 tcp->inst[0] = tcp->u_arg[arg0_index];
1518 tcp->inst[1] = tcp->u_arg[arg1_index];
Roland McGrathd81f1d92003-01-09 06:53:34 +00001519 return 0;
1520
1521 default:
1522 fprintf(stderr, "PANIC: setbpt for syscall %ld on %u???\n",
1523 tcp->scno, tcp->pid);
1524 break;
1525 }
1526
1527 return -1;
1528}
1529
1530int
Denys Vlasenko12014262011-05-30 14:00:14 +02001531clearbpt(struct tcb *tcp)
Roland McGrathd81f1d92003-01-09 06:53:34 +00001532{
1533 arg_setup_state state;
1534 if (arg_setup (tcp, &state) < 0
Roland McGrathe1df47f2003-01-14 09:46:15 +00001535 || restore_arg0 (tcp, &state, tcp->inst[0]) < 0
1536 || restore_arg1 (tcp, &state, tcp->inst[1]) < 0
Roland McGrathd81f1d92003-01-09 06:53:34 +00001537 || arg_finish_change (tcp, &state))
Andreas Schwab46ed50d2009-11-11 13:54:04 +01001538 if (errno != ESRCH) return -1;
Roland McGrathd81f1d92003-01-09 06:53:34 +00001539 tcp->flags &= ~TCB_BPTSET;
1540 return 0;
1541}
1542
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001543# else /* !defined LINUX */
Roland McGrathd81f1d92003-01-09 06:53:34 +00001544
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001545int
Denys Vlasenko12014262011-05-30 14:00:14 +02001546setbpt(struct tcb *tcp)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001547{
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001548# ifdef SUNOS4
1549# ifdef SPARC /* This code is slightly sparc specific */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001550
Wichert Akkermane6f876c1999-06-22 15:28:30 +00001551 struct regs regs;
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001552# define BPT 0x91d02001 /* ta 1 */
1553# define LOOP 0x10800000 /* ba 0 */
1554# define LOOPA 0x30800000 /* ba,a 0 */
1555# define NOP 0x01000000
1556# if LOOPA
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001557 static int loopdeloop[1] = {LOOPA};
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001558# else
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001559 static int loopdeloop[2] = {LOOP, NOP};
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001560# endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001561
1562 if (tcp->flags & TCB_BPTSET) {
1563 fprintf(stderr, "PANIC: TCB already set in pid %u\n", tcp->pid);
1564 return -1;
1565 }
Roland McGratheb9e2e82009-06-02 16:49:22 -07001566 if (ptrace(PTRACE_GETREGS, tcp->pid, (char *)&regs, 0) < 0) {
1567 perror("setbpt: ptrace(PTRACE_GETREGS, ...)");
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001568 return -1;
1569 }
1570 tcp->baddr = regs.r_o7 + 8;
Roland McGratheb9e2e82009-06-02 16:49:22 -07001571 if (ptrace(PTRACE_READTEXT, tcp->pid, (char *)tcp->baddr,
1572 sizeof tcp->inst, (char *)tcp->inst) < 0) {
1573 perror("setbpt: ptrace(PTRACE_READTEXT, ...)");
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001574 return -1;
1575 }
1576
1577 /*
1578 * XXX - BRUTAL MODE ON
1579 * We cannot set a real BPT in the child, since it will not be
1580 * traced at the moment it will reach the trap and would probably
1581 * die with a core dump.
1582 * Thus, we are force our way in by taking out two instructions
1583 * and insert an eternal loop in stead, in expectance of the SIGSTOP
1584 * generated by out PTRACE_ATTACH.
1585 * Of cause, if we evaporate ourselves in the middle of all this...
1586 */
Roland McGratheb9e2e82009-06-02 16:49:22 -07001587 if (ptrace(PTRACE_WRITETEXT, tcp->pid, (char *) tcp->baddr,
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001588 sizeof loopdeloop, (char *) loopdeloop) < 0) {
Roland McGratheb9e2e82009-06-02 16:49:22 -07001589 perror("setbpt: ptrace(PTRACE_WRITETEXT, ...)");
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001590 return -1;
1591 }
1592 tcp->flags |= TCB_BPTSET;
1593
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001594# endif /* SPARC */
1595# endif /* SUNOS4 */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001596
1597 return 0;
1598}
1599
1600int
Denys Vlasenko12014262011-05-30 14:00:14 +02001601clearbpt(struct tcb *tcp)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001602{
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001603# ifdef SUNOS4
1604# ifdef SPARC
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001605
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001606# if !LOOPA
Wichert Akkermane6f876c1999-06-22 15:28:30 +00001607 struct regs regs;
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001608# endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001609
1610 if (!(tcp->flags & TCB_BPTSET)) {
1611 fprintf(stderr, "PANIC: TCB not set in pid %u\n", tcp->pid);
1612 return -1;
1613 }
Roland McGratheb9e2e82009-06-02 16:49:22 -07001614 if (ptrace(PTRACE_WRITETEXT, tcp->pid, (char *) tcp->baddr,
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001615 sizeof tcp->inst, (char *) tcp->inst) < 0) {
Roland McGratheb9e2e82009-06-02 16:49:22 -07001616 perror("clearbtp: ptrace(PTRACE_WRITETEXT, ...)");
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001617 return -1;
1618 }
1619 tcp->flags &= ~TCB_BPTSET;
1620
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001621# if !LOOPA
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001622 /*
1623 * Since we don't have a single instruction breakpoint, we may have
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001624 * to adjust the program counter after removing our `breakpoint'.
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001625 */
Roland McGratheb9e2e82009-06-02 16:49:22 -07001626 if (ptrace(PTRACE_GETREGS, tcp->pid, (char *)&regs, 0) < 0) {
1627 perror("clearbpt: ptrace(PTRACE_GETREGS, ...)");
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001628 return -1;
1629 }
Roland McGratheb9e2e82009-06-02 16:49:22 -07001630 if ((regs.r_pc < tcp->baddr) ||
1631 (regs.r_pc > tcp->baddr + 4)) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001632 /* The breakpoint has not been reached yet */
1633 if (debug)
1634 fprintf(stderr,
1635 "NOTE: PC not at bpt (pc %#x baddr %#x)\n",
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001636 regs.r_pc, tcp->baddr);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001637 return 0;
1638 }
1639 if (regs.r_pc != tcp->baddr)
1640 if (debug)
1641 fprintf(stderr, "NOTE: PC adjusted (%#x -> %#x\n",
1642 regs.r_pc, tcp->baddr);
1643
1644 regs.r_pc = tcp->baddr;
Roland McGratheb9e2e82009-06-02 16:49:22 -07001645 if (ptrace(PTRACE_SETREGS, tcp->pid, (char *)&regs, 0) < 0) {
1646 perror("clearbpt: ptrace(PTRACE_SETREGS, ...)");
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001647 return -1;
1648 }
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001649# endif /* LOOPA */
1650# endif /* SPARC */
1651# endif /* SUNOS4 */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001652
1653 return 0;
1654}
1655
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001656# endif /* !defined LINUX */
Roland McGrathd81f1d92003-01-09 06:53:34 +00001657
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001658#endif /* !USE_PROCFS */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001659
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001660
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001661#ifdef SUNOS4
1662
1663static int
Denys Vlasenko12014262011-05-30 14:00:14 +02001664getex(struct tcb *tcp, struct exec *hdr)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001665{
1666 int n;
1667
1668 for (n = 0; n < sizeof *hdr; n += 4) {
1669 long res;
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001670 if (upeek(tcp, uoff(u_exdata) + n, &res) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001671 return -1;
1672 memcpy(((char *) hdr) + n, &res, 4);
1673 }
1674 if (debug) {
1675 fprintf(stderr, "[struct exec: magic: %o version %u Mach %o\n",
1676 hdr->a_magic, hdr->a_toolversion, hdr->a_machtype);
1677 fprintf(stderr, "Text %lu Data %lu Bss %lu Syms %lu Entry %#lx]\n",
1678 hdr->a_text, hdr->a_data, hdr->a_bss, hdr->a_syms, hdr->a_entry);
1679 }
1680 return 0;
1681}
1682
1683int
Denys Vlasenko12014262011-05-30 14:00:14 +02001684fixvfork(struct tcb *tcp)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001685{
1686 int pid = tcp->pid;
1687 /*
1688 * Change `vfork' in a freshly exec'ed dynamically linked
1689 * executable's (internal) symbol table to plain old `fork'
1690 */
1691
1692 struct exec hdr;
1693 struct link_dynamic dyn;
1694 struct link_dynamic_2 ld;
1695 char *strtab, *cp;
1696
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001697 if (getex(tcp, &hdr) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001698 return -1;
1699 if (!hdr.a_dynamic)
1700 return -1;
1701
1702 if (umove(tcp, (int) N_DATADDR(hdr), &dyn) < 0) {
1703 fprintf(stderr, "Cannot read DYNAMIC\n");
1704 return -1;
1705 }
1706 if (umove(tcp, (int) dyn.ld_un.ld_2, &ld) < 0) {
1707 fprintf(stderr, "Cannot read link_dynamic_2\n");
1708 return -1;
1709 }
1710 if ((strtab = malloc((unsigned)ld.ld_symb_size)) == NULL) {
Roland McGrath46100d02005-06-01 18:55:42 +00001711 fprintf(stderr, "out of memory\n");
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001712 return -1;
1713 }
Roland McGratheb9e2e82009-06-02 16:49:22 -07001714 if (umoven(tcp, (int)ld.ld_symbols+(int)N_TXTADDR(hdr),
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001715 (int)ld.ld_symb_size, strtab) < 0)
1716 goto err;
1717
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001718 for (cp = strtab; cp < strtab + ld.ld_symb_size; ) {
1719 if (strcmp(cp, "_vfork") == 0) {
1720 if (debug)
1721 fprintf(stderr, "fixvfork: FOUND _vfork\n");
1722 strcpy(cp, "_fork");
1723 break;
1724 }
1725 cp += strlen(cp)+1;
1726 }
1727 if (cp < strtab + ld.ld_symb_size)
1728 /*
1729 * Write entire symbol table back to avoid
1730 * memory alignment bugs in ptrace
1731 */
Roland McGratheb9e2e82009-06-02 16:49:22 -07001732 if (tload(pid, (int)ld.ld_symbols+(int)N_TXTADDR(hdr),
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001733 (int)ld.ld_symb_size, strtab) < 0)
1734 goto err;
1735
1736 free(strtab);
1737 return 0;
1738
1739err:
1740 free(strtab);
1741 return -1;
1742}
1743
1744#endif /* SUNOS4 */