blob: 75a449dc8c78406039ae24d2ee9b213d1326c791 [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
Denys Vlasenko52845572011-08-31 12:07:38 +0200167char *
168stpcpy(char *dst, const char *src)
169{
170 while ((*dst = *src++) != '\0')
171 dst++;
172 return dst;
173}
174
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000175/*
Roland McGratheb9e2e82009-06-02 16:49:22 -0700176 * Generic ptrace wrapper which tracks ESRCH errors
177 * by setting tcp->ptrace_errno to ESRCH.
Denys Vlasenko732d1bf2008-12-17 19:21:59 +0000178 *
179 * We assume that ESRCH indicates likely process death (SIGKILL?),
180 * modulo bugs where process somehow ended up not stopped.
181 * Unfortunately kernel uses ESRCH for that case too. Oh well.
Roland McGratheb9e2e82009-06-02 16:49:22 -0700182 *
183 * Currently used by upeek() only.
184 * TODO: use this in all other ptrace() calls while decoding.
Denys Vlasenko732d1bf2008-12-17 19:21:59 +0000185 */
Denys Vlasenko4dedd562009-02-24 15:17:53 +0000186long
Roland McGratheb9e2e82009-06-02 16:49:22 -0700187do_ptrace(int request, struct tcb *tcp, void *addr, void *data)
Denys Vlasenko4dedd562009-02-24 15:17:53 +0000188{
Denys Vlasenko732d1bf2008-12-17 19:21:59 +0000189 long l;
190
191 errno = 0;
Mike Frysinger09a13c22009-10-07 01:13:39 -0400192 l = ptrace(request, tcp->pid, addr, (long) data);
Roland McGratheb9e2e82009-06-02 16:49:22 -0700193 /* Non-ESRCH errors might be our invalid reg/mem accesses,
194 * we do not record them. */
195 if (errno == ESRCH)
196 tcp->ptrace_errno = ESRCH;
Denys Vlasenko732d1bf2008-12-17 19:21:59 +0000197 return l;
198}
199
200/*
201 * Used when we want to unblock stopped traced process.
202 * Should be only used with PTRACE_CONT, PTRACE_DETACH and PTRACE_SYSCALL.
203 * Returns 0 on success or if error was ESRCH
204 * (presumably process was killed while we talk to it).
205 * Otherwise prints error message and returns -1.
206 */
207int
Roland McGratheb9e2e82009-06-02 16:49:22 -0700208ptrace_restart(int op, struct tcb *tcp, int sig)
Denys Vlasenko732d1bf2008-12-17 19:21:59 +0000209{
210 int err;
Roland McGratheb9e2e82009-06-02 16:49:22 -0700211 const char *msg;
Denys Vlasenko732d1bf2008-12-17 19:21:59 +0000212
213 errno = 0;
Mike Frysinger09a13c22009-10-07 01:13:39 -0400214 ptrace(op, tcp->pid, (void *) 1, (long) sig);
Denys Vlasenko732d1bf2008-12-17 19:21:59 +0000215 err = errno;
216 if (!err || err == ESRCH)
217 return 0;
218
219 tcp->ptrace_errno = err;
Roland McGratheb9e2e82009-06-02 16:49:22 -0700220 msg = "SYSCALL";
221 if (op == PTRACE_CONT)
222 msg = "CONT";
223 if (op == PTRACE_DETACH)
224 msg = "DETACH";
225 fprintf(stderr, "strace: ptrace(PTRACE_%s,1,%d): %s\n",
226 msg, sig, strerror(err));
Denys Vlasenko732d1bf2008-12-17 19:21:59 +0000227 return -1;
228}
229
230/*
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000231 * Print entry in struct xlat table, if there.
232 */
233void
Dmitry V. Levinab9008b2007-01-11 22:05:04 +0000234printxval(const struct xlat *xlat, int val, const char *dflt)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000235{
Dmitry V. Levinab9008b2007-01-11 22:05:04 +0000236 const char *str = xlookup(xlat, val);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000237
238 if (str)
239 tprintf("%s", str);
240 else
241 tprintf("%#x /* %s */", val, dflt);
242}
243
Andreas Schwabb5600fc2009-11-04 17:08:34 +0100244#if HAVE_LONG_LONG
245/*
246 * Print 64bit argument at position llarg and return the index of the next
247 * argument.
248 */
249int
250printllval(struct tcb *tcp, const char *format, int llarg)
251{
252# if defined(FREEBSD) \
Andreas Schwabd69fa492010-07-12 21:39:57 +0200253 || (defined(LINUX) && defined(POWERPC) && !defined(POWERPC64)) \
Dmitry V. Levin7a5b08f2011-05-28 20:47:43 +0000254 || defined(LINUX_MIPSO32) \
255 || defined(__ARM_EABI__)
Andreas Schwabb5600fc2009-11-04 17:08:34 +0100256 /* Align 64bit argument to 64bit boundary. */
Denys Vlasenko4b08df42011-08-19 15:58:24 +0200257 llarg = (llarg + 1) & 0x1e;
Andreas Schwabb5600fc2009-11-04 17:08:34 +0100258# endif
Andreas Schwabd69fa492010-07-12 21:39:57 +0200259# if defined LINUX && (defined X86_64 || defined POWERPC64)
Andreas Schwabb5600fc2009-11-04 17:08:34 +0100260 if (current_personality == 0) {
261 tprintf(format, tcp->u_arg[llarg]);
262 llarg++;
263 } else {
Andreas Schwabd69fa492010-07-12 21:39:57 +0200264# ifdef POWERPC64
265 /* Align 64bit argument to 64bit boundary. */
Denys Vlasenko4b08df42011-08-19 15:58:24 +0200266 llarg = (llarg + 1) & 0x1e;
Andreas Schwabd69fa492010-07-12 21:39:57 +0200267# endif
Andreas Schwabb5600fc2009-11-04 17:08:34 +0100268 tprintf(format, LONG_LONG(tcp->u_arg[llarg], tcp->u_arg[llarg + 1]));
269 llarg += 2;
270 }
Andreas Schwabd69fa492010-07-12 21:39:57 +0200271# elif defined IA64 || defined ALPHA
Andreas Schwabb5600fc2009-11-04 17:08:34 +0100272 tprintf(format, tcp->u_arg[llarg]);
273 llarg++;
274# elif defined LINUX_MIPSN32
275 tprintf(format, tcp->ext_arg[llarg]);
276 llarg++;
277# else
278 tprintf(format, LONG_LONG(tcp->u_arg[llarg], tcp->u_arg[llarg + 1]));
279 llarg += 2;
280# endif
281 return llarg;
282}
283#endif
284
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000285/*
286 * Interpret `xlat' as an array of flags
287 * print the entries whose bits are on in `flags'
288 * return # of flags printed.
289 */
Denys Vlasenko4924dbd2011-08-19 18:06:46 +0200290void
Denys Vlasenko12014262011-05-30 14:00:14 +0200291addflags(const struct xlat *xlat, int flags)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000292{
Denys Vlasenko4924dbd2011-08-19 18:06:46 +0200293 for (; xlat->str; xlat++) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000294 if (xlat->val && (flags & xlat->val) == xlat->val) {
295 tprintf("|%s", xlat->str);
296 flags &= ~xlat->val;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000297 }
298 }
299 if (flags) {
300 tprintf("|%#x", flags);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000301 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000302}
303
Roland McGratha6c0d8c2007-11-01 21:46:22 +0000304/*
Denys Vlasenko4924dbd2011-08-19 18:06:46 +0200305 * Interpret `xlat' as an array of flags.
Roland McGratha6c0d8c2007-11-01 21:46:22 +0000306 * Print to static string the entries whose bits are on in `flags'
307 * Return static string.
308 */
309const char *
310sprintflags(const char *prefix, const struct xlat *xlat, int flags)
311{
312 static char outstr[1024];
Denys Vlasenko52845572011-08-31 12:07:38 +0200313 char *outptr;
Roland McGratha6c0d8c2007-11-01 21:46:22 +0000314 int found = 0;
315
Denys Vlasenko52845572011-08-31 12:07:38 +0200316 outptr = stpcpy(outstr, prefix);
Roland McGratha6c0d8c2007-11-01 21:46:22 +0000317
318 for (; xlat->str; xlat++) {
319 if ((flags & xlat->val) == xlat->val) {
320 if (found)
Denys Vlasenko52845572011-08-31 12:07:38 +0200321 *outptr++ = '|';
322 outptr = stpcpy(outptr, xlat->str);
Roland McGratha6c0d8c2007-11-01 21:46:22 +0000323 flags &= ~xlat->val;
324 found = 1;
325 }
326 }
327 if (flags) {
328 if (found)
Denys Vlasenko52845572011-08-31 12:07:38 +0200329 *outptr++ = '|';
330 outptr += sprintf(outptr, "%#x", flags);
Roland McGratha6c0d8c2007-11-01 21:46:22 +0000331 }
332
333 return outstr;
334}
335
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000336int
Dmitry V. Levin30145dd2010-09-06 22:08:24 +0000337printflags(const struct xlat *xlat, int flags, const char *dflt)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000338{
339 int n;
Dmitry V. Levin30145dd2010-09-06 22:08:24 +0000340 const char *sep;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000341
342 if (flags == 0 && xlat->val == 0) {
343 tprintf("%s", xlat->str);
344 return 1;
345 }
346
347 sep = "";
348 for (n = 0; xlat->str; xlat++) {
349 if (xlat->val && (flags & xlat->val) == xlat->val) {
350 tprintf("%s%s", sep, xlat->str);
351 flags &= ~xlat->val;
352 sep = "|";
353 n++;
354 }
355 }
Roland McGrathb2dee132005-06-01 19:02:36 +0000356
357 if (n) {
358 if (flags) {
359 tprintf("%s%#x", sep, flags);
360 n++;
361 }
362 } else {
363 if (flags) {
364 tprintf("%#x", flags);
365 if (dflt)
366 tprintf(" /* %s */", dflt);
367 } else {
368 if (dflt)
369 tprintf("0");
370 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000371 }
Roland McGrathb2dee132005-06-01 19:02:36 +0000372
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000373 return n;
374}
375
376void
Dmitry V. Levin30145dd2010-09-06 22:08:24 +0000377printnum(struct tcb *tcp, long addr, const char *fmt)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000378{
Roland McGratheb285352003-01-14 09:59:00 +0000379 long num;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000380
381 if (!addr) {
382 tprintf("NULL");
383 return;
384 }
385 if (umove(tcp, addr, &num) < 0) {
386 tprintf("%#lx", addr);
387 return;
388 }
389 tprintf("[");
390 tprintf(fmt, num);
391 tprintf("]");
392}
393
Roland McGrath6bc12202003-11-13 22:32:27 +0000394void
Dmitry V. Levin30145dd2010-09-06 22:08:24 +0000395printnum_int(struct tcb *tcp, long addr, const char *fmt)
Roland McGrath9814a942005-07-04 23:28:10 +0000396{
397 int num;
398
399 if (!addr) {
400 tprintf("NULL");
401 return;
402 }
403 if (umove(tcp, addr, &num) < 0) {
404 tprintf("%#lx", addr);
405 return;
406 }
407 tprintf("[");
408 tprintf(fmt, num);
409 tprintf("]");
410}
411
412void
Dmitry V. Levin31382132011-03-04 05:08:02 +0300413printfd(struct tcb *tcp, int fd)
414{
Grant Edwards8a082772011-04-07 20:25:40 +0000415 const char *p;
416
417 if (show_fd_path && (p = getfdpath(tcp, fd)))
418 tprintf("%d<%s>", fd, p);
419 else
420 tprintf("%d", fd);
Dmitry V. Levin31382132011-03-04 05:08:02 +0300421}
422
423void
Denys Vlasenko12014262011-05-30 14:00:14 +0200424printuid(const char *text, unsigned long uid)
Roland McGrath6bc12202003-11-13 22:32:27 +0000425{
426 tprintf("%s", text);
427 tprintf((uid == -1) ? "%ld" : "%lu", uid);
428}
429
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000430static char path[MAXPATHLEN + 1];
431
Dmitry V. Levina501f142008-11-10 23:19:13 +0000432/*
433 * Quote string `instr' of length `size'
434 * Write up to (3 + `size' * 4) bytes to `outstr' buffer.
435 * If `len' < 0, treat `instr' as a NUL-terminated string
436 * and quote at most (`size' - 1) bytes.
437 */
Roland McGrath6d970322007-11-01 23:53:59 +0000438static int
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000439string_quote(const char *instr, char *outstr, int len, int size)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000440{
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000441 const unsigned char *ustr = (const unsigned char *) instr;
442 char *s = outstr;
Denys Vlasenko8778bff2011-08-31 12:22:56 +0200443 int usehex, c, i, eol;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000444
Denys Vlasenko8778bff2011-08-31 12:22:56 +0200445 eol = 0x100; /* this can never match a char */
446 if (len < 0) {
447 size--;
448 eol = '\0';
449 }
450
451 usehex = 0;
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000452 if (xflag > 1)
453 usehex = 1;
454 else if (xflag) {
Dmitry V. Levina501f142008-11-10 23:19:13 +0000455 /* Check for presence of symbol which require
456 to hex-quote the whole string. */
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000457 for (i = 0; i < size; ++i) {
458 c = ustr[i];
Dmitry V. Levina501f142008-11-10 23:19:13 +0000459 /* Check for NUL-terminated string. */
Denys Vlasenko8778bff2011-08-31 12:22:56 +0200460 if (c == eol)
461 break;
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. */
Denys Vlasenko8778bff2011-08-31 12:22:56 +0200476 if (c == eol)
477 goto asciz_ended;
478 *s++ = '\\';
479 *s++ = 'x';
480 *s++ = "0123456789abcdef"[c >> 4];
481 *s++ = "0123456789abcdef"[c & 0xf];
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000482 }
483 } else {
484 for (i = 0; i < size; ++i) {
485 c = ustr[i];
Dmitry V. Levina501f142008-11-10 23:19:13 +0000486 /* Check for NUL-terminated string. */
Denys Vlasenko8778bff2011-08-31 12:22:56 +0200487 if (c == eol)
488 goto asciz_ended;
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000489 switch (c) {
490 case '\"': case '\\':
491 *s++ = '\\';
492 *s++ = c;
493 break;
494 case '\f':
495 *s++ = '\\';
496 *s++ = 'f';
497 break;
498 case '\n':
499 *s++ = '\\';
500 *s++ = 'n';
501 break;
502 case '\r':
503 *s++ = '\\';
504 *s++ = 'r';
505 break;
506 case '\t':
507 *s++ = '\\';
508 *s++ = 't';
509 break;
510 case '\v':
511 *s++ = '\\';
512 *s++ = 'v';
513 break;
514 default:
515 if (isprint(c))
516 *s++ = c;
Denys Vlasenko8778bff2011-08-31 12:22:56 +0200517 else {
518 /* Print \octal */
519 *s++ = '\\';
520 if (i + 1 < size
521 && ustr[i + 1] >= '0'
522 && ustr[i + 1] <= '9'
523 ) {
524 /* Print \ooo */
525 *s++ = '0' + (c >> 6);
526 *s++ = '0' + ((c >> 3) & 0x7);
527 } else {
528 /* Print \[[o]o]o */
529 if ((c >> 3) != 0) {
530 if ((c >> 6) != 0)
531 *s++ = '0' + (c >> 6);
532 *s++ = '0' + ((c >> 3) & 0x7);
533 }
534 }
535 *s++ = '0' + (c & 0x7);
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000536 }
537 break;
538 }
539 }
540 }
541
542 *s++ = '\"';
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000543 *s = '\0';
Roland McGrath6d970322007-11-01 23:53:59 +0000544
Denys Vlasenko8778bff2011-08-31 12:22:56 +0200545 /* Return zero if we printed entire ASCIZ string (didn't truncate it) */
546 if (len < 0 && ustr[i] == '\0') {
547 /* We didn't see NUL yet (otherwise we'd jump to 'asciz_ended')
548 * but next char is NUL.
549 */
550 return 0;
551 }
552
553 return 1;
554
555 asciz_ended:
556 *s++ = '\"';
557 *s = '\0';
558 /* Return zero: we printed entire ASCIZ string (didn't truncate it) */
559 return 0;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000560}
561
Dmitry V. Levina501f142008-11-10 23:19:13 +0000562/*
563 * Print path string specified by address `addr' and length `n'.
564 * If path length exceeds `n', append `...' to the output.
565 */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000566void
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000567printpathn(struct tcb *tcp, long addr, int n)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000568{
Dmitry V. Levina501f142008-11-10 23:19:13 +0000569 if (!addr) {
Roland McGrath371ed8f2005-02-06 01:55:07 +0000570 tprintf("NULL");
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000571 return;
572 }
573
Dmitry V. Levina501f142008-11-10 23:19:13 +0000574 /* Cap path length to the path buffer size,
575 and NUL-terminate the buffer. */
576 if (n > sizeof path - 1)
577 n = sizeof path - 1;
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000578 path[n] = '\0';
Dmitry V. Levina501f142008-11-10 23:19:13 +0000579
580 /* Fetch one byte more to find out whether path length > n. */
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000581 if (umovestr(tcp, addr, n + 1, path) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000582 tprintf("%#lx", addr);
583 else {
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000584 static char outstr[4*(sizeof path - 1) + sizeof "\"...\""];
Denys Vlasenko52845572011-08-31 12:07:38 +0200585 const char *fmt;
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000586 int trunc = (path[n] != '\0');
587
588 if (trunc)
589 path[n] = '\0';
Denys Vlasenko52845572011-08-31 12:07:38 +0200590 string_quote(path, outstr, -1, n + 1);
591 fmt = "%s";
Dmitry V. Levina501f142008-11-10 23:19:13 +0000592 if (trunc)
Denys Vlasenko52845572011-08-31 12:07:38 +0200593 fmt = "%s...";
594 tprintf(fmt, outstr);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000595 }
596}
597
598void
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000599printpath(struct tcb *tcp, long addr)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000600{
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000601 printpathn(tcp, addr, sizeof path - 1);
602}
603
Dmitry V. Levina501f142008-11-10 23:19:13 +0000604/*
605 * Print string specified by address `addr' and length `len'.
606 * If `len' < 0, treat the string as a NUL-terminated string.
607 * If string length exceeds `max_strlen', append `...' to the output.
608 */
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000609void
610printstr(struct tcb *tcp, long addr, int len)
611{
612 static char *str = NULL;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000613 static char *outstr;
Roland McGrath6d970322007-11-01 23:53:59 +0000614 int size;
Denys Vlasenko52845572011-08-31 12:07:38 +0200615 const char *fmt;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000616
617 if (!addr) {
618 tprintf("NULL");
619 return;
620 }
Dmitry V. Levina501f142008-11-10 23:19:13 +0000621 /* Allocate static buffers if they are not allocated yet. */
Denys Vlasenko1d46ba52011-08-31 14:00:02 +0200622 if (!str) {
Dmitry V. Levina501f142008-11-10 23:19:13 +0000623 str = malloc(max_strlen + 1);
Denys Vlasenko1d46ba52011-08-31 14:00:02 +0200624 if (!str)
625 die_out_of_memory();
626 }
627 if (!outstr) {
Dmitry V. Levina501f142008-11-10 23:19:13 +0000628 outstr = malloc(4 * max_strlen + sizeof "\"...\"");
Denys Vlasenko1d46ba52011-08-31 14:00:02 +0200629 if (!outstr)
630 die_out_of_memory();
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000631 }
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000632
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000633 if (len < 0) {
Dmitry V. Levina501f142008-11-10 23:19:13 +0000634 /*
635 * Treat as a NUL-terminated string: fetch one byte more
636 * because string_quote() quotes one byte less.
637 */
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000638 size = max_strlen + 1;
Dmitry V. Levina501f142008-11-10 23:19:13 +0000639 str[max_strlen] = '\0';
Denys Vlasenko52845572011-08-31 12:07:38 +0200640 /* FIXME! umovestr can overwrite the '\0' stored above??? */
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000641 if (umovestr(tcp, addr, size, str) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000642 tprintf("%#lx", addr);
643 return;
644 }
645 }
646 else {
Dmitry V. Levina501f142008-11-10 23:19:13 +0000647 size = MIN(len, max_strlen);
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000648 if (umoven(tcp, addr, size, str) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000649 tprintf("%#lx", addr);
650 return;
651 }
652 }
653
Denys Vlasenko52845572011-08-31 12:07:38 +0200654 fmt = "%s";
Dmitry V. Levina501f142008-11-10 23:19:13 +0000655 if (string_quote(str, outstr, len, size) &&
656 (len < 0 || len > max_strlen))
Denys Vlasenko52845572011-08-31 12:07:38 +0200657 fmt = "%s...";
Roland McGratha503dcf2007-08-02 02:06:26 +0000658
Denys Vlasenko52845572011-08-31 12:07:38 +0200659 tprintf(fmt, outstr);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000660}
661
John Hughes1d08dcf2001-07-10 13:48:44 +0000662#if HAVE_SYS_UIO_H
663void
Denys Vlasenko12014262011-05-30 14:00:14 +0200664dumpiov(struct tcb *tcp, int len, long addr)
John Hughes1d08dcf2001-07-10 13:48:44 +0000665{
Dmitry V. Levin4ebb4e32006-12-13 17:08:08 +0000666#if defined(LINUX) && SUPPORTED_PERSONALITIES > 1
667 union {
668 struct { u_int32_t base; u_int32_t len; } *iov32;
669 struct { u_int64_t base; u_int64_t len; } *iov64;
670 } iovu;
671#define iov iovu.iov64
672#define sizeof_iov \
673 (personality_wordsize[current_personality] == 4 \
674 ? sizeof(*iovu.iov32) : sizeof(*iovu.iov64))
675#define iov_iov_base(i) \
676 (personality_wordsize[current_personality] == 4 \
677 ? (u_int64_t) iovu.iov32[i].base : iovu.iov64[i].base)
678#define iov_iov_len(i) \
679 (personality_wordsize[current_personality] == 4 \
680 ? (u_int64_t) iovu.iov32[i].len : iovu.iov64[i].len)
681#else
John Hughes1d08dcf2001-07-10 13:48:44 +0000682 struct iovec *iov;
Dmitry V. Levin4ebb4e32006-12-13 17:08:08 +0000683#define sizeof_iov sizeof(*iov)
684#define iov_iov_base(i) iov[i].iov_base
685#define iov_iov_len(i) iov[i].iov_len
686#endif
John Hughes1d08dcf2001-07-10 13:48:44 +0000687 int i;
Roland McGrathaa524c82005-06-01 19:22:06 +0000688 unsigned long size;
John Hughes1d08dcf2001-07-10 13:48:44 +0000689
Dmitry V. Levin4ebb4e32006-12-13 17:08:08 +0000690 size = sizeof_iov * (unsigned long) len;
Denys Vlasenko1d46ba52011-08-31 14:00:02 +0200691 if (size / sizeof_iov != len /* overflow? */
Dmitry V. Levin4ebb4e32006-12-13 17:08:08 +0000692 || (iov = malloc(size)) == NULL) {
Denys Vlasenko1d46ba52011-08-31 14:00:02 +0200693 die_out_of_memory();
John Hughes1d08dcf2001-07-10 13:48:44 +0000694 }
Roland McGrathaa524c82005-06-01 19:22:06 +0000695 if (umoven(tcp, addr, size, (char *) iov) >= 0) {
John Hughes1d08dcf2001-07-10 13:48:44 +0000696 for (i = 0; i < len; i++) {
Denys Vlasenkoadedb512008-12-30 18:47:55 +0000697 /* include the buffer number to make it easy to
698 * match up the trace with the source */
699 tprintf(" * %lu bytes in buffer %d\n",
700 (unsigned long)iov_iov_len(i), i);
701 dumpstr(tcp, (long) iov_iov_base(i),
702 iov_iov_len(i));
703 }
John Hughes1d08dcf2001-07-10 13:48:44 +0000704 }
705 free((char *) iov);
Dmitry V. Levin4ebb4e32006-12-13 17:08:08 +0000706#undef sizeof_iov
707#undef iov_iov_base
708#undef iov_iov_len
709#undef iov
John Hughes1d08dcf2001-07-10 13:48:44 +0000710}
711#endif
712
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000713void
Denys Vlasenko12014262011-05-30 14:00:14 +0200714dumpstr(struct tcb *tcp, long addr, int len)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000715{
716 static int strsize = -1;
717 static unsigned char *str;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000718 char *s;
719 int i, j;
720
721 if (strsize < len) {
Denys Vlasenko5d645812011-08-20 12:48:18 +0200722 free(str);
723 str = malloc(len);
Denys Vlasenko1d46ba52011-08-31 14:00:02 +0200724 if (!str)
725 die_out_of_memory();
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000726 strsize = len;
727 }
728
729 if (umoven(tcp, addr, len, (char *) str) < 0)
730 return;
731
732 for (i = 0; i < len; i += 16) {
Denys Vlasenko1d46ba52011-08-31 14:00:02 +0200733 char outstr[80];
734
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000735 s = outstr;
736 sprintf(s, " | %05x ", i);
737 s += 9;
738 for (j = 0; j < 16; j++) {
739 if (j == 8)
740 *s++ = ' ';
741 if (i + j < len) {
742 sprintf(s, " %02x", str[i + j]);
743 s += 3;
744 }
745 else {
746 *s++ = ' '; *s++ = ' '; *s++ = ' ';
747 }
748 }
749 *s++ = ' '; *s++ = ' ';
750 for (j = 0; j < 16; j++) {
751 if (j == 8)
752 *s++ = ' ';
753 if (i + j < len) {
754 if (isprint(str[i + j]))
755 *s++ = str[i + j];
756 else
757 *s++ = '.';
758 }
759 else
760 *s++ = ' ';
761 }
762 tprintf("%s |\n", outstr);
763 }
764}
765
766#define PAGMASK (~(PAGSIZ - 1))
767/*
768 * move `len' bytes of data from process `pid'
769 * at address `addr' to our space at `laddr'
770 */
771int
Denys Vlasenkoef2fbf82009-01-06 21:45:06 +0000772umoven(struct tcb *tcp, long addr, int len, char *laddr)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000773{
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000774#ifdef LINUX
Roland McGratheb9e2e82009-06-02 16:49:22 -0700775 int pid = tcp->pid;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000776 int n, m;
Wichert Akkerman5daa0281999-03-15 19:49:42 +0000777 int started = 0;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000778 union {
779 long val;
780 char x[sizeof(long)];
781 } u;
782
783 if (addr & (sizeof(long) - 1)) {
784 /* addr not a multiple of sizeof(long) */
785 n = addr - (addr & -sizeof(long)); /* residue */
786 addr &= -sizeof(long); /* residue */
Roland McGratheb9e2e82009-06-02 16:49:22 -0700787 errno = 0;
788 u.val = ptrace(PTRACE_PEEKDATA, pid, (char *) addr, 0);
789 if (errno) {
790 if (started && (errno==EPERM || errno==EIO)) {
791 /* Ran into 'end of memory' - stupid "printpath" */
792 return 0;
793 }
794 /* But if not started, we had a bogus address. */
795 if (addr != 0 && errno != EIO && errno != ESRCH)
796 perror("ptrace: umoven");
797 return -1;
798 }
Wichert Akkerman5daa0281999-03-15 19:49:42 +0000799 started = 1;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000800 memcpy(laddr, &u.x[n], m = MIN(sizeof(long) - n, len));
801 addr += sizeof(long), laddr += m, len -= m;
802 }
803 while (len) {
Roland McGratheb9e2e82009-06-02 16:49:22 -0700804 errno = 0;
805 u.val = ptrace(PTRACE_PEEKDATA, pid, (char *) addr, 0);
806 if (errno) {
807 if (started && (errno==EPERM || errno==EIO)) {
808 /* Ran into 'end of memory' - stupid "printpath" */
809 return 0;
810 }
811 if (addr != 0 && errno != EIO && errno != ESRCH)
812 perror("ptrace: umoven");
813 return -1;
814 }
Wichert Akkerman5daa0281999-03-15 19:49:42 +0000815 started = 1;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000816 memcpy(laddr, u.x, m = MIN(sizeof(long), len));
817 addr += sizeof(long), laddr += m, len -= m;
818 }
819#endif /* LINUX */
820
821#ifdef SUNOS4
822 int pid = tcp->pid;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000823 int n;
824
825 while (len) {
826 n = MIN(len, PAGSIZ);
827 n = MIN(n, ((addr + PAGSIZ) & PAGMASK) - addr);
Roland McGratheb9e2e82009-06-02 16:49:22 -0700828 if (ptrace(PTRACE_READDATA, pid,
829 (char *) addr, len, laddr) < 0) {
830 if (errno != ESRCH) {
831 perror("umoven: ptrace(PTRACE_READDATA, ...)");
832 abort();
833 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000834 return -1;
835 }
836 len -= n;
837 addr += n;
838 laddr += n;
839 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000840#endif /* SUNOS4 */
841
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000842#ifdef USE_PROCFS
Wichert Akkermanea78f0f1999-11-29 15:34:02 +0000843#ifdef HAVE_MP_PROCFS
John Hughesaa09c6b2001-05-15 14:53:43 +0000844 int fd = tcp->pfd_as;
Wichert Akkerman9ce1a631999-08-29 23:15:07 +0000845#else
John Hughesaa09c6b2001-05-15 14:53:43 +0000846 int fd = tcp->pfd;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000847#endif
John Hughesaa09c6b2001-05-15 14:53:43 +0000848 lseek(fd, addr, SEEK_SET);
849 if (read(fd, laddr, len) == -1)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000850 return -1;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000851#endif /* USE_PROCFS */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000852
853 return 0;
854}
855
856/*
857 * like `umove' but make the additional effort of looking
858 * for a terminating zero byte.
859 */
860int
Denys Vlasenkoef2fbf82009-01-06 21:45:06 +0000861umovestr(struct tcb *tcp, long addr, int len, char *laddr)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000862{
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000863#ifdef USE_PROCFS
John Hughesaa09c6b2001-05-15 14:53:43 +0000864#ifdef HAVE_MP_PROCFS
865 int fd = tcp->pfd_as;
866#else
867 int fd = tcp->pfd;
868#endif
869 /* Some systems (e.g. FreeBSD) can be upset if we read off the
870 end of valid memory, avoid this by trying to read up
871 to page boundaries. But we don't know what a page is (and
872 getpagesize(2) (if it exists) doesn't necessarily return
873 hardware page size). Assume all pages >= 1024 (a-historical
874 I know) */
875
Denys Vlasenkob63256e2011-06-07 12:13:24 +0200876 int page = 1024; /* How to find this? */
John Hughesaa09c6b2001-05-15 14:53:43 +0000877 int move = page - (addr & (page - 1));
878 int left = len;
879
880 lseek(fd, addr, SEEK_SET);
881
882 while (left) {
Denys Vlasenko5d645812011-08-20 12:48:18 +0200883 if (move > left)
884 move = left;
885 move = read(fd, laddr, move);
886 if (move <= 0)
John Hughesaa09c6b2001-05-15 14:53:43 +0000887 return left != len ? 0 : -1;
Denys Vlasenko5d645812011-08-20 12:48:18 +0200888 if (memchr(laddr, 0, move))
889 break;
John Hughesaa09c6b2001-05-15 14:53:43 +0000890 left -= move;
891 laddr += move;
892 addr += move;
893 move = page;
894 }
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000895#else /* !USE_PROCFS */
Wichert Akkerman5daa0281999-03-15 19:49:42 +0000896 int started = 0;
Roland McGratheb9e2e82009-06-02 16:49:22 -0700897 int pid = tcp->pid;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000898 int i, n, m;
899 union {
900 long val;
901 char x[sizeof(long)];
902 } u;
903
904 if (addr & (sizeof(long) - 1)) {
905 /* addr not a multiple of sizeof(long) */
906 n = addr - (addr & -sizeof(long)); /* residue */
907 addr &= -sizeof(long); /* residue */
Roland McGratheb9e2e82009-06-02 16:49:22 -0700908 errno = 0;
909 u.val = ptrace(PTRACE_PEEKDATA, pid, (char *)addr, 0);
910 if (errno) {
911 if (started && (errno==EPERM || errno==EIO)) {
912 /* Ran into 'end of memory' - stupid "printpath" */
913 return 0;
914 }
915 if (addr != 0 && errno != EIO && errno != ESRCH)
916 perror("umovestr");
917 return -1;
918 }
Wichert Akkerman5daa0281999-03-15 19:49:42 +0000919 started = 1;
Denys Vlasenkob63256e2011-06-07 12:13:24 +0200920 memcpy(laddr, &u.x[n], m = MIN(sizeof(long)-n, len));
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000921 while (n & (sizeof(long) - 1))
922 if (u.x[n++] == '\0')
923 return 0;
924 addr += sizeof(long), laddr += m, len -= m;
925 }
926 while (len) {
Roland McGratheb9e2e82009-06-02 16:49:22 -0700927 errno = 0;
928 u.val = ptrace(PTRACE_PEEKDATA, pid, (char *)addr, 0);
929 if (errno) {
930 if (started && (errno==EPERM || errno==EIO)) {
931 /* Ran into 'end of memory' - stupid "printpath" */
932 return 0;
933 }
934 if (addr != 0 && errno != EIO && errno != ESRCH)
935 perror("umovestr");
936 return -1;
937 }
Wichert Akkerman5daa0281999-03-15 19:49:42 +0000938 started = 1;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000939 memcpy(laddr, u.x, m = MIN(sizeof(long), len));
940 for (i = 0; i < sizeof(long); i++)
941 if (u.x[i] == '\0')
942 return 0;
943
944 addr += sizeof(long), laddr += m, len -= m;
945 }
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000946#endif /* !USE_PROCFS */
John Hughesaa09c6b2001-05-15 14:53:43 +0000947 return 0;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000948}
949
950#ifdef LINUX
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +0000951# if !defined (SPARC) && !defined(SPARC64)
952# define PTRACE_WRITETEXT 101
953# define PTRACE_WRITEDATA 102
954# endif /* !SPARC && !SPARC64 */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000955#endif /* LINUX */
956
957#ifdef SUNOS4
958
959static int
Denys Vlasenko12014262011-05-30 14:00:14 +0200960uload(int cmd, int pid, long addr, int len, char *laddr)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000961{
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000962 int peek, poke;
963 int n, m;
964 union {
965 long val;
966 char x[sizeof(long)];
967 } u;
968
969 if (cmd == PTRACE_WRITETEXT) {
970 peek = PTRACE_PEEKTEXT;
971 poke = PTRACE_POKETEXT;
972 }
973 else {
974 peek = PTRACE_PEEKDATA;
975 poke = PTRACE_POKEDATA;
976 }
977 if (addr & (sizeof(long) - 1)) {
978 /* addr not a multiple of sizeof(long) */
979 n = addr - (addr & -sizeof(long)); /* residue */
980 addr &= -sizeof(long);
Roland McGratheb9e2e82009-06-02 16:49:22 -0700981 errno = 0;
982 u.val = ptrace(peek, pid, (char *) addr, 0);
983 if (errno) {
984 perror("uload: POKE");
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000985 return -1;
986 }
Roland McGratheb9e2e82009-06-02 16:49:22 -0700987 memcpy(&u.x[n], laddr, m = MIN(sizeof(long) - n, len));
988 if (ptrace(poke, pid, (char *)addr, u.val) < 0) {
989 perror("uload: POKE");
990 return -1;
991 }
992 addr += sizeof(long), laddr += m, len -= m;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000993 }
994 while (len) {
995 if (len < sizeof(long))
Roland McGratheb9e2e82009-06-02 16:49:22 -0700996 u.val = ptrace(peek, pid, (char *) addr, 0);
997 memcpy(u.x, laddr, m = MIN(sizeof(long), len));
998 if (ptrace(poke, pid, (char *) addr, u.val) < 0) {
999 perror("uload: POKE");
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001000 return -1;
1001 }
Roland McGratheb9e2e82009-06-02 16:49:22 -07001002 addr += sizeof(long), laddr += m, len -= m;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001003 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001004 return 0;
1005}
1006
Roland McGratheb9e2e82009-06-02 16:49:22 -07001007int
Denys Vlasenko12014262011-05-30 14:00:14 +02001008tload(int pid, int addr, int len, char *laddr)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001009{
Roland McGratheb9e2e82009-06-02 16:49:22 -07001010 return uload(PTRACE_WRITETEXT, pid, addr, len, laddr);
1011}
1012
1013int
Denys Vlasenko12014262011-05-30 14:00:14 +02001014dload(int pid, int addr, int len, char *laddr)
Roland McGratheb9e2e82009-06-02 16:49:22 -07001015{
1016 return uload(PTRACE_WRITEDATA, pid, addr, len, laddr);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001017}
1018
1019#endif /* SUNOS4 */
1020
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001021#ifndef USE_PROCFS
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001022
1023int
Denys Vlasenko12014262011-05-30 14:00:14 +02001024upeek(struct tcb *tcp, long off, long *res)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001025{
1026 long val;
1027
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001028# ifdef SUNOS4_KERNEL_ARCH_KLUDGE
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001029 {
1030 static int is_sun4m = -1;
1031 struct utsname name;
1032
1033 /* Round up the usual suspects. */
1034 if (is_sun4m == -1) {
1035 if (uname(&name) < 0) {
1036 perror("upeek: uname?");
1037 exit(1);
1038 }
1039 is_sun4m = strcmp(name.machine, "sun4m") == 0;
1040 if (is_sun4m) {
Roland McGrathd9f816f2004-09-04 03:39:20 +00001041 const struct xlat *x;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001042
1043 for (x = struct_user_offsets; x->str; x++)
1044 x->val += 1024;
1045 }
1046 }
1047 if (is_sun4m)
1048 off += 1024;
1049 }
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001050# endif /* SUNOS4_KERNEL_ARCH_KLUDGE */
Roland McGratheb9e2e82009-06-02 16:49:22 -07001051 errno = 0;
Denys Vlasenko732d1bf2008-12-17 19:21:59 +00001052 val = do_ptrace(PTRACE_PEEKUSER, tcp, (char *) off, 0);
Roland McGratheb9e2e82009-06-02 16:49:22 -07001053 if (val == -1 && errno) {
1054 if (errno != ESRCH) {
1055 char buf[60];
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001056 sprintf(buf, "upeek: ptrace(PTRACE_PEEKUSER,%d,%lu,0)", tcp->pid, off);
Roland McGratheb9e2e82009-06-02 16:49:22 -07001057 perror(buf);
1058 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001059 return -1;
Roland McGratheb9e2e82009-06-02 16:49:22 -07001060 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001061 *res = val;
1062 return 0;
1063}
1064
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001065#endif /* !USE_PROCFS */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001066
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001067void
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001068printcall(struct tcb *tcp)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001069{
Roland McGrath7a918832005-02-02 20:55:23 +00001070#define PRINTBADPC tprintf(sizeof(long) == 4 ? "[????????] " : \
1071 sizeof(long) == 8 ? "[????????????????] " : \
1072 NULL /* crash */)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001073
1074#ifdef LINUX
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001075# ifdef I386
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001076 long eip;
1077
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001078 if (upeek(tcp, 4*EIP, &eip) < 0) {
Roland McGrath7a918832005-02-02 20:55:23 +00001079 PRINTBADPC;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001080 return;
1081 }
1082 tprintf("[%08lx] ", eip);
Roland McGratheac26fc2005-02-02 02:48:53 +00001083
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001084# elif defined(S390) || defined(S390X)
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001085 long psw;
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001086 if (upeek(tcp, PT_PSWADDR, &psw) < 0) {
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001087 PRINTBADPC;
1088 return;
1089 }
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001090# ifdef S390
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001091 tprintf("[%08lx] ", psw);
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001092# elif S390X
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001093 tprintf("[%16lx] ", psw);
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001094# endif
Roland McGratheac26fc2005-02-02 02:48:53 +00001095
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001096# elif defined(X86_64)
Michal Ludvig0e035502002-09-23 15:41:01 +00001097 long rip;
1098
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001099 if (upeek(tcp, 8*RIP, &rip) < 0) {
Roland McGrath7a918832005-02-02 20:55:23 +00001100 PRINTBADPC;
Michal Ludvig0e035502002-09-23 15:41:01 +00001101 return;
1102 }
1103 tprintf("[%16lx] ", rip);
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001104# elif defined(IA64)
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00001105 long ip;
1106
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001107 if (upeek(tcp, PT_B0, &ip) < 0) {
Roland McGrath7a918832005-02-02 20:55:23 +00001108 PRINTBADPC;
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00001109 return;
1110 }
1111 tprintf("[%08lx] ", ip);
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001112# elif defined(POWERPC)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001113 long pc;
1114
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001115 if (upeek(tcp, sizeof(unsigned long)*PT_NIP, &pc) < 0) {
Andreas Schwabd69fa492010-07-12 21:39:57 +02001116 PRINTBADPC;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001117 return;
1118 }
Andreas Schwabd69fa492010-07-12 21:39:57 +02001119# ifdef POWERPC64
1120 tprintf("[%016lx] ", pc);
1121# else
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001122 tprintf("[%08lx] ", pc);
Andreas Schwabd69fa492010-07-12 21:39:57 +02001123# endif
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001124# elif defined(M68K)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001125 long pc;
1126
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001127 if (upeek(tcp, 4*PT_PC, &pc) < 0) {
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001128 tprintf("[????????] ");
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001129 return;
1130 }
1131 tprintf("[%08lx] ", pc);
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001132# elif defined(ALPHA)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001133 long pc;
1134
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001135 if (upeek(tcp, REG_PC, &pc) < 0) {
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001136 tprintf("[????????????????] ");
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001137 return;
1138 }
1139 tprintf("[%08lx] ", pc);
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001140# elif defined(SPARC) || defined(SPARC64)
Mike Frysinger8566c502009-10-12 11:05:14 -04001141 struct pt_regs regs;
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001142 if (ptrace(PTRACE_GETREGS, tcp->pid, (char *)&regs, 0) < 0) {
Roland McGrath7a918832005-02-02 20:55:23 +00001143 PRINTBADPC;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001144 return;
1145 }
Mike Frysinger8566c502009-10-12 11:05:14 -04001146# if defined(SPARC64)
1147 tprintf("[%08lx] ", regs.tpc);
1148# else
1149 tprintf("[%08lx] ", regs.pc);
1150# endif
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001151# elif defined(HPPA)
Wichert Akkermanc1652e22001-03-27 12:17:16 +00001152 long pc;
1153
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001154 if (upeek(tcp, PT_IAOQ0, &pc) < 0) {
1155 tprintf("[????????] ");
Wichert Akkermanc1652e22001-03-27 12:17:16 +00001156 return;
1157 }
1158 tprintf("[%08lx] ", pc);
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001159# elif defined(MIPS)
Wichert Akkerman75c422b2001-04-10 10:22:50 +00001160 long pc;
1161
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001162 if (upeek(tcp, REG_EPC, &pc) < 0) {
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001163 tprintf("[????????] ");
Wichert Akkerman75c422b2001-04-10 10:22:50 +00001164 return;
1165 }
1166 tprintf("[%08lx] ", pc);
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001167# elif defined(SH)
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001168 long pc;
Wichert Akkermanccef6372002-05-01 16:39:22 +00001169
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001170 if (upeek(tcp, 4*REG_PC, &pc) < 0) {
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001171 tprintf("[????????] ");
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001172 return;
1173 }
1174 tprintf("[%08lx] ", pc);
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001175# elif defined(SH64)
Roland McGrathe1e584b2003-06-02 19:18:58 +00001176 long pc;
1177
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001178 if (upeek(tcp, REG_PC, &pc) < 0) {
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001179 tprintf("[????????????????] ");
Roland McGrathe1e584b2003-06-02 19:18:58 +00001180 return;
1181 }
1182 tprintf("[%08lx] ", pc);
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001183# elif defined(ARM)
Roland McGrathef388682003-06-03 23:28:59 +00001184 long pc;
Roland McGrathe1e584b2003-06-02 19:18:58 +00001185
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001186 if (upeek(tcp, 4*15, &pc) < 0) {
Roland McGrath7a918832005-02-02 20:55:23 +00001187 PRINTBADPC;
Roland McGrathef388682003-06-03 23:28:59 +00001188 return;
1189 }
1190 tprintf("[%08lx] ", pc);
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00001191# elif defined(AVR32)
1192 long pc;
1193
1194 if (upeek(tcp, REG_PC, &pc) < 0) {
1195 tprintf("[????????] ");
1196 return;
1197 }
1198 tprintf("[%08lx] ", pc);
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001199# elif defined(BFIN)
Dmitry V. Levin87ea1f42008-11-10 22:21:41 +00001200 long pc;
1201
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001202 if (upeek(tcp, PT_PC, &pc) < 0) {
Dmitry V. Levin87ea1f42008-11-10 22:21:41 +00001203 PRINTBADPC;
1204 return;
1205 }
1206 tprintf("[%08lx] ", pc);
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001207#elif defined(CRISV10)
1208 long pc;
1209
Edgar E. Iglesiaseeb9ce32009-10-05 14:41:02 +00001210 if (upeek(tcp, 4*PT_IRP, &pc) < 0) {
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001211 PRINTBADPC;
1212 return;
1213 }
1214 tprintf("[%08lx] ", pc);
1215#elif defined(CRISV32)
1216 long pc;
1217
Edgar E. Iglesiaseeb9ce32009-10-05 14:41:02 +00001218 if (upeek(tcp, 4*PT_ERP, &pc) < 0) {
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001219 PRINTBADPC;
1220 return;
1221 }
1222 tprintf("[%08lx] ", pc);
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001223# endif /* architecture */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001224#endif /* LINUX */
1225
1226#ifdef SUNOS4
1227 struct regs regs;
1228
Roland McGratheb9e2e82009-06-02 16:49:22 -07001229 if (ptrace(PTRACE_GETREGS, tcp->pid, (char *) &regs, 0) < 0) {
1230 perror("printcall: ptrace(PTRACE_GETREGS, ...)");
Roland McGrath7a918832005-02-02 20:55:23 +00001231 PRINTBADPC;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001232 return;
1233 }
1234 tprintf("[%08x] ", regs.r_o7);
1235#endif /* SUNOS4 */
1236
1237#ifdef SVR4
1238 /* XXX */
Roland McGrath7a918832005-02-02 20:55:23 +00001239 PRINTBADPC;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001240#endif
1241
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001242#ifdef FREEBSD
1243 struct reg regs;
1244 pread(tcp->pfd_reg, &regs, sizeof(regs), 0);
1245 tprintf("[%08x] ", regs.r_eip);
1246#endif /* FREEBSD */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001247}
1248
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001249
1250/*
1251 * These #if's are huge, please indent them correctly.
1252 * It's easy to get confused otherwise.
1253 */
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001254#ifndef USE_PROCFS
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001255
Denys Vlasenkoe7c90242011-06-22 00:09:25 +02001256# ifdef LINUX
Roland McGrathd81f1d92003-01-09 06:53:34 +00001257
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001258# include "syscall.h"
Roland McGrath3291ef22008-05-20 00:34:34 +00001259
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001260# include <sys/syscall.h>
1261# ifndef CLONE_PTRACE
1262# define CLONE_PTRACE 0x00002000
1263# endif
1264# ifndef CLONE_VFORK
1265# define CLONE_VFORK 0x00004000
1266# endif
1267# ifndef CLONE_VM
1268# define CLONE_VM 0x00000100
1269# endif
1270# ifndef CLONE_STOPPED
1271# define CLONE_STOPPED 0x02000000
1272# endif
Roland McGrathd81f1d92003-01-09 06:53:34 +00001273
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001274# ifdef IA64
Roland McGrathd81f1d92003-01-09 06:53:34 +00001275
Roland McGrath08267b82004-02-20 22:56:43 +00001276/* We don't have fork()/vfork() syscalls on ia64 itself, but the ia32
1277 subsystem has them for x86... */
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001278# define SYS_fork 2
1279# define SYS_vfork 190
Roland McGrath08267b82004-02-20 22:56:43 +00001280
Roland McGrathd81f1d92003-01-09 06:53:34 +00001281typedef unsigned long *arg_setup_state;
1282
1283static int
1284arg_setup(struct tcb *tcp, arg_setup_state *state)
1285{
Jan Kratochvil1f942712008-08-06 21:38:52 +00001286 unsigned long cfm, sof, sol;
1287 long bsp;
Roland McGrathd81f1d92003-01-09 06:53:34 +00001288
Jan Kratochvil1f942712008-08-06 21:38:52 +00001289 if (ia32) {
1290 /* Satisfy a false GCC warning. */
1291 *state = NULL;
Roland McGrath08267b82004-02-20 22:56:43 +00001292 return 0;
Jan Kratochvil1f942712008-08-06 21:38:52 +00001293 }
Roland McGrath08267b82004-02-20 22:56:43 +00001294
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001295 if (upeek(tcp, PT_AR_BSP, &bsp) < 0)
Roland McGrathd81f1d92003-01-09 06:53:34 +00001296 return -1;
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001297 if (upeek(tcp, PT_CFM, (long *) &cfm) < 0)
Roland McGrathd81f1d92003-01-09 06:53:34 +00001298 return -1;
1299
1300 sof = (cfm >> 0) & 0x7f;
1301 sol = (cfm >> 7) & 0x7f;
Jan Kratochvil1f942712008-08-06 21:38:52 +00001302 bsp = (long) ia64_rse_skip_regs((unsigned long *) bsp, -sof + sol);
Roland McGrathd81f1d92003-01-09 06:53:34 +00001303
Jan Kratochvil1f942712008-08-06 21:38:52 +00001304 *state = (unsigned long *) bsp;
Roland McGrathd81f1d92003-01-09 06:53:34 +00001305 return 0;
1306}
1307
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001308# define arg_finish_change(tcp, state) 0
Roland McGrathd81f1d92003-01-09 06:53:34 +00001309
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001310# ifdef SYS_fork
Roland McGrathd81f1d92003-01-09 06:53:34 +00001311static int
Denys Vlasenko12014262011-05-30 14:00:14 +02001312get_arg0(struct tcb *tcp, arg_setup_state *state, long *valp)
Roland McGrathd81f1d92003-01-09 06:53:34 +00001313{
Roland McGrath08267b82004-02-20 22:56:43 +00001314 int ret;
1315
1316 if (ia32)
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001317 ret = upeek(tcp, PT_R11, valp);
Roland McGrath08267b82004-02-20 22:56:43 +00001318 else
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001319 ret = umoven(tcp,
Roland McGrath08267b82004-02-20 22:56:43 +00001320 (unsigned long) ia64_rse_skip_regs(*state, 0),
1321 sizeof(long), (void *) valp);
1322 return ret;
Roland McGrathd81f1d92003-01-09 06:53:34 +00001323}
1324
1325static int
Denys Vlasenko12014262011-05-30 14:00:14 +02001326get_arg1(struct tcb *tcp, arg_setup_state *state, long *valp)
Roland McGrathd81f1d92003-01-09 06:53:34 +00001327{
Roland McGrath08267b82004-02-20 22:56:43 +00001328 int ret;
1329
1330 if (ia32)
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001331 ret = upeek(tcp, PT_R9, valp);
Roland McGrath08267b82004-02-20 22:56:43 +00001332 else
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001333 ret = umoven(tcp,
Roland McGrath08267b82004-02-20 22:56:43 +00001334 (unsigned long) ia64_rse_skip_regs(*state, 1),
1335 sizeof(long), (void *) valp);
1336 return ret;
Roland McGrathd81f1d92003-01-09 06:53:34 +00001337}
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001338# endif
Roland McGrathd81f1d92003-01-09 06:53:34 +00001339
1340static int
Denys Vlasenko12014262011-05-30 14:00:14 +02001341set_arg0(struct tcb *tcp, arg_setup_state *state, long val)
Roland McGrathd81f1d92003-01-09 06:53:34 +00001342{
Roland McGrath08267b82004-02-20 22:56:43 +00001343 int req = PTRACE_POKEDATA;
1344 void *ap;
1345
1346 if (ia32) {
1347 ap = (void *) (intptr_t) PT_R11; /* r11 == EBX */
1348 req = PTRACE_POKEUSER;
1349 } else
1350 ap = ia64_rse_skip_regs(*state, 0);
Roland McGratheb9e2e82009-06-02 16:49:22 -07001351 errno = 0;
1352 ptrace(req, tcp->pid, ap, val);
1353 return errno ? -1 : 0;
Roland McGrathd81f1d92003-01-09 06:53:34 +00001354}
1355
1356static int
Denys Vlasenko12014262011-05-30 14:00:14 +02001357set_arg1(struct tcb *tcp, arg_setup_state *state, long val)
Roland McGrathd81f1d92003-01-09 06:53:34 +00001358{
Roland McGrath08267b82004-02-20 22:56:43 +00001359 int req = PTRACE_POKEDATA;
1360 void *ap;
1361
1362 if (ia32) {
1363 ap = (void *) (intptr_t) PT_R9; /* r9 == ECX */
1364 req = PTRACE_POKEUSER;
1365 } else
1366 ap = ia64_rse_skip_regs(*state, 1);
Roland McGratheb9e2e82009-06-02 16:49:22 -07001367 errno = 0;
1368 ptrace(req, tcp->pid, ap, val);
1369 return errno ? -1 : 0;
Roland McGrathd81f1d92003-01-09 06:53:34 +00001370}
1371
Roland McGrathb659f872008-07-18 01:19:36 +00001372/* ia64 does not return the input arguments from functions (and syscalls)
1373 according to ia64 RSE (Register Stack Engine) behavior. */
1374
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001375# define restore_arg0(tcp, state, val) ((void) (state), 0)
1376# define restore_arg1(tcp, state, val) ((void) (state), 0)
Roland McGrathb659f872008-07-18 01:19:36 +00001377
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001378# elif defined (SPARC) || defined (SPARC64)
Roland McGrathd81f1d92003-01-09 06:53:34 +00001379
Mike Frysinger8566c502009-10-12 11:05:14 -04001380typedef struct pt_regs arg_setup_state;
Roland McGrathd81f1d92003-01-09 06:53:34 +00001381
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001382# define arg_setup(tcp, state) \
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001383 (ptrace(PTRACE_GETREGS, tcp->pid, (char *) (state), 0))
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001384# define arg_finish_change(tcp, state) \
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001385 (ptrace(PTRACE_SETREGS, tcp->pid, (char *) (state), 0))
Roland McGrathd81f1d92003-01-09 06:53:34 +00001386
Mike Frysinger8566c502009-10-12 11:05:14 -04001387# define get_arg0(tcp, state, valp) (*(valp) = (state)->u_regs[U_REG_O0], 0)
1388# define get_arg1(tcp, state, valp) (*(valp) = (state)->u_regs[U_REG_O1], 0)
1389# define set_arg0(tcp, state, val) ((state)->u_regs[U_REG_O0] = (val), 0)
1390# define set_arg1(tcp, state, val) ((state)->u_regs[U_REG_O1] = (val), 0)
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001391# define restore_arg0(tcp, state, val) 0
Roland McGrathd81f1d92003-01-09 06:53:34 +00001392
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001393# else /* other architectures */
Roland McGrathd81f1d92003-01-09 06:53:34 +00001394
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001395# if defined S390 || defined S390X
Roland McGrath7b308222003-01-20 09:04:36 +00001396/* Note: this is only true for the `clone' system call, which handles
1397 arguments specially. We could as well say that its first two arguments
1398 are swapped relative to other architectures, but that would just be
1399 another #ifdef in the calls. */
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001400# define arg0_offset PT_GPR3
1401# define arg1_offset PT_ORIGGPR2
1402# define restore_arg0(tcp, state, val) ((void) (state), 0)
1403# define restore_arg1(tcp, state, val) ((void) (state), 0)
1404# define arg0_index 1
1405# define arg1_index 0
1406# elif defined (ALPHA) || defined (MIPS)
1407# define arg0_offset REG_A0
1408# define arg1_offset (REG_A0+1)
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00001409# elif defined (AVR32)
1410# define arg0_offset (REG_R12)
1411# define arg1_offset (REG_R11)
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001412# elif defined (POWERPC)
1413# define arg0_offset (sizeof(unsigned long)*PT_R3)
1414# define arg1_offset (sizeof(unsigned long)*PT_R4)
1415# define restore_arg0(tcp, state, val) ((void) (state), 0)
1416# elif defined (HPPA)
1417# define arg0_offset PT_GR26
1418# define arg1_offset (PT_GR26-4)
1419# elif defined (X86_64)
1420# define arg0_offset ((long)(8*(current_personality ? RBX : RDI)))
1421# define arg1_offset ((long)(8*(current_personality ? RCX : RSI)))
1422# elif defined (SH)
1423# define arg0_offset (4*(REG_REG0+4))
1424# define arg1_offset (4*(REG_REG0+5))
1425# elif defined (SH64)
1426 /* ABI defines arg0 & 1 in r2 & r3 */
1427# define arg0_offset (REG_OFFSET+16)
1428# define arg1_offset (REG_OFFSET+24)
1429# define restore_arg0(tcp, state, val) 0
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001430# elif defined CRISV10 || defined CRISV32
1431# define arg0_offset (4*PT_R11)
1432# define arg1_offset (4*PT_ORIG_R10)
1433# define restore_arg0(tcp, state, val) 0
1434# define restore_arg1(tcp, state, val) 0
1435# define arg0_index 1
1436# define arg1_index 0
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001437# else
1438# define arg0_offset 0
1439# define arg1_offset 4
1440# if defined ARM
1441# define restore_arg0(tcp, state, val) 0
1442# endif
1443# endif
Roland McGrathd81f1d92003-01-09 06:53:34 +00001444
1445typedef int arg_setup_state;
1446
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001447# define arg_setup(tcp, state) (0)
1448# define arg_finish_change(tcp, state) 0
1449# define get_arg0(tcp, cookie, valp) \
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001450 (upeek((tcp), arg0_offset, (valp)))
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001451# define get_arg1(tcp, cookie, valp) \
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001452 (upeek((tcp), arg1_offset, (valp)))
Roland McGrathd81f1d92003-01-09 06:53:34 +00001453
1454static int
Denys Vlasenko12014262011-05-30 14:00:14 +02001455set_arg0(struct tcb *tcp, void *cookie, long val)
Roland McGrathd81f1d92003-01-09 06:53:34 +00001456{
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001457 return ptrace(PTRACE_POKEUSER, tcp->pid, (char*)arg0_offset, val);
Roland McGrathd81f1d92003-01-09 06:53:34 +00001458}
1459
1460static int
Denys Vlasenko12014262011-05-30 14:00:14 +02001461set_arg1(struct tcb *tcp, void *cookie, long val)
Roland McGrathd81f1d92003-01-09 06:53:34 +00001462{
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001463 return ptrace(PTRACE_POKEUSER, tcp->pid, (char*)arg1_offset, val);
Roland McGrathd81f1d92003-01-09 06:53:34 +00001464}
1465
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001466# endif /* architectures */
Roland McGrathd81f1d92003-01-09 06:53:34 +00001467
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001468# ifndef restore_arg0
1469# define restore_arg0(tcp, state, val) set_arg0((tcp), (state), (val))
1470# endif
1471# ifndef restore_arg1
1472# define restore_arg1(tcp, state, val) set_arg1((tcp), (state), (val))
1473# endif
Roland McGrathd81f1d92003-01-09 06:53:34 +00001474
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001475# ifndef arg0_index
1476# define arg0_index 0
1477# define arg1_index 1
1478# endif
Roland McGrath90d0afd2004-03-01 21:05:16 +00001479
Roland McGrathd81f1d92003-01-09 06:53:34 +00001480int
Denys Vlasenko418d66a2009-01-17 01:52:54 +00001481setbpt(struct tcb *tcp)
Roland McGrathd81f1d92003-01-09 06:53:34 +00001482{
Roland McGrath3291ef22008-05-20 00:34:34 +00001483 static int clone_scno[SUPPORTED_PERSONALITIES] = { SYS_clone };
Roland McGrathd81f1d92003-01-09 06:53:34 +00001484 arg_setup_state state;
1485
1486 if (tcp->flags & TCB_BPTSET) {
1487 fprintf(stderr, "PANIC: TCB already set in pid %u\n", tcp->pid);
1488 return -1;
1489 }
1490
Roland McGrath3291ef22008-05-20 00:34:34 +00001491 /*
1492 * It's a silly kludge to initialize this with a search at runtime.
1493 * But it's better than maintaining another magic thing in the
1494 * godforsaken tables.
1495 */
1496 if (clone_scno[current_personality] == 0) {
1497 int i;
1498 for (i = 0; i < nsyscalls; ++i)
1499 if (sysent[i].sys_func == sys_clone) {
1500 clone_scno[current_personality] = i;
1501 break;
1502 }
1503 }
1504
Roland McGrath76989d72005-06-07 23:21:31 +00001505 switch (known_scno(tcp)) {
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001506# ifdef SYS_vfork
Roland McGrath9383c6c2003-01-18 00:19:31 +00001507 case SYS_vfork:
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001508# endif
1509# ifdef SYS_fork
Roland McGrathd81f1d92003-01-09 06:53:34 +00001510 case SYS_fork:
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001511# endif
1512# if defined SYS_fork || defined SYS_vfork
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001513 if (arg_setup(tcp, &state) < 0
1514 || get_arg0(tcp, &state, &tcp->inst[0]) < 0
1515 || get_arg1(tcp, &state, &tcp->inst[1]) < 0
Roland McGrath3291ef22008-05-20 00:34:34 +00001516 || change_syscall(tcp, clone_scno[current_personality]) < 0
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001517 || set_arg0(tcp, &state, CLONE_PTRACE|SIGCHLD) < 0
1518 || set_arg1(tcp, &state, 0) < 0
1519 || arg_finish_change(tcp, &state) < 0)
Roland McGrathd81f1d92003-01-09 06:53:34 +00001520 return -1;
Roland McGrathc9dc3c12004-03-01 20:57:09 +00001521 tcp->u_arg[arg0_index] = CLONE_PTRACE|SIGCHLD;
1522 tcp->u_arg[arg1_index] = 0;
Roland McGrathd81f1d92003-01-09 06:53:34 +00001523 tcp->flags |= TCB_BPTSET;
1524 return 0;
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001525# endif
Roland McGrathd81f1d92003-01-09 06:53:34 +00001526
Denys Vlasenkoc133bf02011-06-23 21:57:54 +02001527 case SYS_clone: ;
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001528# ifdef SYS_clone2
Denys Vlasenkoc133bf02011-06-23 21:57:54 +02001529 case SYS_clone2: ;
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001530# endif
Jan Kratochvil8fc95752008-08-06 21:43:35 +00001531 /* ia64 calls directly `clone (CLONE_VFORK | CLONE_VM)'
1532 contrary to x86 SYS_vfork above. Even on x86 we turn the
1533 vfork semantics into plain fork - each application must not
1534 depend on the vfork specifics according to POSIX. We would
1535 hang waiting for the parent resume otherwise. We need to
1536 clear also CLONE_VM but only in the CLONE_VFORK case as
1537 otherwise we would break pthread_create. */
1538
Denys Vlasenkoc133bf02011-06-23 21:57:54 +02001539 long new_arg0 = (tcp->u_arg[arg0_index] | CLONE_PTRACE);
1540 if (new_arg0 & CLONE_VFORK)
1541 new_arg0 &= ~(unsigned long)(CLONE_VFORK | CLONE_VM);
1542 if (arg_setup(tcp, &state) < 0
1543 || set_arg0(tcp, &state, new_arg0) < 0
1544 || arg_finish_change(tcp, &state) < 0)
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00001545 return -1;
Roland McGrathd81f1d92003-01-09 06:53:34 +00001546 tcp->flags |= TCB_BPTSET;
Roland McGrathc9dc3c12004-03-01 20:57:09 +00001547 tcp->inst[0] = tcp->u_arg[arg0_index];
1548 tcp->inst[1] = tcp->u_arg[arg1_index];
Roland McGrathd81f1d92003-01-09 06:53:34 +00001549 return 0;
1550
1551 default:
1552 fprintf(stderr, "PANIC: setbpt for syscall %ld on %u???\n",
1553 tcp->scno, tcp->pid);
1554 break;
1555 }
1556
1557 return -1;
1558}
1559
1560int
Denys Vlasenko12014262011-05-30 14:00:14 +02001561clearbpt(struct tcb *tcp)
Roland McGrathd81f1d92003-01-09 06:53:34 +00001562{
1563 arg_setup_state state;
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001564 if (arg_setup(tcp, &state) < 0
1565 || restore_arg0(tcp, &state, tcp->inst[0]) < 0
1566 || restore_arg1(tcp, &state, tcp->inst[1]) < 0
1567 || arg_finish_change(tcp, &state))
Denys Vlasenkoc133bf02011-06-23 21:57:54 +02001568 if (errno != ESRCH)
1569 return -1;
Roland McGrathd81f1d92003-01-09 06:53:34 +00001570 tcp->flags &= ~TCB_BPTSET;
1571 return 0;
1572}
1573
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001574# else /* !defined LINUX */
Roland McGrathd81f1d92003-01-09 06:53:34 +00001575
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001576int
Denys Vlasenko12014262011-05-30 14:00:14 +02001577setbpt(struct tcb *tcp)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001578{
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001579# ifdef SUNOS4
1580# ifdef SPARC /* This code is slightly sparc specific */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001581
Wichert Akkermane6f876c1999-06-22 15:28:30 +00001582 struct regs regs;
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001583# define BPT 0x91d02001 /* ta 1 */
1584# define LOOP 0x10800000 /* ba 0 */
1585# define LOOPA 0x30800000 /* ba,a 0 */
1586# define NOP 0x01000000
1587# if LOOPA
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001588 static int loopdeloop[1] = {LOOPA};
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001589# else
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001590 static int loopdeloop[2] = {LOOP, NOP};
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001591# endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001592
1593 if (tcp->flags & TCB_BPTSET) {
1594 fprintf(stderr, "PANIC: TCB already set in pid %u\n", tcp->pid);
1595 return -1;
1596 }
Roland McGratheb9e2e82009-06-02 16:49:22 -07001597 if (ptrace(PTRACE_GETREGS, tcp->pid, (char *)&regs, 0) < 0) {
1598 perror("setbpt: ptrace(PTRACE_GETREGS, ...)");
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001599 return -1;
1600 }
1601 tcp->baddr = regs.r_o7 + 8;
Roland McGratheb9e2e82009-06-02 16:49:22 -07001602 if (ptrace(PTRACE_READTEXT, tcp->pid, (char *)tcp->baddr,
1603 sizeof tcp->inst, (char *)tcp->inst) < 0) {
1604 perror("setbpt: ptrace(PTRACE_READTEXT, ...)");
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001605 return -1;
1606 }
1607
1608 /*
1609 * XXX - BRUTAL MODE ON
1610 * We cannot set a real BPT in the child, since it will not be
1611 * traced at the moment it will reach the trap and would probably
1612 * die with a core dump.
1613 * Thus, we are force our way in by taking out two instructions
1614 * and insert an eternal loop in stead, in expectance of the SIGSTOP
1615 * generated by out PTRACE_ATTACH.
1616 * Of cause, if we evaporate ourselves in the middle of all this...
1617 */
Roland McGratheb9e2e82009-06-02 16:49:22 -07001618 if (ptrace(PTRACE_WRITETEXT, tcp->pid, (char *) tcp->baddr,
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001619 sizeof loopdeloop, (char *) loopdeloop) < 0) {
Roland McGratheb9e2e82009-06-02 16:49:22 -07001620 perror("setbpt: ptrace(PTRACE_WRITETEXT, ...)");
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001621 return -1;
1622 }
1623 tcp->flags |= TCB_BPTSET;
1624
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001625# endif /* SPARC */
1626# endif /* SUNOS4 */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001627
1628 return 0;
1629}
1630
1631int
Denys Vlasenko12014262011-05-30 14:00:14 +02001632clearbpt(struct tcb *tcp)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001633{
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001634# ifdef SUNOS4
1635# ifdef SPARC
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001636
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001637# if !LOOPA
Wichert Akkermane6f876c1999-06-22 15:28:30 +00001638 struct regs regs;
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001639# endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001640
1641 if (!(tcp->flags & TCB_BPTSET)) {
1642 fprintf(stderr, "PANIC: TCB not set in pid %u\n", tcp->pid);
1643 return -1;
1644 }
Roland McGratheb9e2e82009-06-02 16:49:22 -07001645 if (ptrace(PTRACE_WRITETEXT, tcp->pid, (char *) tcp->baddr,
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001646 sizeof tcp->inst, (char *) tcp->inst) < 0) {
Roland McGratheb9e2e82009-06-02 16:49:22 -07001647 perror("clearbtp: ptrace(PTRACE_WRITETEXT, ...)");
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001648 return -1;
1649 }
1650 tcp->flags &= ~TCB_BPTSET;
1651
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001652# if !LOOPA
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001653 /*
1654 * Since we don't have a single instruction breakpoint, we may have
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001655 * to adjust the program counter after removing our `breakpoint'.
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001656 */
Roland McGratheb9e2e82009-06-02 16:49:22 -07001657 if (ptrace(PTRACE_GETREGS, tcp->pid, (char *)&regs, 0) < 0) {
1658 perror("clearbpt: ptrace(PTRACE_GETREGS, ...)");
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001659 return -1;
1660 }
Roland McGratheb9e2e82009-06-02 16:49:22 -07001661 if ((regs.r_pc < tcp->baddr) ||
1662 (regs.r_pc > tcp->baddr + 4)) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001663 /* The breakpoint has not been reached yet */
1664 if (debug)
1665 fprintf(stderr,
1666 "NOTE: PC not at bpt (pc %#x baddr %#x)\n",
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001667 regs.r_pc, tcp->baddr);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001668 return 0;
1669 }
1670 if (regs.r_pc != tcp->baddr)
1671 if (debug)
1672 fprintf(stderr, "NOTE: PC adjusted (%#x -> %#x\n",
1673 regs.r_pc, tcp->baddr);
1674
1675 regs.r_pc = tcp->baddr;
Roland McGratheb9e2e82009-06-02 16:49:22 -07001676 if (ptrace(PTRACE_SETREGS, tcp->pid, (char *)&regs, 0) < 0) {
1677 perror("clearbpt: ptrace(PTRACE_SETREGS, ...)");
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001678 return -1;
1679 }
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001680# endif /* LOOPA */
1681# endif /* SPARC */
1682# endif /* SUNOS4 */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001683
1684 return 0;
1685}
1686
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001687# endif /* !defined LINUX */
Roland McGrathd81f1d92003-01-09 06:53:34 +00001688
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001689#endif /* !USE_PROCFS */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001690
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001691
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001692#ifdef SUNOS4
1693
1694static int
Denys Vlasenko12014262011-05-30 14:00:14 +02001695getex(struct tcb *tcp, struct exec *hdr)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001696{
1697 int n;
1698
1699 for (n = 0; n < sizeof *hdr; n += 4) {
1700 long res;
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001701 if (upeek(tcp, uoff(u_exdata) + n, &res) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001702 return -1;
1703 memcpy(((char *) hdr) + n, &res, 4);
1704 }
1705 if (debug) {
1706 fprintf(stderr, "[struct exec: magic: %o version %u Mach %o\n",
1707 hdr->a_magic, hdr->a_toolversion, hdr->a_machtype);
1708 fprintf(stderr, "Text %lu Data %lu Bss %lu Syms %lu Entry %#lx]\n",
1709 hdr->a_text, hdr->a_data, hdr->a_bss, hdr->a_syms, hdr->a_entry);
1710 }
1711 return 0;
1712}
1713
1714int
Denys Vlasenko12014262011-05-30 14:00:14 +02001715fixvfork(struct tcb *tcp)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001716{
1717 int pid = tcp->pid;
1718 /*
1719 * Change `vfork' in a freshly exec'ed dynamically linked
1720 * executable's (internal) symbol table to plain old `fork'
1721 */
1722
1723 struct exec hdr;
1724 struct link_dynamic dyn;
1725 struct link_dynamic_2 ld;
1726 char *strtab, *cp;
1727
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001728 if (getex(tcp, &hdr) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001729 return -1;
1730 if (!hdr.a_dynamic)
1731 return -1;
1732
1733 if (umove(tcp, (int) N_DATADDR(hdr), &dyn) < 0) {
1734 fprintf(stderr, "Cannot read DYNAMIC\n");
1735 return -1;
1736 }
1737 if (umove(tcp, (int) dyn.ld_un.ld_2, &ld) < 0) {
1738 fprintf(stderr, "Cannot read link_dynamic_2\n");
1739 return -1;
1740 }
Denys Vlasenko5d645812011-08-20 12:48:18 +02001741 strtab = malloc((unsigned)ld.ld_symb_size);
Denys Vlasenko1d46ba52011-08-31 14:00:02 +02001742 if (!strtab)
1743 die_out_of_memory();
Roland McGratheb9e2e82009-06-02 16:49:22 -07001744 if (umoven(tcp, (int)ld.ld_symbols+(int)N_TXTADDR(hdr),
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001745 (int)ld.ld_symb_size, strtab) < 0)
1746 goto err;
1747
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001748 for (cp = strtab; cp < strtab + ld.ld_symb_size; ) {
1749 if (strcmp(cp, "_vfork") == 0) {
1750 if (debug)
1751 fprintf(stderr, "fixvfork: FOUND _vfork\n");
1752 strcpy(cp, "_fork");
1753 break;
1754 }
1755 cp += strlen(cp)+1;
1756 }
1757 if (cp < strtab + ld.ld_symb_size)
1758 /*
1759 * Write entire symbol table back to avoid
1760 * memory alignment bugs in ptrace
1761 */
Roland McGratheb9e2e82009-06-02 16:49:22 -07001762 if (tload(pid, (int)ld.ld_symbols+(int)N_TXTADDR(hdr),
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001763 (int)ld.ld_symb_size, strtab) < 0)
1764 goto err;
1765
1766 free(strtab);
1767 return 0;
1768
1769err:
1770 free(strtab);
1771 return -1;
1772}
1773
1774#endif /* SUNOS4 */