blob: 7bf2698404f3e6d87bb16fa302c8fb3a9d635356 [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. */
622 if (!str)
623 str = malloc(max_strlen + 1);
624 if (!outstr)
625 outstr = malloc(4 * max_strlen + sizeof "\"...\"");
626 if (!str || !outstr) {
627 fprintf(stderr, "out of memory\n");
628 tprintf("%#lx", addr);
629 return;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000630 }
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000631
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000632 if (len < 0) {
Dmitry V. Levina501f142008-11-10 23:19:13 +0000633 /*
634 * Treat as a NUL-terminated string: fetch one byte more
635 * because string_quote() quotes one byte less.
636 */
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000637 size = max_strlen + 1;
Dmitry V. Levina501f142008-11-10 23:19:13 +0000638 str[max_strlen] = '\0';
Denys Vlasenko52845572011-08-31 12:07:38 +0200639 /* FIXME! umovestr can overwrite the '\0' stored above??? */
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000640 if (umovestr(tcp, addr, size, str) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000641 tprintf("%#lx", addr);
642 return;
643 }
644 }
645 else {
Dmitry V. Levina501f142008-11-10 23:19:13 +0000646 size = MIN(len, max_strlen);
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000647 if (umoven(tcp, addr, size, str) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000648 tprintf("%#lx", addr);
649 return;
650 }
651 }
652
Denys Vlasenko52845572011-08-31 12:07:38 +0200653 fmt = "%s";
Dmitry V. Levina501f142008-11-10 23:19:13 +0000654 if (string_quote(str, outstr, len, size) &&
655 (len < 0 || len > max_strlen))
Denys Vlasenko52845572011-08-31 12:07:38 +0200656 fmt = "%s...";
Roland McGratha503dcf2007-08-02 02:06:26 +0000657
Denys Vlasenko52845572011-08-31 12:07:38 +0200658 tprintf(fmt, outstr);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000659}
660
John Hughes1d08dcf2001-07-10 13:48:44 +0000661#if HAVE_SYS_UIO_H
662void
Denys Vlasenko12014262011-05-30 14:00:14 +0200663dumpiov(struct tcb *tcp, int len, long addr)
John Hughes1d08dcf2001-07-10 13:48:44 +0000664{
Dmitry V. Levin4ebb4e32006-12-13 17:08:08 +0000665#if defined(LINUX) && SUPPORTED_PERSONALITIES > 1
666 union {
667 struct { u_int32_t base; u_int32_t len; } *iov32;
668 struct { u_int64_t base; u_int64_t len; } *iov64;
669 } iovu;
670#define iov iovu.iov64
671#define sizeof_iov \
672 (personality_wordsize[current_personality] == 4 \
673 ? sizeof(*iovu.iov32) : sizeof(*iovu.iov64))
674#define iov_iov_base(i) \
675 (personality_wordsize[current_personality] == 4 \
676 ? (u_int64_t) iovu.iov32[i].base : iovu.iov64[i].base)
677#define iov_iov_len(i) \
678 (personality_wordsize[current_personality] == 4 \
679 ? (u_int64_t) iovu.iov32[i].len : iovu.iov64[i].len)
680#else
John Hughes1d08dcf2001-07-10 13:48:44 +0000681 struct iovec *iov;
Dmitry V. Levin4ebb4e32006-12-13 17:08:08 +0000682#define sizeof_iov sizeof(*iov)
683#define iov_iov_base(i) iov[i].iov_base
684#define iov_iov_len(i) iov[i].iov_len
685#endif
John Hughes1d08dcf2001-07-10 13:48:44 +0000686 int i;
Roland McGrathaa524c82005-06-01 19:22:06 +0000687 unsigned long size;
John Hughes1d08dcf2001-07-10 13:48:44 +0000688
Dmitry V. Levin4ebb4e32006-12-13 17:08:08 +0000689 size = sizeof_iov * (unsigned long) len;
690 if (size / sizeof_iov != len
691 || (iov = malloc(size)) == NULL) {
Roland McGrathaa524c82005-06-01 19:22:06 +0000692 fprintf(stderr, "out of memory\n");
John Hughes1d08dcf2001-07-10 13:48:44 +0000693 return;
694 }
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;
718 static char outstr[80];
719 char *s;
720 int i, j;
721
722 if (strsize < len) {
Denys Vlasenko5d645812011-08-20 12:48:18 +0200723 free(str);
724 str = malloc(len);
725 if (str == NULL) {
Roland McGrath46100d02005-06-01 18:55:42 +0000726 fprintf(stderr, "out of memory\n");
Denys Vlasenkocfd364b2011-08-20 13:41:13 +0200727 /* BUG! On next call we may use NULL str! */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000728 return;
729 }
730 strsize = len;
731 }
732
733 if (umoven(tcp, addr, len, (char *) str) < 0)
734 return;
735
736 for (i = 0; i < len; i += 16) {
737 s = outstr;
738 sprintf(s, " | %05x ", i);
739 s += 9;
740 for (j = 0; j < 16; j++) {
741 if (j == 8)
742 *s++ = ' ';
743 if (i + j < len) {
744 sprintf(s, " %02x", str[i + j]);
745 s += 3;
746 }
747 else {
748 *s++ = ' '; *s++ = ' '; *s++ = ' ';
749 }
750 }
751 *s++ = ' '; *s++ = ' ';
752 for (j = 0; j < 16; j++) {
753 if (j == 8)
754 *s++ = ' ';
755 if (i + j < len) {
756 if (isprint(str[i + j]))
757 *s++ = str[i + j];
758 else
759 *s++ = '.';
760 }
761 else
762 *s++ = ' ';
763 }
764 tprintf("%s |\n", outstr);
765 }
766}
767
768#define PAGMASK (~(PAGSIZ - 1))
769/*
770 * move `len' bytes of data from process `pid'
771 * at address `addr' to our space at `laddr'
772 */
773int
Denys Vlasenkoef2fbf82009-01-06 21:45:06 +0000774umoven(struct tcb *tcp, long addr, int len, char *laddr)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000775{
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000776#ifdef LINUX
Roland McGratheb9e2e82009-06-02 16:49:22 -0700777 int pid = tcp->pid;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000778 int n, m;
Wichert Akkerman5daa0281999-03-15 19:49:42 +0000779 int started = 0;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000780 union {
781 long val;
782 char x[sizeof(long)];
783 } u;
784
785 if (addr & (sizeof(long) - 1)) {
786 /* addr not a multiple of sizeof(long) */
787 n = addr - (addr & -sizeof(long)); /* residue */
788 addr &= -sizeof(long); /* residue */
Roland McGratheb9e2e82009-06-02 16:49:22 -0700789 errno = 0;
790 u.val = ptrace(PTRACE_PEEKDATA, pid, (char *) addr, 0);
791 if (errno) {
792 if (started && (errno==EPERM || errno==EIO)) {
793 /* Ran into 'end of memory' - stupid "printpath" */
794 return 0;
795 }
796 /* But if not started, we had a bogus address. */
797 if (addr != 0 && errno != EIO && errno != ESRCH)
798 perror("ptrace: umoven");
799 return -1;
800 }
Wichert Akkerman5daa0281999-03-15 19:49:42 +0000801 started = 1;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000802 memcpy(laddr, &u.x[n], m = MIN(sizeof(long) - n, len));
803 addr += sizeof(long), laddr += m, len -= m;
804 }
805 while (len) {
Roland McGratheb9e2e82009-06-02 16:49:22 -0700806 errno = 0;
807 u.val = ptrace(PTRACE_PEEKDATA, pid, (char *) addr, 0);
808 if (errno) {
809 if (started && (errno==EPERM || errno==EIO)) {
810 /* Ran into 'end of memory' - stupid "printpath" */
811 return 0;
812 }
813 if (addr != 0 && errno != EIO && errno != ESRCH)
814 perror("ptrace: umoven");
815 return -1;
816 }
Wichert Akkerman5daa0281999-03-15 19:49:42 +0000817 started = 1;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000818 memcpy(laddr, u.x, m = MIN(sizeof(long), len));
819 addr += sizeof(long), laddr += m, len -= m;
820 }
821#endif /* LINUX */
822
823#ifdef SUNOS4
824 int pid = tcp->pid;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000825 int n;
826
827 while (len) {
828 n = MIN(len, PAGSIZ);
829 n = MIN(n, ((addr + PAGSIZ) & PAGMASK) - addr);
Roland McGratheb9e2e82009-06-02 16:49:22 -0700830 if (ptrace(PTRACE_READDATA, pid,
831 (char *) addr, len, laddr) < 0) {
832 if (errno != ESRCH) {
833 perror("umoven: ptrace(PTRACE_READDATA, ...)");
834 abort();
835 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000836 return -1;
837 }
838 len -= n;
839 addr += n;
840 laddr += n;
841 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000842#endif /* SUNOS4 */
843
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000844#ifdef USE_PROCFS
Wichert Akkermanea78f0f1999-11-29 15:34:02 +0000845#ifdef HAVE_MP_PROCFS
John Hughesaa09c6b2001-05-15 14:53:43 +0000846 int fd = tcp->pfd_as;
Wichert Akkerman9ce1a631999-08-29 23:15:07 +0000847#else
John Hughesaa09c6b2001-05-15 14:53:43 +0000848 int fd = tcp->pfd;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000849#endif
John Hughesaa09c6b2001-05-15 14:53:43 +0000850 lseek(fd, addr, SEEK_SET);
851 if (read(fd, laddr, len) == -1)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000852 return -1;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000853#endif /* USE_PROCFS */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000854
855 return 0;
856}
857
858/*
859 * like `umove' but make the additional effort of looking
860 * for a terminating zero byte.
861 */
862int
Denys Vlasenkoef2fbf82009-01-06 21:45:06 +0000863umovestr(struct tcb *tcp, long addr, int len, char *laddr)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000864{
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000865#ifdef USE_PROCFS
John Hughesaa09c6b2001-05-15 14:53:43 +0000866#ifdef HAVE_MP_PROCFS
867 int fd = tcp->pfd_as;
868#else
869 int fd = tcp->pfd;
870#endif
871 /* Some systems (e.g. FreeBSD) can be upset if we read off the
872 end of valid memory, avoid this by trying to read up
873 to page boundaries. But we don't know what a page is (and
874 getpagesize(2) (if it exists) doesn't necessarily return
875 hardware page size). Assume all pages >= 1024 (a-historical
876 I know) */
877
Denys Vlasenkob63256e2011-06-07 12:13:24 +0200878 int page = 1024; /* How to find this? */
John Hughesaa09c6b2001-05-15 14:53:43 +0000879 int move = page - (addr & (page - 1));
880 int left = len;
881
882 lseek(fd, addr, SEEK_SET);
883
884 while (left) {
Denys Vlasenko5d645812011-08-20 12:48:18 +0200885 if (move > left)
886 move = left;
887 move = read(fd, laddr, move);
888 if (move <= 0)
John Hughesaa09c6b2001-05-15 14:53:43 +0000889 return left != len ? 0 : -1;
Denys Vlasenko5d645812011-08-20 12:48:18 +0200890 if (memchr(laddr, 0, move))
891 break;
John Hughesaa09c6b2001-05-15 14:53:43 +0000892 left -= move;
893 laddr += move;
894 addr += move;
895 move = page;
896 }
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000897#else /* !USE_PROCFS */
Wichert Akkerman5daa0281999-03-15 19:49:42 +0000898 int started = 0;
Roland McGratheb9e2e82009-06-02 16:49:22 -0700899 int pid = tcp->pid;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000900 int i, n, m;
901 union {
902 long val;
903 char x[sizeof(long)];
904 } u;
905
906 if (addr & (sizeof(long) - 1)) {
907 /* addr not a multiple of sizeof(long) */
908 n = addr - (addr & -sizeof(long)); /* residue */
909 addr &= -sizeof(long); /* residue */
Roland McGratheb9e2e82009-06-02 16:49:22 -0700910 errno = 0;
911 u.val = ptrace(PTRACE_PEEKDATA, pid, (char *)addr, 0);
912 if (errno) {
913 if (started && (errno==EPERM || errno==EIO)) {
914 /* Ran into 'end of memory' - stupid "printpath" */
915 return 0;
916 }
917 if (addr != 0 && errno != EIO && errno != ESRCH)
918 perror("umovestr");
919 return -1;
920 }
Wichert Akkerman5daa0281999-03-15 19:49:42 +0000921 started = 1;
Denys Vlasenkob63256e2011-06-07 12:13:24 +0200922 memcpy(laddr, &u.x[n], m = MIN(sizeof(long)-n, len));
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000923 while (n & (sizeof(long) - 1))
924 if (u.x[n++] == '\0')
925 return 0;
926 addr += sizeof(long), laddr += m, len -= m;
927 }
928 while (len) {
Roland McGratheb9e2e82009-06-02 16:49:22 -0700929 errno = 0;
930 u.val = ptrace(PTRACE_PEEKDATA, pid, (char *)addr, 0);
931 if (errno) {
932 if (started && (errno==EPERM || errno==EIO)) {
933 /* Ran into 'end of memory' - stupid "printpath" */
934 return 0;
935 }
936 if (addr != 0 && errno != EIO && errno != ESRCH)
937 perror("umovestr");
938 return -1;
939 }
Wichert Akkerman5daa0281999-03-15 19:49:42 +0000940 started = 1;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000941 memcpy(laddr, u.x, m = MIN(sizeof(long), len));
942 for (i = 0; i < sizeof(long); i++)
943 if (u.x[i] == '\0')
944 return 0;
945
946 addr += sizeof(long), laddr += m, len -= m;
947 }
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000948#endif /* !USE_PROCFS */
John Hughesaa09c6b2001-05-15 14:53:43 +0000949 return 0;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000950}
951
952#ifdef LINUX
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +0000953# if !defined (SPARC) && !defined(SPARC64)
954# define PTRACE_WRITETEXT 101
955# define PTRACE_WRITEDATA 102
956# endif /* !SPARC && !SPARC64 */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000957#endif /* LINUX */
958
959#ifdef SUNOS4
960
961static int
Denys Vlasenko12014262011-05-30 14:00:14 +0200962uload(int cmd, int pid, long addr, int len, char *laddr)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000963{
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000964 int peek, poke;
965 int n, m;
966 union {
967 long val;
968 char x[sizeof(long)];
969 } u;
970
971 if (cmd == PTRACE_WRITETEXT) {
972 peek = PTRACE_PEEKTEXT;
973 poke = PTRACE_POKETEXT;
974 }
975 else {
976 peek = PTRACE_PEEKDATA;
977 poke = PTRACE_POKEDATA;
978 }
979 if (addr & (sizeof(long) - 1)) {
980 /* addr not a multiple of sizeof(long) */
981 n = addr - (addr & -sizeof(long)); /* residue */
982 addr &= -sizeof(long);
Roland McGratheb9e2e82009-06-02 16:49:22 -0700983 errno = 0;
984 u.val = ptrace(peek, pid, (char *) addr, 0);
985 if (errno) {
986 perror("uload: POKE");
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000987 return -1;
988 }
Roland McGratheb9e2e82009-06-02 16:49:22 -0700989 memcpy(&u.x[n], laddr, m = MIN(sizeof(long) - n, len));
990 if (ptrace(poke, pid, (char *)addr, u.val) < 0) {
991 perror("uload: POKE");
992 return -1;
993 }
994 addr += sizeof(long), laddr += m, len -= m;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000995 }
996 while (len) {
997 if (len < sizeof(long))
Roland McGratheb9e2e82009-06-02 16:49:22 -0700998 u.val = ptrace(peek, pid, (char *) addr, 0);
999 memcpy(u.x, laddr, m = MIN(sizeof(long), len));
1000 if (ptrace(poke, pid, (char *) addr, u.val) < 0) {
1001 perror("uload: POKE");
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001002 return -1;
1003 }
Roland McGratheb9e2e82009-06-02 16:49:22 -07001004 addr += sizeof(long), laddr += m, len -= m;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001005 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001006 return 0;
1007}
1008
Roland McGratheb9e2e82009-06-02 16:49:22 -07001009int
Denys Vlasenko12014262011-05-30 14:00:14 +02001010tload(int pid, int addr, int len, char *laddr)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001011{
Roland McGratheb9e2e82009-06-02 16:49:22 -07001012 return uload(PTRACE_WRITETEXT, pid, addr, len, laddr);
1013}
1014
1015int
Denys Vlasenko12014262011-05-30 14:00:14 +02001016dload(int pid, int addr, int len, char *laddr)
Roland McGratheb9e2e82009-06-02 16:49:22 -07001017{
1018 return uload(PTRACE_WRITEDATA, pid, addr, len, laddr);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001019}
1020
1021#endif /* SUNOS4 */
1022
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001023#ifndef USE_PROCFS
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001024
1025int
Denys Vlasenko12014262011-05-30 14:00:14 +02001026upeek(struct tcb *tcp, long off, long *res)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001027{
1028 long val;
1029
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001030# ifdef SUNOS4_KERNEL_ARCH_KLUDGE
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001031 {
1032 static int is_sun4m = -1;
1033 struct utsname name;
1034
1035 /* Round up the usual suspects. */
1036 if (is_sun4m == -1) {
1037 if (uname(&name) < 0) {
1038 perror("upeek: uname?");
1039 exit(1);
1040 }
1041 is_sun4m = strcmp(name.machine, "sun4m") == 0;
1042 if (is_sun4m) {
Roland McGrathd9f816f2004-09-04 03:39:20 +00001043 const struct xlat *x;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001044
1045 for (x = struct_user_offsets; x->str; x++)
1046 x->val += 1024;
1047 }
1048 }
1049 if (is_sun4m)
1050 off += 1024;
1051 }
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001052# endif /* SUNOS4_KERNEL_ARCH_KLUDGE */
Roland McGratheb9e2e82009-06-02 16:49:22 -07001053 errno = 0;
Denys Vlasenko732d1bf2008-12-17 19:21:59 +00001054 val = do_ptrace(PTRACE_PEEKUSER, tcp, (char *) off, 0);
Roland McGratheb9e2e82009-06-02 16:49:22 -07001055 if (val == -1 && errno) {
1056 if (errno != ESRCH) {
1057 char buf[60];
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001058 sprintf(buf, "upeek: ptrace(PTRACE_PEEKUSER,%d,%lu,0)", tcp->pid, off);
Roland McGratheb9e2e82009-06-02 16:49:22 -07001059 perror(buf);
1060 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001061 return -1;
Roland McGratheb9e2e82009-06-02 16:49:22 -07001062 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001063 *res = val;
1064 return 0;
1065}
1066
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001067#endif /* !USE_PROCFS */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001068
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001069void
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001070printcall(struct tcb *tcp)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001071{
Roland McGrath7a918832005-02-02 20:55:23 +00001072#define PRINTBADPC tprintf(sizeof(long) == 4 ? "[????????] " : \
1073 sizeof(long) == 8 ? "[????????????????] " : \
1074 NULL /* crash */)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001075
1076#ifdef LINUX
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001077# ifdef I386
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001078 long eip;
1079
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001080 if (upeek(tcp, 4*EIP, &eip) < 0) {
Roland McGrath7a918832005-02-02 20:55:23 +00001081 PRINTBADPC;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001082 return;
1083 }
1084 tprintf("[%08lx] ", eip);
Roland McGratheac26fc2005-02-02 02:48:53 +00001085
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001086# elif defined(S390) || defined(S390X)
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001087 long psw;
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001088 if (upeek(tcp, PT_PSWADDR, &psw) < 0) {
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001089 PRINTBADPC;
1090 return;
1091 }
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001092# ifdef S390
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001093 tprintf("[%08lx] ", psw);
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001094# elif S390X
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001095 tprintf("[%16lx] ", psw);
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001096# endif
Roland McGratheac26fc2005-02-02 02:48:53 +00001097
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001098# elif defined(X86_64)
Michal Ludvig0e035502002-09-23 15:41:01 +00001099 long rip;
1100
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001101 if (upeek(tcp, 8*RIP, &rip) < 0) {
Roland McGrath7a918832005-02-02 20:55:23 +00001102 PRINTBADPC;
Michal Ludvig0e035502002-09-23 15:41:01 +00001103 return;
1104 }
1105 tprintf("[%16lx] ", rip);
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001106# elif defined(IA64)
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00001107 long ip;
1108
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001109 if (upeek(tcp, PT_B0, &ip) < 0) {
Roland McGrath7a918832005-02-02 20:55:23 +00001110 PRINTBADPC;
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00001111 return;
1112 }
1113 tprintf("[%08lx] ", ip);
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001114# elif defined(POWERPC)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001115 long pc;
1116
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001117 if (upeek(tcp, sizeof(unsigned long)*PT_NIP, &pc) < 0) {
Andreas Schwabd69fa492010-07-12 21:39:57 +02001118 PRINTBADPC;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001119 return;
1120 }
Andreas Schwabd69fa492010-07-12 21:39:57 +02001121# ifdef POWERPC64
1122 tprintf("[%016lx] ", pc);
1123# else
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001124 tprintf("[%08lx] ", pc);
Andreas Schwabd69fa492010-07-12 21:39:57 +02001125# endif
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001126# elif defined(M68K)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001127 long pc;
1128
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001129 if (upeek(tcp, 4*PT_PC, &pc) < 0) {
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001130 tprintf("[????????] ");
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001131 return;
1132 }
1133 tprintf("[%08lx] ", pc);
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001134# elif defined(ALPHA)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001135 long pc;
1136
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001137 if (upeek(tcp, REG_PC, &pc) < 0) {
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001138 tprintf("[????????????????] ");
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001139 return;
1140 }
1141 tprintf("[%08lx] ", pc);
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001142# elif defined(SPARC) || defined(SPARC64)
Mike Frysinger8566c502009-10-12 11:05:14 -04001143 struct pt_regs regs;
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001144 if (ptrace(PTRACE_GETREGS, tcp->pid, (char *)&regs, 0) < 0) {
Roland McGrath7a918832005-02-02 20:55:23 +00001145 PRINTBADPC;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001146 return;
1147 }
Mike Frysinger8566c502009-10-12 11:05:14 -04001148# if defined(SPARC64)
1149 tprintf("[%08lx] ", regs.tpc);
1150# else
1151 tprintf("[%08lx] ", regs.pc);
1152# endif
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001153# elif defined(HPPA)
Wichert Akkermanc1652e22001-03-27 12:17:16 +00001154 long pc;
1155
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001156 if (upeek(tcp, PT_IAOQ0, &pc) < 0) {
1157 tprintf("[????????] ");
Wichert Akkermanc1652e22001-03-27 12:17:16 +00001158 return;
1159 }
1160 tprintf("[%08lx] ", pc);
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001161# elif defined(MIPS)
Wichert Akkerman75c422b2001-04-10 10:22:50 +00001162 long pc;
1163
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001164 if (upeek(tcp, REG_EPC, &pc) < 0) {
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001165 tprintf("[????????] ");
Wichert Akkerman75c422b2001-04-10 10:22:50 +00001166 return;
1167 }
1168 tprintf("[%08lx] ", pc);
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001169# elif defined(SH)
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001170 long pc;
Wichert Akkermanccef6372002-05-01 16:39:22 +00001171
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001172 if (upeek(tcp, 4*REG_PC, &pc) < 0) {
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001173 tprintf("[????????] ");
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001174 return;
1175 }
1176 tprintf("[%08lx] ", pc);
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001177# elif defined(SH64)
Roland McGrathe1e584b2003-06-02 19:18:58 +00001178 long pc;
1179
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001180 if (upeek(tcp, REG_PC, &pc) < 0) {
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001181 tprintf("[????????????????] ");
Roland McGrathe1e584b2003-06-02 19:18:58 +00001182 return;
1183 }
1184 tprintf("[%08lx] ", pc);
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001185# elif defined(ARM)
Roland McGrathef388682003-06-03 23:28:59 +00001186 long pc;
Roland McGrathe1e584b2003-06-02 19:18:58 +00001187
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001188 if (upeek(tcp, 4*15, &pc) < 0) {
Roland McGrath7a918832005-02-02 20:55:23 +00001189 PRINTBADPC;
Roland McGrathef388682003-06-03 23:28:59 +00001190 return;
1191 }
1192 tprintf("[%08lx] ", pc);
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00001193# elif defined(AVR32)
1194 long pc;
1195
1196 if (upeek(tcp, REG_PC, &pc) < 0) {
1197 tprintf("[????????] ");
1198 return;
1199 }
1200 tprintf("[%08lx] ", pc);
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001201# elif defined(BFIN)
Dmitry V. Levin87ea1f42008-11-10 22:21:41 +00001202 long pc;
1203
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001204 if (upeek(tcp, PT_PC, &pc) < 0) {
Dmitry V. Levin87ea1f42008-11-10 22:21:41 +00001205 PRINTBADPC;
1206 return;
1207 }
1208 tprintf("[%08lx] ", pc);
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001209#elif defined(CRISV10)
1210 long pc;
1211
Edgar E. Iglesiaseeb9ce32009-10-05 14:41:02 +00001212 if (upeek(tcp, 4*PT_IRP, &pc) < 0) {
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001213 PRINTBADPC;
1214 return;
1215 }
1216 tprintf("[%08lx] ", pc);
1217#elif defined(CRISV32)
1218 long pc;
1219
Edgar E. Iglesiaseeb9ce32009-10-05 14:41:02 +00001220 if (upeek(tcp, 4*PT_ERP, &pc) < 0) {
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001221 PRINTBADPC;
1222 return;
1223 }
1224 tprintf("[%08lx] ", pc);
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001225# endif /* architecture */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001226#endif /* LINUX */
1227
1228#ifdef SUNOS4
1229 struct regs regs;
1230
Roland McGratheb9e2e82009-06-02 16:49:22 -07001231 if (ptrace(PTRACE_GETREGS, tcp->pid, (char *) &regs, 0) < 0) {
1232 perror("printcall: ptrace(PTRACE_GETREGS, ...)");
Roland McGrath7a918832005-02-02 20:55:23 +00001233 PRINTBADPC;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001234 return;
1235 }
1236 tprintf("[%08x] ", regs.r_o7);
1237#endif /* SUNOS4 */
1238
1239#ifdef SVR4
1240 /* XXX */
Roland McGrath7a918832005-02-02 20:55:23 +00001241 PRINTBADPC;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001242#endif
1243
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001244#ifdef FREEBSD
1245 struct reg regs;
1246 pread(tcp->pfd_reg, &regs, sizeof(regs), 0);
1247 tprintf("[%08x] ", regs.r_eip);
1248#endif /* FREEBSD */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001249}
1250
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001251
1252/*
1253 * These #if's are huge, please indent them correctly.
1254 * It's easy to get confused otherwise.
1255 */
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001256#ifndef USE_PROCFS
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001257
Denys Vlasenkoe7c90242011-06-22 00:09:25 +02001258# ifdef LINUX
Roland McGrathd81f1d92003-01-09 06:53:34 +00001259
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001260# include "syscall.h"
Roland McGrath3291ef22008-05-20 00:34:34 +00001261
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001262# include <sys/syscall.h>
1263# ifndef CLONE_PTRACE
1264# define CLONE_PTRACE 0x00002000
1265# endif
1266# ifndef CLONE_VFORK
1267# define CLONE_VFORK 0x00004000
1268# endif
1269# ifndef CLONE_VM
1270# define CLONE_VM 0x00000100
1271# endif
1272# ifndef CLONE_STOPPED
1273# define CLONE_STOPPED 0x02000000
1274# endif
Roland McGrathd81f1d92003-01-09 06:53:34 +00001275
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001276# ifdef IA64
Roland McGrathd81f1d92003-01-09 06:53:34 +00001277
Roland McGrath08267b82004-02-20 22:56:43 +00001278/* We don't have fork()/vfork() syscalls on ia64 itself, but the ia32
1279 subsystem has them for x86... */
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001280# define SYS_fork 2
1281# define SYS_vfork 190
Roland McGrath08267b82004-02-20 22:56:43 +00001282
Roland McGrathd81f1d92003-01-09 06:53:34 +00001283typedef unsigned long *arg_setup_state;
1284
1285static int
1286arg_setup(struct tcb *tcp, arg_setup_state *state)
1287{
Jan Kratochvil1f942712008-08-06 21:38:52 +00001288 unsigned long cfm, sof, sol;
1289 long bsp;
Roland McGrathd81f1d92003-01-09 06:53:34 +00001290
Jan Kratochvil1f942712008-08-06 21:38:52 +00001291 if (ia32) {
1292 /* Satisfy a false GCC warning. */
1293 *state = NULL;
Roland McGrath08267b82004-02-20 22:56:43 +00001294 return 0;
Jan Kratochvil1f942712008-08-06 21:38:52 +00001295 }
Roland McGrath08267b82004-02-20 22:56:43 +00001296
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001297 if (upeek(tcp, PT_AR_BSP, &bsp) < 0)
Roland McGrathd81f1d92003-01-09 06:53:34 +00001298 return -1;
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001299 if (upeek(tcp, PT_CFM, (long *) &cfm) < 0)
Roland McGrathd81f1d92003-01-09 06:53:34 +00001300 return -1;
1301
1302 sof = (cfm >> 0) & 0x7f;
1303 sol = (cfm >> 7) & 0x7f;
Jan Kratochvil1f942712008-08-06 21:38:52 +00001304 bsp = (long) ia64_rse_skip_regs((unsigned long *) bsp, -sof + sol);
Roland McGrathd81f1d92003-01-09 06:53:34 +00001305
Jan Kratochvil1f942712008-08-06 21:38:52 +00001306 *state = (unsigned long *) bsp;
Roland McGrathd81f1d92003-01-09 06:53:34 +00001307 return 0;
1308}
1309
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001310# define arg_finish_change(tcp, state) 0
Roland McGrathd81f1d92003-01-09 06:53:34 +00001311
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001312# ifdef SYS_fork
Roland McGrathd81f1d92003-01-09 06:53:34 +00001313static int
Denys Vlasenko12014262011-05-30 14:00:14 +02001314get_arg0(struct tcb *tcp, arg_setup_state *state, long *valp)
Roland McGrathd81f1d92003-01-09 06:53:34 +00001315{
Roland McGrath08267b82004-02-20 22:56:43 +00001316 int ret;
1317
1318 if (ia32)
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001319 ret = upeek(tcp, PT_R11, valp);
Roland McGrath08267b82004-02-20 22:56:43 +00001320 else
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001321 ret = umoven(tcp,
Roland McGrath08267b82004-02-20 22:56:43 +00001322 (unsigned long) ia64_rse_skip_regs(*state, 0),
1323 sizeof(long), (void *) valp);
1324 return ret;
Roland McGrathd81f1d92003-01-09 06:53:34 +00001325}
1326
1327static int
Denys Vlasenko12014262011-05-30 14:00:14 +02001328get_arg1(struct tcb *tcp, arg_setup_state *state, long *valp)
Roland McGrathd81f1d92003-01-09 06:53:34 +00001329{
Roland McGrath08267b82004-02-20 22:56:43 +00001330 int ret;
1331
1332 if (ia32)
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001333 ret = upeek(tcp, PT_R9, valp);
Roland McGrath08267b82004-02-20 22:56:43 +00001334 else
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001335 ret = umoven(tcp,
Roland McGrath08267b82004-02-20 22:56:43 +00001336 (unsigned long) ia64_rse_skip_regs(*state, 1),
1337 sizeof(long), (void *) valp);
1338 return ret;
Roland McGrathd81f1d92003-01-09 06:53:34 +00001339}
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001340# endif
Roland McGrathd81f1d92003-01-09 06:53:34 +00001341
1342static int
Denys Vlasenko12014262011-05-30 14:00:14 +02001343set_arg0(struct tcb *tcp, arg_setup_state *state, long val)
Roland McGrathd81f1d92003-01-09 06:53:34 +00001344{
Roland McGrath08267b82004-02-20 22:56:43 +00001345 int req = PTRACE_POKEDATA;
1346 void *ap;
1347
1348 if (ia32) {
1349 ap = (void *) (intptr_t) PT_R11; /* r11 == EBX */
1350 req = PTRACE_POKEUSER;
1351 } else
1352 ap = ia64_rse_skip_regs(*state, 0);
Roland McGratheb9e2e82009-06-02 16:49:22 -07001353 errno = 0;
1354 ptrace(req, tcp->pid, ap, val);
1355 return errno ? -1 : 0;
Roland McGrathd81f1d92003-01-09 06:53:34 +00001356}
1357
1358static int
Denys Vlasenko12014262011-05-30 14:00:14 +02001359set_arg1(struct tcb *tcp, arg_setup_state *state, long val)
Roland McGrathd81f1d92003-01-09 06:53:34 +00001360{
Roland McGrath08267b82004-02-20 22:56:43 +00001361 int req = PTRACE_POKEDATA;
1362 void *ap;
1363
1364 if (ia32) {
1365 ap = (void *) (intptr_t) PT_R9; /* r9 == ECX */
1366 req = PTRACE_POKEUSER;
1367 } else
1368 ap = ia64_rse_skip_regs(*state, 1);
Roland McGratheb9e2e82009-06-02 16:49:22 -07001369 errno = 0;
1370 ptrace(req, tcp->pid, ap, val);
1371 return errno ? -1 : 0;
Roland McGrathd81f1d92003-01-09 06:53:34 +00001372}
1373
Roland McGrathb659f872008-07-18 01:19:36 +00001374/* ia64 does not return the input arguments from functions (and syscalls)
1375 according to ia64 RSE (Register Stack Engine) behavior. */
1376
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001377# define restore_arg0(tcp, state, val) ((void) (state), 0)
1378# define restore_arg1(tcp, state, val) ((void) (state), 0)
Roland McGrathb659f872008-07-18 01:19:36 +00001379
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001380# elif defined (SPARC) || defined (SPARC64)
Roland McGrathd81f1d92003-01-09 06:53:34 +00001381
Mike Frysinger8566c502009-10-12 11:05:14 -04001382typedef struct pt_regs arg_setup_state;
Roland McGrathd81f1d92003-01-09 06:53:34 +00001383
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001384# define arg_setup(tcp, state) \
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001385 (ptrace(PTRACE_GETREGS, tcp->pid, (char *) (state), 0))
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001386# define arg_finish_change(tcp, state) \
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001387 (ptrace(PTRACE_SETREGS, tcp->pid, (char *) (state), 0))
Roland McGrathd81f1d92003-01-09 06:53:34 +00001388
Mike Frysinger8566c502009-10-12 11:05:14 -04001389# define get_arg0(tcp, state, valp) (*(valp) = (state)->u_regs[U_REG_O0], 0)
1390# define get_arg1(tcp, state, valp) (*(valp) = (state)->u_regs[U_REG_O1], 0)
1391# define set_arg0(tcp, state, val) ((state)->u_regs[U_REG_O0] = (val), 0)
1392# define set_arg1(tcp, state, val) ((state)->u_regs[U_REG_O1] = (val), 0)
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001393# define restore_arg0(tcp, state, val) 0
Roland McGrathd81f1d92003-01-09 06:53:34 +00001394
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001395# else /* other architectures */
Roland McGrathd81f1d92003-01-09 06:53:34 +00001396
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001397# if defined S390 || defined S390X
Roland McGrath7b308222003-01-20 09:04:36 +00001398/* Note: this is only true for the `clone' system call, which handles
1399 arguments specially. We could as well say that its first two arguments
1400 are swapped relative to other architectures, but that would just be
1401 another #ifdef in the calls. */
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001402# define arg0_offset PT_GPR3
1403# define arg1_offset PT_ORIGGPR2
1404# define restore_arg0(tcp, state, val) ((void) (state), 0)
1405# define restore_arg1(tcp, state, val) ((void) (state), 0)
1406# define arg0_index 1
1407# define arg1_index 0
1408# elif defined (ALPHA) || defined (MIPS)
1409# define arg0_offset REG_A0
1410# define arg1_offset (REG_A0+1)
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00001411# elif defined (AVR32)
1412# define arg0_offset (REG_R12)
1413# define arg1_offset (REG_R11)
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001414# elif defined (POWERPC)
1415# define arg0_offset (sizeof(unsigned long)*PT_R3)
1416# define arg1_offset (sizeof(unsigned long)*PT_R4)
1417# define restore_arg0(tcp, state, val) ((void) (state), 0)
1418# elif defined (HPPA)
1419# define arg0_offset PT_GR26
1420# define arg1_offset (PT_GR26-4)
1421# elif defined (X86_64)
1422# define arg0_offset ((long)(8*(current_personality ? RBX : RDI)))
1423# define arg1_offset ((long)(8*(current_personality ? RCX : RSI)))
1424# elif defined (SH)
1425# define arg0_offset (4*(REG_REG0+4))
1426# define arg1_offset (4*(REG_REG0+5))
1427# elif defined (SH64)
1428 /* ABI defines arg0 & 1 in r2 & r3 */
1429# define arg0_offset (REG_OFFSET+16)
1430# define arg1_offset (REG_OFFSET+24)
1431# define restore_arg0(tcp, state, val) 0
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001432# elif defined CRISV10 || defined CRISV32
1433# define arg0_offset (4*PT_R11)
1434# define arg1_offset (4*PT_ORIG_R10)
1435# define restore_arg0(tcp, state, val) 0
1436# define restore_arg1(tcp, state, val) 0
1437# define arg0_index 1
1438# define arg1_index 0
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001439# else
1440# define arg0_offset 0
1441# define arg1_offset 4
1442# if defined ARM
1443# define restore_arg0(tcp, state, val) 0
1444# endif
1445# endif
Roland McGrathd81f1d92003-01-09 06:53:34 +00001446
1447typedef int arg_setup_state;
1448
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001449# define arg_setup(tcp, state) (0)
1450# define arg_finish_change(tcp, state) 0
1451# define get_arg0(tcp, cookie, valp) \
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001452 (upeek((tcp), arg0_offset, (valp)))
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001453# define get_arg1(tcp, cookie, valp) \
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001454 (upeek((tcp), arg1_offset, (valp)))
Roland McGrathd81f1d92003-01-09 06:53:34 +00001455
1456static int
Denys Vlasenko12014262011-05-30 14:00:14 +02001457set_arg0(struct tcb *tcp, void *cookie, long val)
Roland McGrathd81f1d92003-01-09 06:53:34 +00001458{
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001459 return ptrace(PTRACE_POKEUSER, tcp->pid, (char*)arg0_offset, val);
Roland McGrathd81f1d92003-01-09 06:53:34 +00001460}
1461
1462static int
Denys Vlasenko12014262011-05-30 14:00:14 +02001463set_arg1(struct tcb *tcp, void *cookie, long val)
Roland McGrathd81f1d92003-01-09 06:53:34 +00001464{
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001465 return ptrace(PTRACE_POKEUSER, tcp->pid, (char*)arg1_offset, val);
Roland McGrathd81f1d92003-01-09 06:53:34 +00001466}
1467
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001468# endif /* architectures */
Roland McGrathd81f1d92003-01-09 06:53:34 +00001469
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001470# ifndef restore_arg0
1471# define restore_arg0(tcp, state, val) set_arg0((tcp), (state), (val))
1472# endif
1473# ifndef restore_arg1
1474# define restore_arg1(tcp, state, val) set_arg1((tcp), (state), (val))
1475# endif
Roland McGrathd81f1d92003-01-09 06:53:34 +00001476
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001477# ifndef arg0_index
1478# define arg0_index 0
1479# define arg1_index 1
1480# endif
Roland McGrath90d0afd2004-03-01 21:05:16 +00001481
Roland McGrathd81f1d92003-01-09 06:53:34 +00001482int
Denys Vlasenko418d66a2009-01-17 01:52:54 +00001483setbpt(struct tcb *tcp)
Roland McGrathd81f1d92003-01-09 06:53:34 +00001484{
Roland McGrath3291ef22008-05-20 00:34:34 +00001485 static int clone_scno[SUPPORTED_PERSONALITIES] = { SYS_clone };
Roland McGrathd81f1d92003-01-09 06:53:34 +00001486 arg_setup_state state;
1487
1488 if (tcp->flags & TCB_BPTSET) {
1489 fprintf(stderr, "PANIC: TCB already set in pid %u\n", tcp->pid);
1490 return -1;
1491 }
1492
Roland McGrath3291ef22008-05-20 00:34:34 +00001493 /*
1494 * It's a silly kludge to initialize this with a search at runtime.
1495 * But it's better than maintaining another magic thing in the
1496 * godforsaken tables.
1497 */
1498 if (clone_scno[current_personality] == 0) {
1499 int i;
1500 for (i = 0; i < nsyscalls; ++i)
1501 if (sysent[i].sys_func == sys_clone) {
1502 clone_scno[current_personality] = i;
1503 break;
1504 }
1505 }
1506
Roland McGrath76989d72005-06-07 23:21:31 +00001507 switch (known_scno(tcp)) {
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001508# ifdef SYS_vfork
Roland McGrath9383c6c2003-01-18 00:19:31 +00001509 case SYS_vfork:
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001510# endif
1511# ifdef SYS_fork
Roland McGrathd81f1d92003-01-09 06:53:34 +00001512 case SYS_fork:
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001513# endif
1514# if defined SYS_fork || defined SYS_vfork
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001515 if (arg_setup(tcp, &state) < 0
1516 || get_arg0(tcp, &state, &tcp->inst[0]) < 0
1517 || get_arg1(tcp, &state, &tcp->inst[1]) < 0
Roland McGrath3291ef22008-05-20 00:34:34 +00001518 || change_syscall(tcp, clone_scno[current_personality]) < 0
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001519 || set_arg0(tcp, &state, CLONE_PTRACE|SIGCHLD) < 0
1520 || set_arg1(tcp, &state, 0) < 0
1521 || arg_finish_change(tcp, &state) < 0)
Roland McGrathd81f1d92003-01-09 06:53:34 +00001522 return -1;
Roland McGrathc9dc3c12004-03-01 20:57:09 +00001523 tcp->u_arg[arg0_index] = CLONE_PTRACE|SIGCHLD;
1524 tcp->u_arg[arg1_index] = 0;
Roland McGrathd81f1d92003-01-09 06:53:34 +00001525 tcp->flags |= TCB_BPTSET;
1526 return 0;
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001527# endif
Roland McGrathd81f1d92003-01-09 06:53:34 +00001528
Denys Vlasenkoc133bf02011-06-23 21:57:54 +02001529 case SYS_clone: ;
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001530# ifdef SYS_clone2
Denys Vlasenkoc133bf02011-06-23 21:57:54 +02001531 case SYS_clone2: ;
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001532# endif
Jan Kratochvil8fc95752008-08-06 21:43:35 +00001533 /* ia64 calls directly `clone (CLONE_VFORK | CLONE_VM)'
1534 contrary to x86 SYS_vfork above. Even on x86 we turn the
1535 vfork semantics into plain fork - each application must not
1536 depend on the vfork specifics according to POSIX. We would
1537 hang waiting for the parent resume otherwise. We need to
1538 clear also CLONE_VM but only in the CLONE_VFORK case as
1539 otherwise we would break pthread_create. */
1540
Denys Vlasenkoc133bf02011-06-23 21:57:54 +02001541 long new_arg0 = (tcp->u_arg[arg0_index] | CLONE_PTRACE);
1542 if (new_arg0 & CLONE_VFORK)
1543 new_arg0 &= ~(unsigned long)(CLONE_VFORK | CLONE_VM);
1544 if (arg_setup(tcp, &state) < 0
1545 || set_arg0(tcp, &state, new_arg0) < 0
1546 || arg_finish_change(tcp, &state) < 0)
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00001547 return -1;
Roland McGrathd81f1d92003-01-09 06:53:34 +00001548 tcp->flags |= TCB_BPTSET;
Roland McGrathc9dc3c12004-03-01 20:57:09 +00001549 tcp->inst[0] = tcp->u_arg[arg0_index];
1550 tcp->inst[1] = tcp->u_arg[arg1_index];
Roland McGrathd81f1d92003-01-09 06:53:34 +00001551 return 0;
1552
1553 default:
1554 fprintf(stderr, "PANIC: setbpt for syscall %ld on %u???\n",
1555 tcp->scno, tcp->pid);
1556 break;
1557 }
1558
1559 return -1;
1560}
1561
1562int
Denys Vlasenko12014262011-05-30 14:00:14 +02001563clearbpt(struct tcb *tcp)
Roland McGrathd81f1d92003-01-09 06:53:34 +00001564{
1565 arg_setup_state state;
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001566 if (arg_setup(tcp, &state) < 0
1567 || restore_arg0(tcp, &state, tcp->inst[0]) < 0
1568 || restore_arg1(tcp, &state, tcp->inst[1]) < 0
1569 || arg_finish_change(tcp, &state))
Denys Vlasenkoc133bf02011-06-23 21:57:54 +02001570 if (errno != ESRCH)
1571 return -1;
Roland McGrathd81f1d92003-01-09 06:53:34 +00001572 tcp->flags &= ~TCB_BPTSET;
1573 return 0;
1574}
1575
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001576# else /* !defined LINUX */
Roland McGrathd81f1d92003-01-09 06:53:34 +00001577
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001578int
Denys Vlasenko12014262011-05-30 14:00:14 +02001579setbpt(struct tcb *tcp)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001580{
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001581# ifdef SUNOS4
1582# ifdef SPARC /* This code is slightly sparc specific */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001583
Wichert Akkermane6f876c1999-06-22 15:28:30 +00001584 struct regs regs;
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001585# define BPT 0x91d02001 /* ta 1 */
1586# define LOOP 0x10800000 /* ba 0 */
1587# define LOOPA 0x30800000 /* ba,a 0 */
1588# define NOP 0x01000000
1589# if LOOPA
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001590 static int loopdeloop[1] = {LOOPA};
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001591# else
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001592 static int loopdeloop[2] = {LOOP, NOP};
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001593# endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001594
1595 if (tcp->flags & TCB_BPTSET) {
1596 fprintf(stderr, "PANIC: TCB already set in pid %u\n", tcp->pid);
1597 return -1;
1598 }
Roland McGratheb9e2e82009-06-02 16:49:22 -07001599 if (ptrace(PTRACE_GETREGS, tcp->pid, (char *)&regs, 0) < 0) {
1600 perror("setbpt: ptrace(PTRACE_GETREGS, ...)");
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001601 return -1;
1602 }
1603 tcp->baddr = regs.r_o7 + 8;
Roland McGratheb9e2e82009-06-02 16:49:22 -07001604 if (ptrace(PTRACE_READTEXT, tcp->pid, (char *)tcp->baddr,
1605 sizeof tcp->inst, (char *)tcp->inst) < 0) {
1606 perror("setbpt: ptrace(PTRACE_READTEXT, ...)");
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001607 return -1;
1608 }
1609
1610 /*
1611 * XXX - BRUTAL MODE ON
1612 * We cannot set a real BPT in the child, since it will not be
1613 * traced at the moment it will reach the trap and would probably
1614 * die with a core dump.
1615 * Thus, we are force our way in by taking out two instructions
1616 * and insert an eternal loop in stead, in expectance of the SIGSTOP
1617 * generated by out PTRACE_ATTACH.
1618 * Of cause, if we evaporate ourselves in the middle of all this...
1619 */
Roland McGratheb9e2e82009-06-02 16:49:22 -07001620 if (ptrace(PTRACE_WRITETEXT, tcp->pid, (char *) tcp->baddr,
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001621 sizeof loopdeloop, (char *) loopdeloop) < 0) {
Roland McGratheb9e2e82009-06-02 16:49:22 -07001622 perror("setbpt: ptrace(PTRACE_WRITETEXT, ...)");
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001623 return -1;
1624 }
1625 tcp->flags |= TCB_BPTSET;
1626
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001627# endif /* SPARC */
1628# endif /* SUNOS4 */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001629
1630 return 0;
1631}
1632
1633int
Denys Vlasenko12014262011-05-30 14:00:14 +02001634clearbpt(struct tcb *tcp)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001635{
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001636# ifdef SUNOS4
1637# ifdef SPARC
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001638
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001639# if !LOOPA
Wichert Akkermane6f876c1999-06-22 15:28:30 +00001640 struct regs regs;
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001641# endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001642
1643 if (!(tcp->flags & TCB_BPTSET)) {
1644 fprintf(stderr, "PANIC: TCB not set in pid %u\n", tcp->pid);
1645 return -1;
1646 }
Roland McGratheb9e2e82009-06-02 16:49:22 -07001647 if (ptrace(PTRACE_WRITETEXT, tcp->pid, (char *) tcp->baddr,
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001648 sizeof tcp->inst, (char *) tcp->inst) < 0) {
Roland McGratheb9e2e82009-06-02 16:49:22 -07001649 perror("clearbtp: ptrace(PTRACE_WRITETEXT, ...)");
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001650 return -1;
1651 }
1652 tcp->flags &= ~TCB_BPTSET;
1653
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001654# if !LOOPA
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001655 /*
1656 * Since we don't have a single instruction breakpoint, we may have
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001657 * to adjust the program counter after removing our `breakpoint'.
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001658 */
Roland McGratheb9e2e82009-06-02 16:49:22 -07001659 if (ptrace(PTRACE_GETREGS, tcp->pid, (char *)&regs, 0) < 0) {
1660 perror("clearbpt: ptrace(PTRACE_GETREGS, ...)");
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001661 return -1;
1662 }
Roland McGratheb9e2e82009-06-02 16:49:22 -07001663 if ((regs.r_pc < tcp->baddr) ||
1664 (regs.r_pc > tcp->baddr + 4)) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001665 /* The breakpoint has not been reached yet */
1666 if (debug)
1667 fprintf(stderr,
1668 "NOTE: PC not at bpt (pc %#x baddr %#x)\n",
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001669 regs.r_pc, tcp->baddr);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001670 return 0;
1671 }
1672 if (regs.r_pc != tcp->baddr)
1673 if (debug)
1674 fprintf(stderr, "NOTE: PC adjusted (%#x -> %#x\n",
1675 regs.r_pc, tcp->baddr);
1676
1677 regs.r_pc = tcp->baddr;
Roland McGratheb9e2e82009-06-02 16:49:22 -07001678 if (ptrace(PTRACE_SETREGS, tcp->pid, (char *)&regs, 0) < 0) {
1679 perror("clearbpt: ptrace(PTRACE_SETREGS, ...)");
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001680 return -1;
1681 }
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001682# endif /* LOOPA */
1683# endif /* SPARC */
1684# endif /* SUNOS4 */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001685
1686 return 0;
1687}
1688
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001689# endif /* !defined LINUX */
Roland McGrathd81f1d92003-01-09 06:53:34 +00001690
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001691#endif /* !USE_PROCFS */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001692
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001693
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001694#ifdef SUNOS4
1695
1696static int
Denys Vlasenko12014262011-05-30 14:00:14 +02001697getex(struct tcb *tcp, struct exec *hdr)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001698{
1699 int n;
1700
1701 for (n = 0; n < sizeof *hdr; n += 4) {
1702 long res;
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001703 if (upeek(tcp, uoff(u_exdata) + n, &res) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001704 return -1;
1705 memcpy(((char *) hdr) + n, &res, 4);
1706 }
1707 if (debug) {
1708 fprintf(stderr, "[struct exec: magic: %o version %u Mach %o\n",
1709 hdr->a_magic, hdr->a_toolversion, hdr->a_machtype);
1710 fprintf(stderr, "Text %lu Data %lu Bss %lu Syms %lu Entry %#lx]\n",
1711 hdr->a_text, hdr->a_data, hdr->a_bss, hdr->a_syms, hdr->a_entry);
1712 }
1713 return 0;
1714}
1715
1716int
Denys Vlasenko12014262011-05-30 14:00:14 +02001717fixvfork(struct tcb *tcp)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001718{
1719 int pid = tcp->pid;
1720 /*
1721 * Change `vfork' in a freshly exec'ed dynamically linked
1722 * executable's (internal) symbol table to plain old `fork'
1723 */
1724
1725 struct exec hdr;
1726 struct link_dynamic dyn;
1727 struct link_dynamic_2 ld;
1728 char *strtab, *cp;
1729
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001730 if (getex(tcp, &hdr) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001731 return -1;
1732 if (!hdr.a_dynamic)
1733 return -1;
1734
1735 if (umove(tcp, (int) N_DATADDR(hdr), &dyn) < 0) {
1736 fprintf(stderr, "Cannot read DYNAMIC\n");
1737 return -1;
1738 }
1739 if (umove(tcp, (int) dyn.ld_un.ld_2, &ld) < 0) {
1740 fprintf(stderr, "Cannot read link_dynamic_2\n");
1741 return -1;
1742 }
Denys Vlasenko5d645812011-08-20 12:48:18 +02001743 strtab = malloc((unsigned)ld.ld_symb_size);
1744 if (strtab == NULL) {
Roland McGrath46100d02005-06-01 18:55:42 +00001745 fprintf(stderr, "out of memory\n");
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001746 return -1;
1747 }
Roland McGratheb9e2e82009-06-02 16:49:22 -07001748 if (umoven(tcp, (int)ld.ld_symbols+(int)N_TXTADDR(hdr),
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001749 (int)ld.ld_symb_size, strtab) < 0)
1750 goto err;
1751
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001752 for (cp = strtab; cp < strtab + ld.ld_symb_size; ) {
1753 if (strcmp(cp, "_vfork") == 0) {
1754 if (debug)
1755 fprintf(stderr, "fixvfork: FOUND _vfork\n");
1756 strcpy(cp, "_fork");
1757 break;
1758 }
1759 cp += strlen(cp)+1;
1760 }
1761 if (cp < strtab + ld.ld_symb_size)
1762 /*
1763 * Write entire symbol table back to avoid
1764 * memory alignment bugs in ptrace
1765 */
Roland McGratheb9e2e82009-06-02 16:49:22 -07001766 if (tload(pid, (int)ld.ld_symbols+(int)N_TXTADDR(hdr),
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001767 (int)ld.ld_symb_size, strtab) < 0)
1768 goto err;
1769
1770 free(strtab);
1771 return 0;
1772
1773err:
1774 free(strtab);
1775 return -1;
1776}
1777
1778#endif /* SUNOS4 */