blob: b2bf3e36bd451cdb4cf6fd725445e8d8f5f16463 [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;
443 int usehex = 0, c, i;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000444
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000445 if (xflag > 1)
446 usehex = 1;
447 else if (xflag) {
Dmitry V. Levina501f142008-11-10 23:19:13 +0000448 /* Check for presence of symbol which require
449 to hex-quote the whole string. */
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000450 for (i = 0; i < size; ++i) {
451 c = ustr[i];
Dmitry V. Levina501f142008-11-10 23:19:13 +0000452 /* Check for NUL-terminated string. */
453 if (len < 0) {
454 if (c == '\0')
455 break;
456 /* Quote at most size - 1 bytes. */
457 if (i == size - 1)
458 continue;
459 }
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000460 if (!isprint(c) && !isspace(c)) {
461 usehex = 1;
462 break;
463 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000464 }
465 }
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000466
467 *s++ = '\"';
468
469 if (usehex) {
Dmitry V. Levina501f142008-11-10 23:19:13 +0000470 /* Hex-quote the whole string. */
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000471 for (i = 0; i < size; ++i) {
472 c = ustr[i];
Dmitry V. Levina501f142008-11-10 23:19:13 +0000473 /* Check for NUL-terminated string. */
474 if (len < 0) {
475 if (c == '\0')
476 break;
477 /* Quote at most size - 1 bytes. */
478 if (i == size - 1)
479 continue;
480 }
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000481 sprintf(s, "\\x%02x", c);
482 s += 4;
483 }
484 } else {
485 for (i = 0; i < size; ++i) {
486 c = ustr[i];
Dmitry V. Levina501f142008-11-10 23:19:13 +0000487 /* Check for NUL-terminated string. */
488 if (len < 0) {
489 if (c == '\0')
490 break;
491 /* Quote at most size - 1 bytes. */
492 if (i == size - 1)
493 continue;
494 }
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000495 switch (c) {
496 case '\"': case '\\':
497 *s++ = '\\';
498 *s++ = c;
499 break;
500 case '\f':
501 *s++ = '\\';
502 *s++ = 'f';
503 break;
504 case '\n':
505 *s++ = '\\';
506 *s++ = 'n';
507 break;
508 case '\r':
509 *s++ = '\\';
510 *s++ = 'r';
511 break;
512 case '\t':
513 *s++ = '\\';
514 *s++ = 't';
515 break;
516 case '\v':
517 *s++ = '\\';
518 *s++ = 'v';
519 break;
520 default:
521 if (isprint(c))
522 *s++ = c;
523 else if (i + 1 < size
524 && isdigit(ustr[i + 1])) {
525 sprintf(s, "\\%03o", c);
526 s += 4;
527 } else {
528 sprintf(s, "\\%o", c);
529 s += strlen(s);
530 }
531 break;
532 }
533 }
534 }
535
536 *s++ = '\"';
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000537 *s = '\0';
Roland McGrath6d970322007-11-01 23:53:59 +0000538
539 /* Return nonzero if the string was unterminated. */
540 return i == size;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000541}
542
Dmitry V. Levina501f142008-11-10 23:19:13 +0000543/*
544 * Print path string specified by address `addr' and length `n'.
545 * If path length exceeds `n', append `...' to the output.
546 */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000547void
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000548printpathn(struct tcb *tcp, long addr, int n)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000549{
Dmitry V. Levina501f142008-11-10 23:19:13 +0000550 if (!addr) {
Roland McGrath371ed8f2005-02-06 01:55:07 +0000551 tprintf("NULL");
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000552 return;
553 }
554
Dmitry V. Levina501f142008-11-10 23:19:13 +0000555 /* Cap path length to the path buffer size,
556 and NUL-terminate the buffer. */
557 if (n > sizeof path - 1)
558 n = sizeof path - 1;
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000559 path[n] = '\0';
Dmitry V. Levina501f142008-11-10 23:19:13 +0000560
561 /* Fetch one byte more to find out whether path length > n. */
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000562 if (umovestr(tcp, addr, n + 1, path) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000563 tprintf("%#lx", addr);
564 else {
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000565 static char outstr[4*(sizeof path - 1) + sizeof "\"...\""];
Denys Vlasenko52845572011-08-31 12:07:38 +0200566 const char *fmt;
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000567 int trunc = (path[n] != '\0');
568
569 if (trunc)
570 path[n] = '\0';
Denys Vlasenko52845572011-08-31 12:07:38 +0200571 string_quote(path, outstr, -1, n + 1);
572 fmt = "%s";
Dmitry V. Levina501f142008-11-10 23:19:13 +0000573 if (trunc)
Denys Vlasenko52845572011-08-31 12:07:38 +0200574 fmt = "%s...";
575 tprintf(fmt, outstr);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000576 }
577}
578
579void
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000580printpath(struct tcb *tcp, long addr)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000581{
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000582 printpathn(tcp, addr, sizeof path - 1);
583}
584
Dmitry V. Levina501f142008-11-10 23:19:13 +0000585/*
586 * Print string specified by address `addr' and length `len'.
587 * If `len' < 0, treat the string as a NUL-terminated string.
588 * If string length exceeds `max_strlen', append `...' to the output.
589 */
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000590void
591printstr(struct tcb *tcp, long addr, int len)
592{
593 static char *str = NULL;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000594 static char *outstr;
Roland McGrath6d970322007-11-01 23:53:59 +0000595 int size;
Denys Vlasenko52845572011-08-31 12:07:38 +0200596 const char *fmt;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000597
598 if (!addr) {
599 tprintf("NULL");
600 return;
601 }
Dmitry V. Levina501f142008-11-10 23:19:13 +0000602 /* Allocate static buffers if they are not allocated yet. */
603 if (!str)
604 str = malloc(max_strlen + 1);
605 if (!outstr)
606 outstr = malloc(4 * max_strlen + sizeof "\"...\"");
607 if (!str || !outstr) {
608 fprintf(stderr, "out of memory\n");
609 tprintf("%#lx", addr);
610 return;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000611 }
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000612
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000613 if (len < 0) {
Dmitry V. Levina501f142008-11-10 23:19:13 +0000614 /*
615 * Treat as a NUL-terminated string: fetch one byte more
616 * because string_quote() quotes one byte less.
617 */
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000618 size = max_strlen + 1;
Dmitry V. Levina501f142008-11-10 23:19:13 +0000619 str[max_strlen] = '\0';
Denys Vlasenko52845572011-08-31 12:07:38 +0200620 /* FIXME! umovestr can overwrite the '\0' stored above??? */
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000621 if (umovestr(tcp, addr, size, str) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000622 tprintf("%#lx", addr);
623 return;
624 }
625 }
626 else {
Dmitry V. Levina501f142008-11-10 23:19:13 +0000627 size = MIN(len, max_strlen);
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000628 if (umoven(tcp, addr, size, str) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000629 tprintf("%#lx", addr);
630 return;
631 }
632 }
633
Denys Vlasenko52845572011-08-31 12:07:38 +0200634 fmt = "%s";
Dmitry V. Levina501f142008-11-10 23:19:13 +0000635 if (string_quote(str, outstr, len, size) &&
636 (len < 0 || len > max_strlen))
Denys Vlasenko52845572011-08-31 12:07:38 +0200637 fmt = "%s...";
Roland McGratha503dcf2007-08-02 02:06:26 +0000638
Denys Vlasenko52845572011-08-31 12:07:38 +0200639 tprintf(fmt, outstr);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000640}
641
John Hughes1d08dcf2001-07-10 13:48:44 +0000642#if HAVE_SYS_UIO_H
643void
Denys Vlasenko12014262011-05-30 14:00:14 +0200644dumpiov(struct tcb *tcp, int len, long addr)
John Hughes1d08dcf2001-07-10 13:48:44 +0000645{
Dmitry V. Levin4ebb4e32006-12-13 17:08:08 +0000646#if defined(LINUX) && SUPPORTED_PERSONALITIES > 1
647 union {
648 struct { u_int32_t base; u_int32_t len; } *iov32;
649 struct { u_int64_t base; u_int64_t len; } *iov64;
650 } iovu;
651#define iov iovu.iov64
652#define sizeof_iov \
653 (personality_wordsize[current_personality] == 4 \
654 ? sizeof(*iovu.iov32) : sizeof(*iovu.iov64))
655#define iov_iov_base(i) \
656 (personality_wordsize[current_personality] == 4 \
657 ? (u_int64_t) iovu.iov32[i].base : iovu.iov64[i].base)
658#define iov_iov_len(i) \
659 (personality_wordsize[current_personality] == 4 \
660 ? (u_int64_t) iovu.iov32[i].len : iovu.iov64[i].len)
661#else
John Hughes1d08dcf2001-07-10 13:48:44 +0000662 struct iovec *iov;
Dmitry V. Levin4ebb4e32006-12-13 17:08:08 +0000663#define sizeof_iov sizeof(*iov)
664#define iov_iov_base(i) iov[i].iov_base
665#define iov_iov_len(i) iov[i].iov_len
666#endif
John Hughes1d08dcf2001-07-10 13:48:44 +0000667 int i;
Roland McGrathaa524c82005-06-01 19:22:06 +0000668 unsigned long size;
John Hughes1d08dcf2001-07-10 13:48:44 +0000669
Dmitry V. Levin4ebb4e32006-12-13 17:08:08 +0000670 size = sizeof_iov * (unsigned long) len;
671 if (size / sizeof_iov != len
672 || (iov = malloc(size)) == NULL) {
Roland McGrathaa524c82005-06-01 19:22:06 +0000673 fprintf(stderr, "out of memory\n");
John Hughes1d08dcf2001-07-10 13:48:44 +0000674 return;
675 }
Roland McGrathaa524c82005-06-01 19:22:06 +0000676 if (umoven(tcp, addr, size, (char *) iov) >= 0) {
John Hughes1d08dcf2001-07-10 13:48:44 +0000677 for (i = 0; i < len; i++) {
Denys Vlasenkoadedb512008-12-30 18:47:55 +0000678 /* include the buffer number to make it easy to
679 * match up the trace with the source */
680 tprintf(" * %lu bytes in buffer %d\n",
681 (unsigned long)iov_iov_len(i), i);
682 dumpstr(tcp, (long) iov_iov_base(i),
683 iov_iov_len(i));
684 }
John Hughes1d08dcf2001-07-10 13:48:44 +0000685 }
686 free((char *) iov);
Dmitry V. Levin4ebb4e32006-12-13 17:08:08 +0000687#undef sizeof_iov
688#undef iov_iov_base
689#undef iov_iov_len
690#undef iov
John Hughes1d08dcf2001-07-10 13:48:44 +0000691}
692#endif
693
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000694void
Denys Vlasenko12014262011-05-30 14:00:14 +0200695dumpstr(struct tcb *tcp, long addr, int len)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000696{
697 static int strsize = -1;
698 static unsigned char *str;
699 static char outstr[80];
700 char *s;
701 int i, j;
702
703 if (strsize < len) {
Denys Vlasenko5d645812011-08-20 12:48:18 +0200704 free(str);
705 str = malloc(len);
706 if (str == NULL) {
Roland McGrath46100d02005-06-01 18:55:42 +0000707 fprintf(stderr, "out of memory\n");
Denys Vlasenkocfd364b2011-08-20 13:41:13 +0200708 /* BUG! On next call we may use NULL str! */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000709 return;
710 }
711 strsize = len;
712 }
713
714 if (umoven(tcp, addr, len, (char *) str) < 0)
715 return;
716
717 for (i = 0; i < len; i += 16) {
718 s = outstr;
719 sprintf(s, " | %05x ", i);
720 s += 9;
721 for (j = 0; j < 16; j++) {
722 if (j == 8)
723 *s++ = ' ';
724 if (i + j < len) {
725 sprintf(s, " %02x", str[i + j]);
726 s += 3;
727 }
728 else {
729 *s++ = ' '; *s++ = ' '; *s++ = ' ';
730 }
731 }
732 *s++ = ' '; *s++ = ' ';
733 for (j = 0; j < 16; j++) {
734 if (j == 8)
735 *s++ = ' ';
736 if (i + j < len) {
737 if (isprint(str[i + j]))
738 *s++ = str[i + j];
739 else
740 *s++ = '.';
741 }
742 else
743 *s++ = ' ';
744 }
745 tprintf("%s |\n", outstr);
746 }
747}
748
749#define PAGMASK (~(PAGSIZ - 1))
750/*
751 * move `len' bytes of data from process `pid'
752 * at address `addr' to our space at `laddr'
753 */
754int
Denys Vlasenkoef2fbf82009-01-06 21:45:06 +0000755umoven(struct tcb *tcp, long addr, int len, char *laddr)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000756{
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000757#ifdef LINUX
Roland McGratheb9e2e82009-06-02 16:49:22 -0700758 int pid = tcp->pid;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000759 int n, m;
Wichert Akkerman5daa0281999-03-15 19:49:42 +0000760 int started = 0;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000761 union {
762 long val;
763 char x[sizeof(long)];
764 } u;
765
766 if (addr & (sizeof(long) - 1)) {
767 /* addr not a multiple of sizeof(long) */
768 n = addr - (addr & -sizeof(long)); /* residue */
769 addr &= -sizeof(long); /* residue */
Roland McGratheb9e2e82009-06-02 16:49:22 -0700770 errno = 0;
771 u.val = ptrace(PTRACE_PEEKDATA, pid, (char *) addr, 0);
772 if (errno) {
773 if (started && (errno==EPERM || errno==EIO)) {
774 /* Ran into 'end of memory' - stupid "printpath" */
775 return 0;
776 }
777 /* But if not started, we had a bogus address. */
778 if (addr != 0 && errno != EIO && errno != ESRCH)
779 perror("ptrace: umoven");
780 return -1;
781 }
Wichert Akkerman5daa0281999-03-15 19:49:42 +0000782 started = 1;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000783 memcpy(laddr, &u.x[n], m = MIN(sizeof(long) - n, len));
784 addr += sizeof(long), laddr += m, len -= m;
785 }
786 while (len) {
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 if (addr != 0 && errno != EIO && errno != ESRCH)
795 perror("ptrace: umoven");
796 return -1;
797 }
Wichert Akkerman5daa0281999-03-15 19:49:42 +0000798 started = 1;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000799 memcpy(laddr, u.x, m = MIN(sizeof(long), len));
800 addr += sizeof(long), laddr += m, len -= m;
801 }
802#endif /* LINUX */
803
804#ifdef SUNOS4
805 int pid = tcp->pid;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000806 int n;
807
808 while (len) {
809 n = MIN(len, PAGSIZ);
810 n = MIN(n, ((addr + PAGSIZ) & PAGMASK) - addr);
Roland McGratheb9e2e82009-06-02 16:49:22 -0700811 if (ptrace(PTRACE_READDATA, pid,
812 (char *) addr, len, laddr) < 0) {
813 if (errno != ESRCH) {
814 perror("umoven: ptrace(PTRACE_READDATA, ...)");
815 abort();
816 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000817 return -1;
818 }
819 len -= n;
820 addr += n;
821 laddr += n;
822 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000823#endif /* SUNOS4 */
824
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000825#ifdef USE_PROCFS
Wichert Akkermanea78f0f1999-11-29 15:34:02 +0000826#ifdef HAVE_MP_PROCFS
John Hughesaa09c6b2001-05-15 14:53:43 +0000827 int fd = tcp->pfd_as;
Wichert Akkerman9ce1a631999-08-29 23:15:07 +0000828#else
John Hughesaa09c6b2001-05-15 14:53:43 +0000829 int fd = tcp->pfd;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000830#endif
John Hughesaa09c6b2001-05-15 14:53:43 +0000831 lseek(fd, addr, SEEK_SET);
832 if (read(fd, laddr, len) == -1)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000833 return -1;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000834#endif /* USE_PROCFS */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000835
836 return 0;
837}
838
839/*
840 * like `umove' but make the additional effort of looking
841 * for a terminating zero byte.
842 */
843int
Denys Vlasenkoef2fbf82009-01-06 21:45:06 +0000844umovestr(struct tcb *tcp, long addr, int len, char *laddr)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000845{
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000846#ifdef USE_PROCFS
John Hughesaa09c6b2001-05-15 14:53:43 +0000847#ifdef HAVE_MP_PROCFS
848 int fd = tcp->pfd_as;
849#else
850 int fd = tcp->pfd;
851#endif
852 /* Some systems (e.g. FreeBSD) can be upset if we read off the
853 end of valid memory, avoid this by trying to read up
854 to page boundaries. But we don't know what a page is (and
855 getpagesize(2) (if it exists) doesn't necessarily return
856 hardware page size). Assume all pages >= 1024 (a-historical
857 I know) */
858
Denys Vlasenkob63256e2011-06-07 12:13:24 +0200859 int page = 1024; /* How to find this? */
John Hughesaa09c6b2001-05-15 14:53:43 +0000860 int move = page - (addr & (page - 1));
861 int left = len;
862
863 lseek(fd, addr, SEEK_SET);
864
865 while (left) {
Denys Vlasenko5d645812011-08-20 12:48:18 +0200866 if (move > left)
867 move = left;
868 move = read(fd, laddr, move);
869 if (move <= 0)
John Hughesaa09c6b2001-05-15 14:53:43 +0000870 return left != len ? 0 : -1;
Denys Vlasenko5d645812011-08-20 12:48:18 +0200871 if (memchr(laddr, 0, move))
872 break;
John Hughesaa09c6b2001-05-15 14:53:43 +0000873 left -= move;
874 laddr += move;
875 addr += move;
876 move = page;
877 }
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000878#else /* !USE_PROCFS */
Wichert Akkerman5daa0281999-03-15 19:49:42 +0000879 int started = 0;
Roland McGratheb9e2e82009-06-02 16:49:22 -0700880 int pid = tcp->pid;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000881 int i, n, m;
882 union {
883 long val;
884 char x[sizeof(long)];
885 } u;
886
887 if (addr & (sizeof(long) - 1)) {
888 /* addr not a multiple of sizeof(long) */
889 n = addr - (addr & -sizeof(long)); /* residue */
890 addr &= -sizeof(long); /* residue */
Roland McGratheb9e2e82009-06-02 16:49:22 -0700891 errno = 0;
892 u.val = ptrace(PTRACE_PEEKDATA, pid, (char *)addr, 0);
893 if (errno) {
894 if (started && (errno==EPERM || errno==EIO)) {
895 /* Ran into 'end of memory' - stupid "printpath" */
896 return 0;
897 }
898 if (addr != 0 && errno != EIO && errno != ESRCH)
899 perror("umovestr");
900 return -1;
901 }
Wichert Akkerman5daa0281999-03-15 19:49:42 +0000902 started = 1;
Denys Vlasenkob63256e2011-06-07 12:13:24 +0200903 memcpy(laddr, &u.x[n], m = MIN(sizeof(long)-n, len));
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000904 while (n & (sizeof(long) - 1))
905 if (u.x[n++] == '\0')
906 return 0;
907 addr += sizeof(long), laddr += m, len -= m;
908 }
909 while (len) {
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;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000922 memcpy(laddr, u.x, m = MIN(sizeof(long), len));
923 for (i = 0; i < sizeof(long); i++)
924 if (u.x[i] == '\0')
925 return 0;
926
927 addr += sizeof(long), laddr += m, len -= m;
928 }
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000929#endif /* !USE_PROCFS */
John Hughesaa09c6b2001-05-15 14:53:43 +0000930 return 0;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000931}
932
933#ifdef LINUX
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +0000934# if !defined (SPARC) && !defined(SPARC64)
935# define PTRACE_WRITETEXT 101
936# define PTRACE_WRITEDATA 102
937# endif /* !SPARC && !SPARC64 */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000938#endif /* LINUX */
939
940#ifdef SUNOS4
941
942static int
Denys Vlasenko12014262011-05-30 14:00:14 +0200943uload(int cmd, int pid, long addr, int len, char *laddr)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000944{
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000945 int peek, poke;
946 int n, m;
947 union {
948 long val;
949 char x[sizeof(long)];
950 } u;
951
952 if (cmd == PTRACE_WRITETEXT) {
953 peek = PTRACE_PEEKTEXT;
954 poke = PTRACE_POKETEXT;
955 }
956 else {
957 peek = PTRACE_PEEKDATA;
958 poke = PTRACE_POKEDATA;
959 }
960 if (addr & (sizeof(long) - 1)) {
961 /* addr not a multiple of sizeof(long) */
962 n = addr - (addr & -sizeof(long)); /* residue */
963 addr &= -sizeof(long);
Roland McGratheb9e2e82009-06-02 16:49:22 -0700964 errno = 0;
965 u.val = ptrace(peek, pid, (char *) addr, 0);
966 if (errno) {
967 perror("uload: POKE");
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000968 return -1;
969 }
Roland McGratheb9e2e82009-06-02 16:49:22 -0700970 memcpy(&u.x[n], laddr, m = MIN(sizeof(long) - n, len));
971 if (ptrace(poke, pid, (char *)addr, u.val) < 0) {
972 perror("uload: POKE");
973 return -1;
974 }
975 addr += sizeof(long), laddr += m, len -= m;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000976 }
977 while (len) {
978 if (len < sizeof(long))
Roland McGratheb9e2e82009-06-02 16:49:22 -0700979 u.val = ptrace(peek, pid, (char *) addr, 0);
980 memcpy(u.x, laddr, m = MIN(sizeof(long), len));
981 if (ptrace(poke, pid, (char *) addr, u.val) < 0) {
982 perror("uload: POKE");
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000983 return -1;
984 }
Roland McGratheb9e2e82009-06-02 16:49:22 -0700985 addr += sizeof(long), laddr += m, len -= m;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000986 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000987 return 0;
988}
989
Roland McGratheb9e2e82009-06-02 16:49:22 -0700990int
Denys Vlasenko12014262011-05-30 14:00:14 +0200991tload(int pid, int addr, int len, char *laddr)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000992{
Roland McGratheb9e2e82009-06-02 16:49:22 -0700993 return uload(PTRACE_WRITETEXT, pid, addr, len, laddr);
994}
995
996int
Denys Vlasenko12014262011-05-30 14:00:14 +0200997dload(int pid, int addr, int len, char *laddr)
Roland McGratheb9e2e82009-06-02 16:49:22 -0700998{
999 return uload(PTRACE_WRITEDATA, pid, addr, len, laddr);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001000}
1001
1002#endif /* SUNOS4 */
1003
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001004#ifndef USE_PROCFS
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001005
1006int
Denys Vlasenko12014262011-05-30 14:00:14 +02001007upeek(struct tcb *tcp, long off, long *res)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001008{
1009 long val;
1010
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001011# ifdef SUNOS4_KERNEL_ARCH_KLUDGE
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001012 {
1013 static int is_sun4m = -1;
1014 struct utsname name;
1015
1016 /* Round up the usual suspects. */
1017 if (is_sun4m == -1) {
1018 if (uname(&name) < 0) {
1019 perror("upeek: uname?");
1020 exit(1);
1021 }
1022 is_sun4m = strcmp(name.machine, "sun4m") == 0;
1023 if (is_sun4m) {
Roland McGrathd9f816f2004-09-04 03:39:20 +00001024 const struct xlat *x;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001025
1026 for (x = struct_user_offsets; x->str; x++)
1027 x->val += 1024;
1028 }
1029 }
1030 if (is_sun4m)
1031 off += 1024;
1032 }
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001033# endif /* SUNOS4_KERNEL_ARCH_KLUDGE */
Roland McGratheb9e2e82009-06-02 16:49:22 -07001034 errno = 0;
Denys Vlasenko732d1bf2008-12-17 19:21:59 +00001035 val = do_ptrace(PTRACE_PEEKUSER, tcp, (char *) off, 0);
Roland McGratheb9e2e82009-06-02 16:49:22 -07001036 if (val == -1 && errno) {
1037 if (errno != ESRCH) {
1038 char buf[60];
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001039 sprintf(buf, "upeek: ptrace(PTRACE_PEEKUSER,%d,%lu,0)", tcp->pid, off);
Roland McGratheb9e2e82009-06-02 16:49:22 -07001040 perror(buf);
1041 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001042 return -1;
Roland McGratheb9e2e82009-06-02 16:49:22 -07001043 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001044 *res = val;
1045 return 0;
1046}
1047
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001048#endif /* !USE_PROCFS */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001049
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001050void
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001051printcall(struct tcb *tcp)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001052{
Roland McGrath7a918832005-02-02 20:55:23 +00001053#define PRINTBADPC tprintf(sizeof(long) == 4 ? "[????????] " : \
1054 sizeof(long) == 8 ? "[????????????????] " : \
1055 NULL /* crash */)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001056
1057#ifdef LINUX
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001058# ifdef I386
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001059 long eip;
1060
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001061 if (upeek(tcp, 4*EIP, &eip) < 0) {
Roland McGrath7a918832005-02-02 20:55:23 +00001062 PRINTBADPC;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001063 return;
1064 }
1065 tprintf("[%08lx] ", eip);
Roland McGratheac26fc2005-02-02 02:48:53 +00001066
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001067# elif defined(S390) || defined(S390X)
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001068 long psw;
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001069 if (upeek(tcp, PT_PSWADDR, &psw) < 0) {
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001070 PRINTBADPC;
1071 return;
1072 }
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001073# ifdef S390
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001074 tprintf("[%08lx] ", psw);
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001075# elif S390X
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001076 tprintf("[%16lx] ", psw);
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001077# endif
Roland McGratheac26fc2005-02-02 02:48:53 +00001078
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001079# elif defined(X86_64)
Michal Ludvig0e035502002-09-23 15:41:01 +00001080 long rip;
1081
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001082 if (upeek(tcp, 8*RIP, &rip) < 0) {
Roland McGrath7a918832005-02-02 20:55:23 +00001083 PRINTBADPC;
Michal Ludvig0e035502002-09-23 15:41:01 +00001084 return;
1085 }
1086 tprintf("[%16lx] ", rip);
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001087# elif defined(IA64)
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00001088 long ip;
1089
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001090 if (upeek(tcp, PT_B0, &ip) < 0) {
Roland McGrath7a918832005-02-02 20:55:23 +00001091 PRINTBADPC;
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00001092 return;
1093 }
1094 tprintf("[%08lx] ", ip);
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001095# elif defined(POWERPC)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001096 long pc;
1097
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001098 if (upeek(tcp, sizeof(unsigned long)*PT_NIP, &pc) < 0) {
Andreas Schwabd69fa492010-07-12 21:39:57 +02001099 PRINTBADPC;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001100 return;
1101 }
Andreas Schwabd69fa492010-07-12 21:39:57 +02001102# ifdef POWERPC64
1103 tprintf("[%016lx] ", pc);
1104# else
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001105 tprintf("[%08lx] ", pc);
Andreas Schwabd69fa492010-07-12 21:39:57 +02001106# endif
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001107# elif defined(M68K)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001108 long pc;
1109
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001110 if (upeek(tcp, 4*PT_PC, &pc) < 0) {
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001111 tprintf("[????????] ");
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001112 return;
1113 }
1114 tprintf("[%08lx] ", pc);
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001115# elif defined(ALPHA)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001116 long pc;
1117
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001118 if (upeek(tcp, REG_PC, &pc) < 0) {
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001119 tprintf("[????????????????] ");
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001120 return;
1121 }
1122 tprintf("[%08lx] ", pc);
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001123# elif defined(SPARC) || defined(SPARC64)
Mike Frysinger8566c502009-10-12 11:05:14 -04001124 struct pt_regs regs;
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001125 if (ptrace(PTRACE_GETREGS, tcp->pid, (char *)&regs, 0) < 0) {
Roland McGrath7a918832005-02-02 20:55:23 +00001126 PRINTBADPC;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001127 return;
1128 }
Mike Frysinger8566c502009-10-12 11:05:14 -04001129# if defined(SPARC64)
1130 tprintf("[%08lx] ", regs.tpc);
1131# else
1132 tprintf("[%08lx] ", regs.pc);
1133# endif
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001134# elif defined(HPPA)
Wichert Akkermanc1652e22001-03-27 12:17:16 +00001135 long pc;
1136
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001137 if (upeek(tcp, PT_IAOQ0, &pc) < 0) {
1138 tprintf("[????????] ");
Wichert Akkermanc1652e22001-03-27 12:17:16 +00001139 return;
1140 }
1141 tprintf("[%08lx] ", pc);
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001142# elif defined(MIPS)
Wichert Akkerman75c422b2001-04-10 10:22:50 +00001143 long pc;
1144
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001145 if (upeek(tcp, REG_EPC, &pc) < 0) {
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001146 tprintf("[????????] ");
Wichert Akkerman75c422b2001-04-10 10:22:50 +00001147 return;
1148 }
1149 tprintf("[%08lx] ", pc);
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001150# elif defined(SH)
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001151 long pc;
Wichert Akkermanccef6372002-05-01 16:39:22 +00001152
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001153 if (upeek(tcp, 4*REG_PC, &pc) < 0) {
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001154 tprintf("[????????] ");
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001155 return;
1156 }
1157 tprintf("[%08lx] ", pc);
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001158# elif defined(SH64)
Roland McGrathe1e584b2003-06-02 19:18:58 +00001159 long pc;
1160
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001161 if (upeek(tcp, REG_PC, &pc) < 0) {
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001162 tprintf("[????????????????] ");
Roland McGrathe1e584b2003-06-02 19:18:58 +00001163 return;
1164 }
1165 tprintf("[%08lx] ", pc);
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001166# elif defined(ARM)
Roland McGrathef388682003-06-03 23:28:59 +00001167 long pc;
Roland McGrathe1e584b2003-06-02 19:18:58 +00001168
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001169 if (upeek(tcp, 4*15, &pc) < 0) {
Roland McGrath7a918832005-02-02 20:55:23 +00001170 PRINTBADPC;
Roland McGrathef388682003-06-03 23:28:59 +00001171 return;
1172 }
1173 tprintf("[%08lx] ", pc);
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00001174# elif defined(AVR32)
1175 long pc;
1176
1177 if (upeek(tcp, REG_PC, &pc) < 0) {
1178 tprintf("[????????] ");
1179 return;
1180 }
1181 tprintf("[%08lx] ", pc);
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001182# elif defined(BFIN)
Dmitry V. Levin87ea1f42008-11-10 22:21:41 +00001183 long pc;
1184
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001185 if (upeek(tcp, PT_PC, &pc) < 0) {
Dmitry V. Levin87ea1f42008-11-10 22:21:41 +00001186 PRINTBADPC;
1187 return;
1188 }
1189 tprintf("[%08lx] ", pc);
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001190#elif defined(CRISV10)
1191 long pc;
1192
Edgar E. Iglesiaseeb9ce32009-10-05 14:41:02 +00001193 if (upeek(tcp, 4*PT_IRP, &pc) < 0) {
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001194 PRINTBADPC;
1195 return;
1196 }
1197 tprintf("[%08lx] ", pc);
1198#elif defined(CRISV32)
1199 long pc;
1200
Edgar E. Iglesiaseeb9ce32009-10-05 14:41:02 +00001201 if (upeek(tcp, 4*PT_ERP, &pc) < 0) {
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001202 PRINTBADPC;
1203 return;
1204 }
1205 tprintf("[%08lx] ", pc);
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001206# endif /* architecture */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001207#endif /* LINUX */
1208
1209#ifdef SUNOS4
1210 struct regs regs;
1211
Roland McGratheb9e2e82009-06-02 16:49:22 -07001212 if (ptrace(PTRACE_GETREGS, tcp->pid, (char *) &regs, 0) < 0) {
1213 perror("printcall: ptrace(PTRACE_GETREGS, ...)");
Roland McGrath7a918832005-02-02 20:55:23 +00001214 PRINTBADPC;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001215 return;
1216 }
1217 tprintf("[%08x] ", regs.r_o7);
1218#endif /* SUNOS4 */
1219
1220#ifdef SVR4
1221 /* XXX */
Roland McGrath7a918832005-02-02 20:55:23 +00001222 PRINTBADPC;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001223#endif
1224
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001225#ifdef FREEBSD
1226 struct reg regs;
1227 pread(tcp->pfd_reg, &regs, sizeof(regs), 0);
1228 tprintf("[%08x] ", regs.r_eip);
1229#endif /* FREEBSD */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001230}
1231
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001232
1233/*
1234 * These #if's are huge, please indent them correctly.
1235 * It's easy to get confused otherwise.
1236 */
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001237#ifndef USE_PROCFS
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001238
Denys Vlasenkoe7c90242011-06-22 00:09:25 +02001239# ifdef LINUX
Roland McGrathd81f1d92003-01-09 06:53:34 +00001240
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001241# include "syscall.h"
Roland McGrath3291ef22008-05-20 00:34:34 +00001242
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001243# include <sys/syscall.h>
1244# ifndef CLONE_PTRACE
1245# define CLONE_PTRACE 0x00002000
1246# endif
1247# ifndef CLONE_VFORK
1248# define CLONE_VFORK 0x00004000
1249# endif
1250# ifndef CLONE_VM
1251# define CLONE_VM 0x00000100
1252# endif
1253# ifndef CLONE_STOPPED
1254# define CLONE_STOPPED 0x02000000
1255# endif
Roland McGrathd81f1d92003-01-09 06:53:34 +00001256
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001257# ifdef IA64
Roland McGrathd81f1d92003-01-09 06:53:34 +00001258
Roland McGrath08267b82004-02-20 22:56:43 +00001259/* We don't have fork()/vfork() syscalls on ia64 itself, but the ia32
1260 subsystem has them for x86... */
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001261# define SYS_fork 2
1262# define SYS_vfork 190
Roland McGrath08267b82004-02-20 22:56:43 +00001263
Roland McGrathd81f1d92003-01-09 06:53:34 +00001264typedef unsigned long *arg_setup_state;
1265
1266static int
1267arg_setup(struct tcb *tcp, arg_setup_state *state)
1268{
Jan Kratochvil1f942712008-08-06 21:38:52 +00001269 unsigned long cfm, sof, sol;
1270 long bsp;
Roland McGrathd81f1d92003-01-09 06:53:34 +00001271
Jan Kratochvil1f942712008-08-06 21:38:52 +00001272 if (ia32) {
1273 /* Satisfy a false GCC warning. */
1274 *state = NULL;
Roland McGrath08267b82004-02-20 22:56:43 +00001275 return 0;
Jan Kratochvil1f942712008-08-06 21:38:52 +00001276 }
Roland McGrath08267b82004-02-20 22:56:43 +00001277
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001278 if (upeek(tcp, PT_AR_BSP, &bsp) < 0)
Roland McGrathd81f1d92003-01-09 06:53:34 +00001279 return -1;
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001280 if (upeek(tcp, PT_CFM, (long *) &cfm) < 0)
Roland McGrathd81f1d92003-01-09 06:53:34 +00001281 return -1;
1282
1283 sof = (cfm >> 0) & 0x7f;
1284 sol = (cfm >> 7) & 0x7f;
Jan Kratochvil1f942712008-08-06 21:38:52 +00001285 bsp = (long) ia64_rse_skip_regs((unsigned long *) bsp, -sof + sol);
Roland McGrathd81f1d92003-01-09 06:53:34 +00001286
Jan Kratochvil1f942712008-08-06 21:38:52 +00001287 *state = (unsigned long *) bsp;
Roland McGrathd81f1d92003-01-09 06:53:34 +00001288 return 0;
1289}
1290
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001291# define arg_finish_change(tcp, state) 0
Roland McGrathd81f1d92003-01-09 06:53:34 +00001292
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001293# ifdef SYS_fork
Roland McGrathd81f1d92003-01-09 06:53:34 +00001294static int
Denys Vlasenko12014262011-05-30 14:00:14 +02001295get_arg0(struct tcb *tcp, arg_setup_state *state, long *valp)
Roland McGrathd81f1d92003-01-09 06:53:34 +00001296{
Roland McGrath08267b82004-02-20 22:56:43 +00001297 int ret;
1298
1299 if (ia32)
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001300 ret = upeek(tcp, PT_R11, valp);
Roland McGrath08267b82004-02-20 22:56:43 +00001301 else
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001302 ret = umoven(tcp,
Roland McGrath08267b82004-02-20 22:56:43 +00001303 (unsigned long) ia64_rse_skip_regs(*state, 0),
1304 sizeof(long), (void *) valp);
1305 return ret;
Roland McGrathd81f1d92003-01-09 06:53:34 +00001306}
1307
1308static int
Denys Vlasenko12014262011-05-30 14:00:14 +02001309get_arg1(struct tcb *tcp, arg_setup_state *state, long *valp)
Roland McGrathd81f1d92003-01-09 06:53:34 +00001310{
Roland McGrath08267b82004-02-20 22:56:43 +00001311 int ret;
1312
1313 if (ia32)
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001314 ret = upeek(tcp, PT_R9, valp);
Roland McGrath08267b82004-02-20 22:56:43 +00001315 else
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001316 ret = umoven(tcp,
Roland McGrath08267b82004-02-20 22:56:43 +00001317 (unsigned long) ia64_rse_skip_regs(*state, 1),
1318 sizeof(long), (void *) valp);
1319 return ret;
Roland McGrathd81f1d92003-01-09 06:53:34 +00001320}
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001321# endif
Roland McGrathd81f1d92003-01-09 06:53:34 +00001322
1323static int
Denys Vlasenko12014262011-05-30 14:00:14 +02001324set_arg0(struct tcb *tcp, arg_setup_state *state, long val)
Roland McGrathd81f1d92003-01-09 06:53:34 +00001325{
Roland McGrath08267b82004-02-20 22:56:43 +00001326 int req = PTRACE_POKEDATA;
1327 void *ap;
1328
1329 if (ia32) {
1330 ap = (void *) (intptr_t) PT_R11; /* r11 == EBX */
1331 req = PTRACE_POKEUSER;
1332 } else
1333 ap = ia64_rse_skip_regs(*state, 0);
Roland McGratheb9e2e82009-06-02 16:49:22 -07001334 errno = 0;
1335 ptrace(req, tcp->pid, ap, val);
1336 return errno ? -1 : 0;
Roland McGrathd81f1d92003-01-09 06:53:34 +00001337}
1338
1339static int
Denys Vlasenko12014262011-05-30 14:00:14 +02001340set_arg1(struct tcb *tcp, arg_setup_state *state, long val)
Roland McGrathd81f1d92003-01-09 06:53:34 +00001341{
Roland McGrath08267b82004-02-20 22:56:43 +00001342 int req = PTRACE_POKEDATA;
1343 void *ap;
1344
1345 if (ia32) {
1346 ap = (void *) (intptr_t) PT_R9; /* r9 == ECX */
1347 req = PTRACE_POKEUSER;
1348 } else
1349 ap = ia64_rse_skip_regs(*state, 1);
Roland McGratheb9e2e82009-06-02 16:49:22 -07001350 errno = 0;
1351 ptrace(req, tcp->pid, ap, val);
1352 return errno ? -1 : 0;
Roland McGrathd81f1d92003-01-09 06:53:34 +00001353}
1354
Roland McGrathb659f872008-07-18 01:19:36 +00001355/* ia64 does not return the input arguments from functions (and syscalls)
1356 according to ia64 RSE (Register Stack Engine) behavior. */
1357
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001358# define restore_arg0(tcp, state, val) ((void) (state), 0)
1359# define restore_arg1(tcp, state, val) ((void) (state), 0)
Roland McGrathb659f872008-07-18 01:19:36 +00001360
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001361# elif defined (SPARC) || defined (SPARC64)
Roland McGrathd81f1d92003-01-09 06:53:34 +00001362
Mike Frysinger8566c502009-10-12 11:05:14 -04001363typedef struct pt_regs arg_setup_state;
Roland McGrathd81f1d92003-01-09 06:53:34 +00001364
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001365# define arg_setup(tcp, state) \
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001366 (ptrace(PTRACE_GETREGS, tcp->pid, (char *) (state), 0))
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001367# define arg_finish_change(tcp, state) \
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001368 (ptrace(PTRACE_SETREGS, tcp->pid, (char *) (state), 0))
Roland McGrathd81f1d92003-01-09 06:53:34 +00001369
Mike Frysinger8566c502009-10-12 11:05:14 -04001370# define get_arg0(tcp, state, valp) (*(valp) = (state)->u_regs[U_REG_O0], 0)
1371# define get_arg1(tcp, state, valp) (*(valp) = (state)->u_regs[U_REG_O1], 0)
1372# define set_arg0(tcp, state, val) ((state)->u_regs[U_REG_O0] = (val), 0)
1373# define set_arg1(tcp, state, val) ((state)->u_regs[U_REG_O1] = (val), 0)
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001374# define restore_arg0(tcp, state, val) 0
Roland McGrathd81f1d92003-01-09 06:53:34 +00001375
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001376# else /* other architectures */
Roland McGrathd81f1d92003-01-09 06:53:34 +00001377
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001378# if defined S390 || defined S390X
Roland McGrath7b308222003-01-20 09:04:36 +00001379/* Note: this is only true for the `clone' system call, which handles
1380 arguments specially. We could as well say that its first two arguments
1381 are swapped relative to other architectures, but that would just be
1382 another #ifdef in the calls. */
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001383# define arg0_offset PT_GPR3
1384# define arg1_offset PT_ORIGGPR2
1385# define restore_arg0(tcp, state, val) ((void) (state), 0)
1386# define restore_arg1(tcp, state, val) ((void) (state), 0)
1387# define arg0_index 1
1388# define arg1_index 0
1389# elif defined (ALPHA) || defined (MIPS)
1390# define arg0_offset REG_A0
1391# define arg1_offset (REG_A0+1)
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00001392# elif defined (AVR32)
1393# define arg0_offset (REG_R12)
1394# define arg1_offset (REG_R11)
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001395# elif defined (POWERPC)
1396# define arg0_offset (sizeof(unsigned long)*PT_R3)
1397# define arg1_offset (sizeof(unsigned long)*PT_R4)
1398# define restore_arg0(tcp, state, val) ((void) (state), 0)
1399# elif defined (HPPA)
1400# define arg0_offset PT_GR26
1401# define arg1_offset (PT_GR26-4)
1402# elif defined (X86_64)
1403# define arg0_offset ((long)(8*(current_personality ? RBX : RDI)))
1404# define arg1_offset ((long)(8*(current_personality ? RCX : RSI)))
1405# elif defined (SH)
1406# define arg0_offset (4*(REG_REG0+4))
1407# define arg1_offset (4*(REG_REG0+5))
1408# elif defined (SH64)
1409 /* ABI defines arg0 & 1 in r2 & r3 */
1410# define arg0_offset (REG_OFFSET+16)
1411# define arg1_offset (REG_OFFSET+24)
1412# define restore_arg0(tcp, state, val) 0
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001413# elif defined CRISV10 || defined CRISV32
1414# define arg0_offset (4*PT_R11)
1415# define arg1_offset (4*PT_ORIG_R10)
1416# define restore_arg0(tcp, state, val) 0
1417# define restore_arg1(tcp, state, val) 0
1418# define arg0_index 1
1419# define arg1_index 0
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001420# else
1421# define arg0_offset 0
1422# define arg1_offset 4
1423# if defined ARM
1424# define restore_arg0(tcp, state, val) 0
1425# endif
1426# endif
Roland McGrathd81f1d92003-01-09 06:53:34 +00001427
1428typedef int arg_setup_state;
1429
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001430# define arg_setup(tcp, state) (0)
1431# define arg_finish_change(tcp, state) 0
1432# define get_arg0(tcp, cookie, valp) \
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001433 (upeek((tcp), arg0_offset, (valp)))
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001434# define get_arg1(tcp, cookie, valp) \
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001435 (upeek((tcp), arg1_offset, (valp)))
Roland McGrathd81f1d92003-01-09 06:53:34 +00001436
1437static int
Denys Vlasenko12014262011-05-30 14:00:14 +02001438set_arg0(struct tcb *tcp, void *cookie, long val)
Roland McGrathd81f1d92003-01-09 06:53:34 +00001439{
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001440 return ptrace(PTRACE_POKEUSER, tcp->pid, (char*)arg0_offset, val);
Roland McGrathd81f1d92003-01-09 06:53:34 +00001441}
1442
1443static int
Denys Vlasenko12014262011-05-30 14:00:14 +02001444set_arg1(struct tcb *tcp, void *cookie, long val)
Roland McGrathd81f1d92003-01-09 06:53:34 +00001445{
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001446 return ptrace(PTRACE_POKEUSER, tcp->pid, (char*)arg1_offset, val);
Roland McGrathd81f1d92003-01-09 06:53:34 +00001447}
1448
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001449# endif /* architectures */
Roland McGrathd81f1d92003-01-09 06:53:34 +00001450
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001451# ifndef restore_arg0
1452# define restore_arg0(tcp, state, val) set_arg0((tcp), (state), (val))
1453# endif
1454# ifndef restore_arg1
1455# define restore_arg1(tcp, state, val) set_arg1((tcp), (state), (val))
1456# endif
Roland McGrathd81f1d92003-01-09 06:53:34 +00001457
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001458# ifndef arg0_index
1459# define arg0_index 0
1460# define arg1_index 1
1461# endif
Roland McGrath90d0afd2004-03-01 21:05:16 +00001462
Roland McGrathd81f1d92003-01-09 06:53:34 +00001463int
Denys Vlasenko418d66a2009-01-17 01:52:54 +00001464setbpt(struct tcb *tcp)
Roland McGrathd81f1d92003-01-09 06:53:34 +00001465{
Roland McGrath3291ef22008-05-20 00:34:34 +00001466 static int clone_scno[SUPPORTED_PERSONALITIES] = { SYS_clone };
Roland McGrathd81f1d92003-01-09 06:53:34 +00001467 arg_setup_state state;
1468
1469 if (tcp->flags & TCB_BPTSET) {
1470 fprintf(stderr, "PANIC: TCB already set in pid %u\n", tcp->pid);
1471 return -1;
1472 }
1473
Roland McGrath3291ef22008-05-20 00:34:34 +00001474 /*
1475 * It's a silly kludge to initialize this with a search at runtime.
1476 * But it's better than maintaining another magic thing in the
1477 * godforsaken tables.
1478 */
1479 if (clone_scno[current_personality] == 0) {
1480 int i;
1481 for (i = 0; i < nsyscalls; ++i)
1482 if (sysent[i].sys_func == sys_clone) {
1483 clone_scno[current_personality] = i;
1484 break;
1485 }
1486 }
1487
Roland McGrath76989d72005-06-07 23:21:31 +00001488 switch (known_scno(tcp)) {
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001489# ifdef SYS_vfork
Roland McGrath9383c6c2003-01-18 00:19:31 +00001490 case SYS_vfork:
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001491# endif
1492# ifdef SYS_fork
Roland McGrathd81f1d92003-01-09 06:53:34 +00001493 case SYS_fork:
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001494# endif
1495# if defined SYS_fork || defined SYS_vfork
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001496 if (arg_setup(tcp, &state) < 0
1497 || get_arg0(tcp, &state, &tcp->inst[0]) < 0
1498 || get_arg1(tcp, &state, &tcp->inst[1]) < 0
Roland McGrath3291ef22008-05-20 00:34:34 +00001499 || change_syscall(tcp, clone_scno[current_personality]) < 0
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001500 || set_arg0(tcp, &state, CLONE_PTRACE|SIGCHLD) < 0
1501 || set_arg1(tcp, &state, 0) < 0
1502 || arg_finish_change(tcp, &state) < 0)
Roland McGrathd81f1d92003-01-09 06:53:34 +00001503 return -1;
Roland McGrathc9dc3c12004-03-01 20:57:09 +00001504 tcp->u_arg[arg0_index] = CLONE_PTRACE|SIGCHLD;
1505 tcp->u_arg[arg1_index] = 0;
Roland McGrathd81f1d92003-01-09 06:53:34 +00001506 tcp->flags |= TCB_BPTSET;
1507 return 0;
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001508# endif
Roland McGrathd81f1d92003-01-09 06:53:34 +00001509
Denys Vlasenkoc133bf02011-06-23 21:57:54 +02001510 case SYS_clone: ;
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001511# ifdef SYS_clone2
Denys Vlasenkoc133bf02011-06-23 21:57:54 +02001512 case SYS_clone2: ;
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001513# endif
Jan Kratochvil8fc95752008-08-06 21:43:35 +00001514 /* ia64 calls directly `clone (CLONE_VFORK | CLONE_VM)'
1515 contrary to x86 SYS_vfork above. Even on x86 we turn the
1516 vfork semantics into plain fork - each application must not
1517 depend on the vfork specifics according to POSIX. We would
1518 hang waiting for the parent resume otherwise. We need to
1519 clear also CLONE_VM but only in the CLONE_VFORK case as
1520 otherwise we would break pthread_create. */
1521
Denys Vlasenkoc133bf02011-06-23 21:57:54 +02001522 long new_arg0 = (tcp->u_arg[arg0_index] | CLONE_PTRACE);
1523 if (new_arg0 & CLONE_VFORK)
1524 new_arg0 &= ~(unsigned long)(CLONE_VFORK | CLONE_VM);
1525 if (arg_setup(tcp, &state) < 0
1526 || set_arg0(tcp, &state, new_arg0) < 0
1527 || arg_finish_change(tcp, &state) < 0)
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00001528 return -1;
Roland McGrathd81f1d92003-01-09 06:53:34 +00001529 tcp->flags |= TCB_BPTSET;
Roland McGrathc9dc3c12004-03-01 20:57:09 +00001530 tcp->inst[0] = tcp->u_arg[arg0_index];
1531 tcp->inst[1] = tcp->u_arg[arg1_index];
Roland McGrathd81f1d92003-01-09 06:53:34 +00001532 return 0;
1533
1534 default:
1535 fprintf(stderr, "PANIC: setbpt for syscall %ld on %u???\n",
1536 tcp->scno, tcp->pid);
1537 break;
1538 }
1539
1540 return -1;
1541}
1542
1543int
Denys Vlasenko12014262011-05-30 14:00:14 +02001544clearbpt(struct tcb *tcp)
Roland McGrathd81f1d92003-01-09 06:53:34 +00001545{
1546 arg_setup_state state;
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001547 if (arg_setup(tcp, &state) < 0
1548 || restore_arg0(tcp, &state, tcp->inst[0]) < 0
1549 || restore_arg1(tcp, &state, tcp->inst[1]) < 0
1550 || arg_finish_change(tcp, &state))
Denys Vlasenkoc133bf02011-06-23 21:57:54 +02001551 if (errno != ESRCH)
1552 return -1;
Roland McGrathd81f1d92003-01-09 06:53:34 +00001553 tcp->flags &= ~TCB_BPTSET;
1554 return 0;
1555}
1556
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001557# else /* !defined LINUX */
Roland McGrathd81f1d92003-01-09 06:53:34 +00001558
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001559int
Denys Vlasenko12014262011-05-30 14:00:14 +02001560setbpt(struct tcb *tcp)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001561{
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001562# ifdef SUNOS4
1563# ifdef SPARC /* This code is slightly sparc specific */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001564
Wichert Akkermane6f876c1999-06-22 15:28:30 +00001565 struct regs regs;
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001566# define BPT 0x91d02001 /* ta 1 */
1567# define LOOP 0x10800000 /* ba 0 */
1568# define LOOPA 0x30800000 /* ba,a 0 */
1569# define NOP 0x01000000
1570# if LOOPA
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001571 static int loopdeloop[1] = {LOOPA};
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001572# else
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001573 static int loopdeloop[2] = {LOOP, NOP};
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001574# endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001575
1576 if (tcp->flags & TCB_BPTSET) {
1577 fprintf(stderr, "PANIC: TCB already set in pid %u\n", tcp->pid);
1578 return -1;
1579 }
Roland McGratheb9e2e82009-06-02 16:49:22 -07001580 if (ptrace(PTRACE_GETREGS, tcp->pid, (char *)&regs, 0) < 0) {
1581 perror("setbpt: ptrace(PTRACE_GETREGS, ...)");
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001582 return -1;
1583 }
1584 tcp->baddr = regs.r_o7 + 8;
Roland McGratheb9e2e82009-06-02 16:49:22 -07001585 if (ptrace(PTRACE_READTEXT, tcp->pid, (char *)tcp->baddr,
1586 sizeof tcp->inst, (char *)tcp->inst) < 0) {
1587 perror("setbpt: ptrace(PTRACE_READTEXT, ...)");
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001588 return -1;
1589 }
1590
1591 /*
1592 * XXX - BRUTAL MODE ON
1593 * We cannot set a real BPT in the child, since it will not be
1594 * traced at the moment it will reach the trap and would probably
1595 * die with a core dump.
1596 * Thus, we are force our way in by taking out two instructions
1597 * and insert an eternal loop in stead, in expectance of the SIGSTOP
1598 * generated by out PTRACE_ATTACH.
1599 * Of cause, if we evaporate ourselves in the middle of all this...
1600 */
Roland McGratheb9e2e82009-06-02 16:49:22 -07001601 if (ptrace(PTRACE_WRITETEXT, tcp->pid, (char *) tcp->baddr,
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001602 sizeof loopdeloop, (char *) loopdeloop) < 0) {
Roland McGratheb9e2e82009-06-02 16:49:22 -07001603 perror("setbpt: ptrace(PTRACE_WRITETEXT, ...)");
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001604 return -1;
1605 }
1606 tcp->flags |= TCB_BPTSET;
1607
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001608# endif /* SPARC */
1609# endif /* SUNOS4 */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001610
1611 return 0;
1612}
1613
1614int
Denys Vlasenko12014262011-05-30 14:00:14 +02001615clearbpt(struct tcb *tcp)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001616{
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001617# ifdef SUNOS4
1618# ifdef SPARC
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001619
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001620# if !LOOPA
Wichert Akkermane6f876c1999-06-22 15:28:30 +00001621 struct regs regs;
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001622# endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001623
1624 if (!(tcp->flags & TCB_BPTSET)) {
1625 fprintf(stderr, "PANIC: TCB not set in pid %u\n", tcp->pid);
1626 return -1;
1627 }
Roland McGratheb9e2e82009-06-02 16:49:22 -07001628 if (ptrace(PTRACE_WRITETEXT, tcp->pid, (char *) tcp->baddr,
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001629 sizeof tcp->inst, (char *) tcp->inst) < 0) {
Roland McGratheb9e2e82009-06-02 16:49:22 -07001630 perror("clearbtp: ptrace(PTRACE_WRITETEXT, ...)");
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001631 return -1;
1632 }
1633 tcp->flags &= ~TCB_BPTSET;
1634
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001635# if !LOOPA
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001636 /*
1637 * Since we don't have a single instruction breakpoint, we may have
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001638 * to adjust the program counter after removing our `breakpoint'.
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001639 */
Roland McGratheb9e2e82009-06-02 16:49:22 -07001640 if (ptrace(PTRACE_GETREGS, tcp->pid, (char *)&regs, 0) < 0) {
1641 perror("clearbpt: ptrace(PTRACE_GETREGS, ...)");
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001642 return -1;
1643 }
Roland McGratheb9e2e82009-06-02 16:49:22 -07001644 if ((regs.r_pc < tcp->baddr) ||
1645 (regs.r_pc > tcp->baddr + 4)) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001646 /* The breakpoint has not been reached yet */
1647 if (debug)
1648 fprintf(stderr,
1649 "NOTE: PC not at bpt (pc %#x baddr %#x)\n",
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001650 regs.r_pc, tcp->baddr);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001651 return 0;
1652 }
1653 if (regs.r_pc != tcp->baddr)
1654 if (debug)
1655 fprintf(stderr, "NOTE: PC adjusted (%#x -> %#x\n",
1656 regs.r_pc, tcp->baddr);
1657
1658 regs.r_pc = tcp->baddr;
Roland McGratheb9e2e82009-06-02 16:49:22 -07001659 if (ptrace(PTRACE_SETREGS, tcp->pid, (char *)&regs, 0) < 0) {
1660 perror("clearbpt: ptrace(PTRACE_SETREGS, ...)");
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001661 return -1;
1662 }
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001663# endif /* LOOPA */
1664# endif /* SPARC */
1665# endif /* SUNOS4 */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001666
1667 return 0;
1668}
1669
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001670# endif /* !defined LINUX */
Roland McGrathd81f1d92003-01-09 06:53:34 +00001671
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001672#endif /* !USE_PROCFS */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001673
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001674
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001675#ifdef SUNOS4
1676
1677static int
Denys Vlasenko12014262011-05-30 14:00:14 +02001678getex(struct tcb *tcp, struct exec *hdr)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001679{
1680 int n;
1681
1682 for (n = 0; n < sizeof *hdr; n += 4) {
1683 long res;
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001684 if (upeek(tcp, uoff(u_exdata) + n, &res) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001685 return -1;
1686 memcpy(((char *) hdr) + n, &res, 4);
1687 }
1688 if (debug) {
1689 fprintf(stderr, "[struct exec: magic: %o version %u Mach %o\n",
1690 hdr->a_magic, hdr->a_toolversion, hdr->a_machtype);
1691 fprintf(stderr, "Text %lu Data %lu Bss %lu Syms %lu Entry %#lx]\n",
1692 hdr->a_text, hdr->a_data, hdr->a_bss, hdr->a_syms, hdr->a_entry);
1693 }
1694 return 0;
1695}
1696
1697int
Denys Vlasenko12014262011-05-30 14:00:14 +02001698fixvfork(struct tcb *tcp)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001699{
1700 int pid = tcp->pid;
1701 /*
1702 * Change `vfork' in a freshly exec'ed dynamically linked
1703 * executable's (internal) symbol table to plain old `fork'
1704 */
1705
1706 struct exec hdr;
1707 struct link_dynamic dyn;
1708 struct link_dynamic_2 ld;
1709 char *strtab, *cp;
1710
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001711 if (getex(tcp, &hdr) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001712 return -1;
1713 if (!hdr.a_dynamic)
1714 return -1;
1715
1716 if (umove(tcp, (int) N_DATADDR(hdr), &dyn) < 0) {
1717 fprintf(stderr, "Cannot read DYNAMIC\n");
1718 return -1;
1719 }
1720 if (umove(tcp, (int) dyn.ld_un.ld_2, &ld) < 0) {
1721 fprintf(stderr, "Cannot read link_dynamic_2\n");
1722 return -1;
1723 }
Denys Vlasenko5d645812011-08-20 12:48:18 +02001724 strtab = malloc((unsigned)ld.ld_symb_size);
1725 if (strtab == NULL) {
Roland McGrath46100d02005-06-01 18:55:42 +00001726 fprintf(stderr, "out of memory\n");
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001727 return -1;
1728 }
Roland McGratheb9e2e82009-06-02 16:49:22 -07001729 if (umoven(tcp, (int)ld.ld_symbols+(int)N_TXTADDR(hdr),
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001730 (int)ld.ld_symb_size, strtab) < 0)
1731 goto err;
1732
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001733 for (cp = strtab; cp < strtab + ld.ld_symb_size; ) {
1734 if (strcmp(cp, "_vfork") == 0) {
1735 if (debug)
1736 fprintf(stderr, "fixvfork: FOUND _vfork\n");
1737 strcpy(cp, "_fork");
1738 break;
1739 }
1740 cp += strlen(cp)+1;
1741 }
1742 if (cp < strtab + ld.ld_symb_size)
1743 /*
1744 * Write entire symbol table back to avoid
1745 * memory alignment bugs in ptrace
1746 */
Roland McGratheb9e2e82009-06-02 16:49:22 -07001747 if (tload(pid, (int)ld.ld_symbols+(int)N_TXTADDR(hdr),
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001748 (int)ld.ld_symb_size, strtab) < 0)
1749 goto err;
1750
1751 free(strtab);
1752 return 0;
1753
1754err:
1755 free(strtab);
1756 return -1;
1757}
1758
1759#endif /* SUNOS4 */