blob: ec0b3cbc7fff688fbc40167f17f5907ad5ee0f6e [file] [log] [blame]
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001/*
2 * Copyright (c) 1991, 1992 Paul Kranenburg <pk@cs.few.eur.nl>
3 * Copyright (c) 1993 Branko Lankester <branko@hacktic.nl>
4 * Copyright (c) 1993, 1994, 1995, 1996 Rick Sladkey <jrs@world.std.com>
Wichert Akkerman4dc8a2a1999-12-23 14:20:14 +00005 * Copyright (c) 1996-1999 Wichert Akkerman <wichert@cistron.nl>
6 * Copyright (c) 1999 IBM Deutschland Entwicklung GmbH, IBM Corporation
7 * Linux for s390 port by D.J. Barrow
8 * <barrow_dj@mail.yahoo.com,djbarrow@de.ibm.com>
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00009 * All rights reserved.
10 *
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions
13 * are met:
14 * 1. Redistributions of source code must retain the above copyright
15 * notice, this list of conditions and the following disclaimer.
16 * 2. Redistributions in binary form must reproduce the above copyright
17 * notice, this list of conditions and the following disclaimer in the
18 * documentation and/or other materials provided with the distribution.
19 * 3. The name of the author may not be used to endorse or promote products
20 * derived from this software without specific prior written permission.
21 *
22 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
23 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
24 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
25 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
26 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
27 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
28 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
29 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
30 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
31 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32 *
33 * $Id$
34 */
35
36#include "defs.h"
37
Roland McGrathd81f1d92003-01-09 06:53:34 +000038#include <signal.h>
39#include <sys/syscall.h>
Wichert Akkerman76baf7c1999-02-19 00:21:36 +000040#include <sys/user.h>
41#include <sys/param.h>
42#include <fcntl.h>
John Hughes1d08dcf2001-07-10 13:48:44 +000043#if HAVE_SYS_UIO_H
44#include <sys/uio.h>
45#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +000046#ifdef SUNOS4
47#include <machine/reg.h>
48#include <a.out.h>
49#include <link.h>
50#endif /* SUNOS4 */
Wichert Akkerman36915a11999-07-13 15:45:02 +000051
Wichert Akkerman43a74822000-06-27 17:33:32 +000052#if defined(linux) && (__GLIBC__ < 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ < 1))
Wichert Akkerman36915a11999-07-13 15:45:02 +000053#include <linux/ptrace.h>
Roland McGrath1e85cf92002-12-16 20:40:54 +000054#endif
Wichert Akkerman36915a11999-07-13 15:45:02 +000055
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +000056#if defined(LINUX) && defined(IA64)
Roland McGrathd81f1d92003-01-09 06:53:34 +000057# include <asm/ptrace_offsets.h>
58# include <asm/rse.h>
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +000059#endif
60
Wichert Akkerman36915a11999-07-13 15:45:02 +000061#ifdef HAVE_SYS_REG_H
62#include <sys/reg.h>
Wichert Akkerman76baf7c1999-02-19 00:21:36 +000063# define PTRACE_PEEKUSR PTRACE_PEEKUSER
Wichert Akkermanfaf72222000-02-19 23:59:03 +000064#elif defined(HAVE_LINUX_PTRACE_H)
65#undef PTRACE_SYSCALL
Roland McGrathce9f0742004-03-01 21:29:22 +000066# ifdef HAVE_STRUCT_IA64_FPREG
67# define ia64_fpreg XXX_ia64_fpreg
68# endif
69# ifdef HAVE_STRUCT_PT_ALL_USER_REGS
70# define pt_all_user_regs XXX_pt_all_user_regs
71# endif
Wichert Akkermanfaf72222000-02-19 23:59:03 +000072#include <linux/ptrace.h>
Roland McGrathce9f0742004-03-01 21:29:22 +000073# undef ia64_fpreg
74# undef pt_all_user_regs
Wichert Akkerman2e2553a1999-05-09 00:29:58 +000075#endif
76
Wichert Akkerman76baf7c1999-02-19 00:21:36 +000077#ifdef SUNOS4_KERNEL_ARCH_KLUDGE
78#include <sys/utsname.h>
79#endif /* SUNOS4_KERNEL_ARCH_KLUDGE */
80
Mike Frysinger8566c502009-10-12 11:05:14 -040081#if defined(LINUXSPARC) && defined (SPARC64)
Roland McGrath6d1a65c2004-07-12 07:44:08 +000082# undef PTRACE_GETREGS
83# define PTRACE_GETREGS PTRACE_GETREGS64
84# undef PTRACE_SETREGS
85# define PTRACE_SETREGS PTRACE_SETREGS64
Wichert Akkerman9ce1a631999-08-29 23:15:07 +000086#endif
87
Wichert Akkerman76baf7c1999-02-19 00:21:36 +000088/* macros */
89#ifndef MAX
90#define MAX(a,b) (((a) > (b)) ? (a) : (b))
91#endif
92#ifndef MIN
93#define MIN(a,b) (((a) < (b)) ? (a) : (b))
94#endif
95
Wichert Akkerman76baf7c1999-02-19 00:21:36 +000096int
Denys Vlasenko12014262011-05-30 14:00:14 +020097tv_nz(struct timeval *a)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +000098{
99 return a->tv_sec || a->tv_usec;
100}
101
102int
Denys Vlasenko12014262011-05-30 14:00:14 +0200103tv_cmp(struct timeval *a, struct timeval *b)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000104{
105 if (a->tv_sec < b->tv_sec
106 || (a->tv_sec == b->tv_sec && a->tv_usec < b->tv_usec))
107 return -1;
108 if (a->tv_sec > b->tv_sec
109 || (a->tv_sec == b->tv_sec && a->tv_usec > b->tv_usec))
110 return 1;
111 return 0;
112}
113
114double
Denys Vlasenko12014262011-05-30 14:00:14 +0200115tv_float(struct timeval *tv)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000116{
117 return tv->tv_sec + tv->tv_usec/1000000.0;
118}
119
120void
Denys Vlasenko12014262011-05-30 14:00:14 +0200121tv_add(struct timeval *tv, struct timeval *a, struct timeval *b)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000122{
123 tv->tv_sec = a->tv_sec + b->tv_sec;
124 tv->tv_usec = a->tv_usec + b->tv_usec;
Roland McGrath58372f52007-07-24 01:38:22 +0000125 if (tv->tv_usec >= 1000000) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000126 tv->tv_sec++;
127 tv->tv_usec -= 1000000;
128 }
129}
130
131void
Denys Vlasenko12014262011-05-30 14:00:14 +0200132tv_sub(struct timeval *tv, struct timeval *a, struct timeval *b)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000133{
134 tv->tv_sec = a->tv_sec - b->tv_sec;
135 tv->tv_usec = a->tv_usec - b->tv_usec;
136 if (((long) tv->tv_usec) < 0) {
137 tv->tv_sec--;
138 tv->tv_usec += 1000000;
139 }
140}
141
142void
Denys Vlasenko12014262011-05-30 14:00:14 +0200143tv_div(struct timeval *tv, struct timeval *a, int n)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000144{
145 tv->tv_usec = (a->tv_sec % n * 1000000 + a->tv_usec + n / 2) / n;
146 tv->tv_sec = a->tv_sec / n + tv->tv_usec / 1000000;
147 tv->tv_usec %= 1000000;
148}
149
150void
Denys Vlasenko12014262011-05-30 14:00:14 +0200151tv_mul(struct timeval *tv, struct timeval *a, int n)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000152{
153 tv->tv_usec = a->tv_usec * n;
Dmitry V. Levinfefdd972007-06-29 21:25:56 +0000154 tv->tv_sec = a->tv_sec * n + tv->tv_usec / 1000000;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000155 tv->tv_usec %= 1000000;
156}
157
Dmitry V. Levinab9008b2007-01-11 22:05:04 +0000158const char *
159xlookup(const struct xlat *xlat, int val)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000160{
161 for (; xlat->str != NULL; xlat++)
162 if (xlat->val == val)
163 return xlat->str;
164 return NULL;
165}
166
167/*
Roland McGratheb9e2e82009-06-02 16:49:22 -0700168 * Generic ptrace wrapper which tracks ESRCH errors
169 * by setting tcp->ptrace_errno to ESRCH.
Denys Vlasenko732d1bf2008-12-17 19:21:59 +0000170 *
171 * We assume that ESRCH indicates likely process death (SIGKILL?),
172 * modulo bugs where process somehow ended up not stopped.
173 * Unfortunately kernel uses ESRCH for that case too. Oh well.
Roland McGratheb9e2e82009-06-02 16:49:22 -0700174 *
175 * Currently used by upeek() only.
176 * TODO: use this in all other ptrace() calls while decoding.
Denys Vlasenko732d1bf2008-12-17 19:21:59 +0000177 */
Denys Vlasenko4dedd562009-02-24 15:17:53 +0000178long
Roland McGratheb9e2e82009-06-02 16:49:22 -0700179do_ptrace(int request, struct tcb *tcp, void *addr, void *data)
Denys Vlasenko4dedd562009-02-24 15:17:53 +0000180{
Denys Vlasenko732d1bf2008-12-17 19:21:59 +0000181 long l;
182
183 errno = 0;
Mike Frysinger09a13c22009-10-07 01:13:39 -0400184 l = ptrace(request, tcp->pid, addr, (long) data);
Roland McGratheb9e2e82009-06-02 16:49:22 -0700185 /* Non-ESRCH errors might be our invalid reg/mem accesses,
186 * we do not record them. */
187 if (errno == ESRCH)
188 tcp->ptrace_errno = ESRCH;
Denys Vlasenko732d1bf2008-12-17 19:21:59 +0000189 return l;
190}
191
192/*
193 * Used when we want to unblock stopped traced process.
194 * Should be only used with PTRACE_CONT, PTRACE_DETACH and PTRACE_SYSCALL.
195 * Returns 0 on success or if error was ESRCH
196 * (presumably process was killed while we talk to it).
197 * Otherwise prints error message and returns -1.
198 */
199int
Roland McGratheb9e2e82009-06-02 16:49:22 -0700200ptrace_restart(int op, struct tcb *tcp, int sig)
Denys Vlasenko732d1bf2008-12-17 19:21:59 +0000201{
202 int err;
Roland McGratheb9e2e82009-06-02 16:49:22 -0700203 const char *msg;
Denys Vlasenko732d1bf2008-12-17 19:21:59 +0000204
205 errno = 0;
Mike Frysinger09a13c22009-10-07 01:13:39 -0400206 ptrace(op, tcp->pid, (void *) 1, (long) sig);
Denys Vlasenko732d1bf2008-12-17 19:21:59 +0000207 err = errno;
208 if (!err || err == ESRCH)
209 return 0;
210
211 tcp->ptrace_errno = err;
Roland McGratheb9e2e82009-06-02 16:49:22 -0700212 msg = "SYSCALL";
213 if (op == PTRACE_CONT)
214 msg = "CONT";
215 if (op == PTRACE_DETACH)
216 msg = "DETACH";
217 fprintf(stderr, "strace: ptrace(PTRACE_%s,1,%d): %s\n",
218 msg, sig, strerror(err));
Denys Vlasenko732d1bf2008-12-17 19:21:59 +0000219 return -1;
220}
221
222/*
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000223 * Print entry in struct xlat table, if there.
224 */
225void
Dmitry V. Levinab9008b2007-01-11 22:05:04 +0000226printxval(const struct xlat *xlat, int val, const char *dflt)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000227{
Dmitry V. Levinab9008b2007-01-11 22:05:04 +0000228 const char *str = xlookup(xlat, val);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000229
230 if (str)
231 tprintf("%s", str);
232 else
233 tprintf("%#x /* %s */", val, dflt);
234}
235
Andreas Schwabb5600fc2009-11-04 17:08:34 +0100236#if HAVE_LONG_LONG
237/*
238 * Print 64bit argument at position llarg and return the index of the next
239 * argument.
240 */
241int
242printllval(struct tcb *tcp, const char *format, int llarg)
243{
244# if defined(FREEBSD) \
Andreas Schwabd69fa492010-07-12 21:39:57 +0200245 || (defined(LINUX) && defined(POWERPC) && !defined(POWERPC64)) \
Dmitry V. Levin7a5b08f2011-05-28 20:47:43 +0000246 || defined(LINUX_MIPSO32) \
247 || defined(__ARM_EABI__)
Andreas Schwabb5600fc2009-11-04 17:08:34 +0100248 /* Align 64bit argument to 64bit boundary. */
Denys Vlasenko4b08df42011-08-19 15:58:24 +0200249 llarg = (llarg + 1) & 0x1e;
Andreas Schwabb5600fc2009-11-04 17:08:34 +0100250# endif
Andreas Schwabd69fa492010-07-12 21:39:57 +0200251# if defined LINUX && (defined X86_64 || defined POWERPC64)
Andreas Schwabb5600fc2009-11-04 17:08:34 +0100252 if (current_personality == 0) {
253 tprintf(format, tcp->u_arg[llarg]);
254 llarg++;
255 } else {
Andreas Schwabd69fa492010-07-12 21:39:57 +0200256# ifdef POWERPC64
257 /* Align 64bit argument to 64bit boundary. */
Denys Vlasenko4b08df42011-08-19 15:58:24 +0200258 llarg = (llarg + 1) & 0x1e;
Andreas Schwabd69fa492010-07-12 21:39:57 +0200259# endif
Andreas Schwabb5600fc2009-11-04 17:08:34 +0100260 tprintf(format, LONG_LONG(tcp->u_arg[llarg], tcp->u_arg[llarg + 1]));
261 llarg += 2;
262 }
Andreas Schwabd69fa492010-07-12 21:39:57 +0200263# elif defined IA64 || defined ALPHA
Andreas Schwabb5600fc2009-11-04 17:08:34 +0100264 tprintf(format, tcp->u_arg[llarg]);
265 llarg++;
266# elif defined LINUX_MIPSN32
267 tprintf(format, tcp->ext_arg[llarg]);
268 llarg++;
269# else
270 tprintf(format, LONG_LONG(tcp->u_arg[llarg], tcp->u_arg[llarg + 1]));
271 llarg += 2;
272# endif
273 return llarg;
274}
275#endif
276
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000277/*
278 * Interpret `xlat' as an array of flags
279 * print the entries whose bits are on in `flags'
280 * return # of flags printed.
281 */
Denys Vlasenko4924dbd2011-08-19 18:06:46 +0200282void
Denys Vlasenko12014262011-05-30 14:00:14 +0200283addflags(const struct xlat *xlat, int flags)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000284{
Denys Vlasenko4924dbd2011-08-19 18:06:46 +0200285 for (; xlat->str; xlat++) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000286 if (xlat->val && (flags & xlat->val) == xlat->val) {
287 tprintf("|%s", xlat->str);
288 flags &= ~xlat->val;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000289 }
290 }
291 if (flags) {
292 tprintf("|%#x", flags);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000293 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000294}
295
Roland McGratha6c0d8c2007-11-01 21:46:22 +0000296/*
Denys Vlasenko4924dbd2011-08-19 18:06:46 +0200297 * Interpret `xlat' as an array of flags.
Roland McGratha6c0d8c2007-11-01 21:46:22 +0000298 * Print to static string the entries whose bits are on in `flags'
299 * Return static string.
300 */
301const char *
302sprintflags(const char *prefix, const struct xlat *xlat, int flags)
303{
304 static char outstr[1024];
305 int found = 0;
306
307 strcpy(outstr, prefix);
308
309 for (; xlat->str; xlat++) {
310 if ((flags & xlat->val) == xlat->val) {
311 if (found)
312 strcat(outstr, "|");
313 strcat(outstr, xlat->str);
314 flags &= ~xlat->val;
315 found = 1;
316 }
317 }
318 if (flags) {
319 if (found)
320 strcat(outstr, "|");
321 sprintf(outstr + strlen(outstr), "%#x", flags);
322 }
323
324 return outstr;
325}
326
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000327int
Dmitry V. Levin30145dd2010-09-06 22:08:24 +0000328printflags(const struct xlat *xlat, int flags, const char *dflt)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000329{
330 int n;
Dmitry V. Levin30145dd2010-09-06 22:08:24 +0000331 const char *sep;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000332
333 if (flags == 0 && xlat->val == 0) {
334 tprintf("%s", xlat->str);
335 return 1;
336 }
337
338 sep = "";
339 for (n = 0; xlat->str; xlat++) {
340 if (xlat->val && (flags & xlat->val) == xlat->val) {
341 tprintf("%s%s", sep, xlat->str);
342 flags &= ~xlat->val;
343 sep = "|";
344 n++;
345 }
346 }
Roland McGrathb2dee132005-06-01 19:02:36 +0000347
348 if (n) {
349 if (flags) {
350 tprintf("%s%#x", sep, flags);
351 n++;
352 }
353 } else {
354 if (flags) {
355 tprintf("%#x", flags);
356 if (dflt)
357 tprintf(" /* %s */", dflt);
358 } else {
359 if (dflt)
360 tprintf("0");
361 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000362 }
Roland McGrathb2dee132005-06-01 19:02:36 +0000363
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000364 return n;
365}
366
367void
Dmitry V. Levin30145dd2010-09-06 22:08:24 +0000368printnum(struct tcb *tcp, long addr, const char *fmt)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000369{
Roland McGratheb285352003-01-14 09:59:00 +0000370 long num;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000371
372 if (!addr) {
373 tprintf("NULL");
374 return;
375 }
376 if (umove(tcp, addr, &num) < 0) {
377 tprintf("%#lx", addr);
378 return;
379 }
380 tprintf("[");
381 tprintf(fmt, num);
382 tprintf("]");
383}
384
Roland McGrath6bc12202003-11-13 22:32:27 +0000385void
Dmitry V. Levin30145dd2010-09-06 22:08:24 +0000386printnum_int(struct tcb *tcp, long addr, const char *fmt)
Roland McGrath9814a942005-07-04 23:28:10 +0000387{
388 int num;
389
390 if (!addr) {
391 tprintf("NULL");
392 return;
393 }
394 if (umove(tcp, addr, &num) < 0) {
395 tprintf("%#lx", addr);
396 return;
397 }
398 tprintf("[");
399 tprintf(fmt, num);
400 tprintf("]");
401}
402
403void
Dmitry V. Levin31382132011-03-04 05:08:02 +0300404printfd(struct tcb *tcp, int fd)
405{
Grant Edwards8a082772011-04-07 20:25:40 +0000406 const char *p;
407
408 if (show_fd_path && (p = getfdpath(tcp, fd)))
409 tprintf("%d<%s>", fd, p);
410 else
411 tprintf("%d", fd);
Dmitry V. Levin31382132011-03-04 05:08:02 +0300412}
413
414void
Denys Vlasenko12014262011-05-30 14:00:14 +0200415printuid(const char *text, unsigned long uid)
Roland McGrath6bc12202003-11-13 22:32:27 +0000416{
417 tprintf("%s", text);
418 tprintf((uid == -1) ? "%ld" : "%lu", uid);
419}
420
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000421static char path[MAXPATHLEN + 1];
422
Dmitry V. Levina501f142008-11-10 23:19:13 +0000423/*
424 * Quote string `instr' of length `size'
425 * Write up to (3 + `size' * 4) bytes to `outstr' buffer.
426 * If `len' < 0, treat `instr' as a NUL-terminated string
427 * and quote at most (`size' - 1) bytes.
428 */
Roland McGrath6d970322007-11-01 23:53:59 +0000429static int
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000430string_quote(const char *instr, char *outstr, int len, int size)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000431{
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000432 const unsigned char *ustr = (const unsigned char *) instr;
433 char *s = outstr;
434 int usehex = 0, c, i;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000435
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000436 if (xflag > 1)
437 usehex = 1;
438 else if (xflag) {
Dmitry V. Levina501f142008-11-10 23:19:13 +0000439 /* Check for presence of symbol which require
440 to hex-quote the whole string. */
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000441 for (i = 0; i < size; ++i) {
442 c = ustr[i];
Dmitry V. Levina501f142008-11-10 23:19:13 +0000443 /* Check for NUL-terminated string. */
444 if (len < 0) {
445 if (c == '\0')
446 break;
447 /* Quote at most size - 1 bytes. */
448 if (i == size - 1)
449 continue;
450 }
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000451 if (!isprint(c) && !isspace(c)) {
452 usehex = 1;
453 break;
454 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000455 }
456 }
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000457
458 *s++ = '\"';
459
460 if (usehex) {
Dmitry V. Levina501f142008-11-10 23:19:13 +0000461 /* Hex-quote the whole string. */
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000462 for (i = 0; i < size; ++i) {
463 c = ustr[i];
Dmitry V. Levina501f142008-11-10 23:19:13 +0000464 /* Check for NUL-terminated string. */
465 if (len < 0) {
466 if (c == '\0')
467 break;
468 /* Quote at most size - 1 bytes. */
469 if (i == size - 1)
470 continue;
471 }
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000472 sprintf(s, "\\x%02x", c);
473 s += 4;
474 }
475 } else {
476 for (i = 0; i < size; ++i) {
477 c = ustr[i];
Dmitry V. Levina501f142008-11-10 23:19:13 +0000478 /* Check for NUL-terminated string. */
479 if (len < 0) {
480 if (c == '\0')
481 break;
482 /* Quote at most size - 1 bytes. */
483 if (i == size - 1)
484 continue;
485 }
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000486 switch (c) {
487 case '\"': case '\\':
488 *s++ = '\\';
489 *s++ = c;
490 break;
491 case '\f':
492 *s++ = '\\';
493 *s++ = 'f';
494 break;
495 case '\n':
496 *s++ = '\\';
497 *s++ = 'n';
498 break;
499 case '\r':
500 *s++ = '\\';
501 *s++ = 'r';
502 break;
503 case '\t':
504 *s++ = '\\';
505 *s++ = 't';
506 break;
507 case '\v':
508 *s++ = '\\';
509 *s++ = 'v';
510 break;
511 default:
512 if (isprint(c))
513 *s++ = c;
514 else if (i + 1 < size
515 && isdigit(ustr[i + 1])) {
516 sprintf(s, "\\%03o", c);
517 s += 4;
518 } else {
519 sprintf(s, "\\%o", c);
520 s += strlen(s);
521 }
522 break;
523 }
524 }
525 }
526
527 *s++ = '\"';
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000528 *s = '\0';
Roland McGrath6d970322007-11-01 23:53:59 +0000529
530 /* Return nonzero if the string was unterminated. */
531 return i == size;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000532}
533
Dmitry V. Levina501f142008-11-10 23:19:13 +0000534/*
535 * Print path string specified by address `addr' and length `n'.
536 * If path length exceeds `n', append `...' to the output.
537 */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000538void
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000539printpathn(struct tcb *tcp, long addr, int n)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000540{
Dmitry V. Levina501f142008-11-10 23:19:13 +0000541 if (!addr) {
Roland McGrath371ed8f2005-02-06 01:55:07 +0000542 tprintf("NULL");
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000543 return;
544 }
545
Dmitry V. Levina501f142008-11-10 23:19:13 +0000546 /* Cap path length to the path buffer size,
547 and NUL-terminate the buffer. */
548 if (n > sizeof path - 1)
549 n = sizeof path - 1;
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000550 path[n] = '\0';
Dmitry V. Levina501f142008-11-10 23:19:13 +0000551
552 /* Fetch one byte more to find out whether path length > n. */
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000553 if (umovestr(tcp, addr, n + 1, path) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000554 tprintf("%#lx", addr);
555 else {
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000556 static char outstr[4*(sizeof path - 1) + sizeof "\"...\""];
557 int trunc = (path[n] != '\0');
558
559 if (trunc)
560 path[n] = '\0';
Dmitry V. Levina501f142008-11-10 23:19:13 +0000561 (void) string_quote(path, outstr, -1, n + 1);
562 if (trunc)
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000563 strcat(outstr, "...");
564 tprintf("%s", outstr);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000565 }
566}
567
568void
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000569printpath(struct tcb *tcp, long addr)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000570{
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000571 printpathn(tcp, addr, sizeof path - 1);
572}
573
Dmitry V. Levina501f142008-11-10 23:19:13 +0000574/*
575 * Print string specified by address `addr' and length `len'.
576 * If `len' < 0, treat the string as a NUL-terminated string.
577 * If string length exceeds `max_strlen', append `...' to the output.
578 */
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000579void
580printstr(struct tcb *tcp, long addr, int len)
581{
582 static char *str = NULL;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000583 static char *outstr;
Roland McGrath6d970322007-11-01 23:53:59 +0000584 int size;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000585
586 if (!addr) {
587 tprintf("NULL");
588 return;
589 }
Dmitry V. Levina501f142008-11-10 23:19:13 +0000590 /* Allocate static buffers if they are not allocated yet. */
591 if (!str)
592 str = malloc(max_strlen + 1);
593 if (!outstr)
594 outstr = malloc(4 * max_strlen + sizeof "\"...\"");
595 if (!str || !outstr) {
596 fprintf(stderr, "out of memory\n");
597 tprintf("%#lx", addr);
598 return;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000599 }
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000600
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000601 if (len < 0) {
Dmitry V. Levina501f142008-11-10 23:19:13 +0000602 /*
603 * Treat as a NUL-terminated string: fetch one byte more
604 * because string_quote() quotes one byte less.
605 */
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000606 size = max_strlen + 1;
Dmitry V. Levina501f142008-11-10 23:19:13 +0000607 str[max_strlen] = '\0';
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000608 if (umovestr(tcp, addr, size, str) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000609 tprintf("%#lx", addr);
610 return;
611 }
612 }
613 else {
Dmitry V. Levina501f142008-11-10 23:19:13 +0000614 size = MIN(len, max_strlen);
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000615 if (umoven(tcp, addr, size, str) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000616 tprintf("%#lx", addr);
617 return;
618 }
619 }
620
Dmitry V. Levina501f142008-11-10 23:19:13 +0000621 if (string_quote(str, outstr, len, size) &&
622 (len < 0 || len > max_strlen))
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000623 strcat(outstr, "...");
Roland McGratha503dcf2007-08-02 02:06:26 +0000624
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000625 tprintf("%s", outstr);
626}
627
John Hughes1d08dcf2001-07-10 13:48:44 +0000628#if HAVE_SYS_UIO_H
629void
Denys Vlasenko12014262011-05-30 14:00:14 +0200630dumpiov(struct tcb *tcp, int len, long addr)
John Hughes1d08dcf2001-07-10 13:48:44 +0000631{
Dmitry V. Levin4ebb4e32006-12-13 17:08:08 +0000632#if defined(LINUX) && SUPPORTED_PERSONALITIES > 1
633 union {
634 struct { u_int32_t base; u_int32_t len; } *iov32;
635 struct { u_int64_t base; u_int64_t len; } *iov64;
636 } iovu;
637#define iov iovu.iov64
638#define sizeof_iov \
639 (personality_wordsize[current_personality] == 4 \
640 ? sizeof(*iovu.iov32) : sizeof(*iovu.iov64))
641#define iov_iov_base(i) \
642 (personality_wordsize[current_personality] == 4 \
643 ? (u_int64_t) iovu.iov32[i].base : iovu.iov64[i].base)
644#define iov_iov_len(i) \
645 (personality_wordsize[current_personality] == 4 \
646 ? (u_int64_t) iovu.iov32[i].len : iovu.iov64[i].len)
647#else
John Hughes1d08dcf2001-07-10 13:48:44 +0000648 struct iovec *iov;
Dmitry V. Levin4ebb4e32006-12-13 17:08:08 +0000649#define sizeof_iov sizeof(*iov)
650#define iov_iov_base(i) iov[i].iov_base
651#define iov_iov_len(i) iov[i].iov_len
652#endif
John Hughes1d08dcf2001-07-10 13:48:44 +0000653 int i;
Roland McGrathaa524c82005-06-01 19:22:06 +0000654 unsigned long size;
John Hughes1d08dcf2001-07-10 13:48:44 +0000655
Dmitry V. Levin4ebb4e32006-12-13 17:08:08 +0000656 size = sizeof_iov * (unsigned long) len;
657 if (size / sizeof_iov != len
658 || (iov = malloc(size)) == NULL) {
Roland McGrathaa524c82005-06-01 19:22:06 +0000659 fprintf(stderr, "out of memory\n");
John Hughes1d08dcf2001-07-10 13:48:44 +0000660 return;
661 }
Roland McGrathaa524c82005-06-01 19:22:06 +0000662 if (umoven(tcp, addr, size, (char *) iov) >= 0) {
John Hughes1d08dcf2001-07-10 13:48:44 +0000663 for (i = 0; i < len; i++) {
Denys Vlasenkoadedb512008-12-30 18:47:55 +0000664 /* include the buffer number to make it easy to
665 * match up the trace with the source */
666 tprintf(" * %lu bytes in buffer %d\n",
667 (unsigned long)iov_iov_len(i), i);
668 dumpstr(tcp, (long) iov_iov_base(i),
669 iov_iov_len(i));
670 }
John Hughes1d08dcf2001-07-10 13:48:44 +0000671 }
672 free((char *) iov);
Dmitry V. Levin4ebb4e32006-12-13 17:08:08 +0000673#undef sizeof_iov
674#undef iov_iov_base
675#undef iov_iov_len
676#undef iov
John Hughes1d08dcf2001-07-10 13:48:44 +0000677}
678#endif
679
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000680void
Denys Vlasenko12014262011-05-30 14:00:14 +0200681dumpstr(struct tcb *tcp, long addr, int len)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000682{
683 static int strsize = -1;
684 static unsigned char *str;
685 static char outstr[80];
686 char *s;
687 int i, j;
688
689 if (strsize < len) {
Denys Vlasenko5d645812011-08-20 12:48:18 +0200690 free(str);
691 str = malloc(len);
692 if (str == NULL) {
Roland McGrath46100d02005-06-01 18:55:42 +0000693 fprintf(stderr, "out of memory\n");
Denys Vlasenkocfd364b2011-08-20 13:41:13 +0200694 /* BUG! On next call we may use NULL str! */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000695 return;
696 }
697 strsize = len;
698 }
699
700 if (umoven(tcp, addr, len, (char *) str) < 0)
701 return;
702
703 for (i = 0; i < len; i += 16) {
704 s = outstr;
705 sprintf(s, " | %05x ", i);
706 s += 9;
707 for (j = 0; j < 16; j++) {
708 if (j == 8)
709 *s++ = ' ';
710 if (i + j < len) {
711 sprintf(s, " %02x", str[i + j]);
712 s += 3;
713 }
714 else {
715 *s++ = ' '; *s++ = ' '; *s++ = ' ';
716 }
717 }
718 *s++ = ' '; *s++ = ' ';
719 for (j = 0; j < 16; j++) {
720 if (j == 8)
721 *s++ = ' ';
722 if (i + j < len) {
723 if (isprint(str[i + j]))
724 *s++ = str[i + j];
725 else
726 *s++ = '.';
727 }
728 else
729 *s++ = ' ';
730 }
731 tprintf("%s |\n", outstr);
732 }
733}
734
735#define PAGMASK (~(PAGSIZ - 1))
736/*
737 * move `len' bytes of data from process `pid'
738 * at address `addr' to our space at `laddr'
739 */
740int
Denys Vlasenkoef2fbf82009-01-06 21:45:06 +0000741umoven(struct tcb *tcp, long addr, int len, char *laddr)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000742{
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000743#ifdef LINUX
Roland McGratheb9e2e82009-06-02 16:49:22 -0700744 int pid = tcp->pid;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000745 int n, m;
Wichert Akkerman5daa0281999-03-15 19:49:42 +0000746 int started = 0;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000747 union {
748 long val;
749 char x[sizeof(long)];
750 } u;
751
752 if (addr & (sizeof(long) - 1)) {
753 /* addr not a multiple of sizeof(long) */
754 n = addr - (addr & -sizeof(long)); /* residue */
755 addr &= -sizeof(long); /* residue */
Roland McGratheb9e2e82009-06-02 16:49:22 -0700756 errno = 0;
757 u.val = ptrace(PTRACE_PEEKDATA, pid, (char *) addr, 0);
758 if (errno) {
759 if (started && (errno==EPERM || errno==EIO)) {
760 /* Ran into 'end of memory' - stupid "printpath" */
761 return 0;
762 }
763 /* But if not started, we had a bogus address. */
764 if (addr != 0 && errno != EIO && errno != ESRCH)
765 perror("ptrace: umoven");
766 return -1;
767 }
Wichert Akkerman5daa0281999-03-15 19:49:42 +0000768 started = 1;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000769 memcpy(laddr, &u.x[n], m = MIN(sizeof(long) - n, len));
770 addr += sizeof(long), laddr += m, len -= m;
771 }
772 while (len) {
Roland McGratheb9e2e82009-06-02 16:49:22 -0700773 errno = 0;
774 u.val = ptrace(PTRACE_PEEKDATA, pid, (char *) addr, 0);
775 if (errno) {
776 if (started && (errno==EPERM || errno==EIO)) {
777 /* Ran into 'end of memory' - stupid "printpath" */
778 return 0;
779 }
780 if (addr != 0 && errno != EIO && errno != ESRCH)
781 perror("ptrace: umoven");
782 return -1;
783 }
Wichert Akkerman5daa0281999-03-15 19:49:42 +0000784 started = 1;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000785 memcpy(laddr, u.x, m = MIN(sizeof(long), len));
786 addr += sizeof(long), laddr += m, len -= m;
787 }
788#endif /* LINUX */
789
790#ifdef SUNOS4
791 int pid = tcp->pid;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000792 int n;
793
794 while (len) {
795 n = MIN(len, PAGSIZ);
796 n = MIN(n, ((addr + PAGSIZ) & PAGMASK) - addr);
Roland McGratheb9e2e82009-06-02 16:49:22 -0700797 if (ptrace(PTRACE_READDATA, pid,
798 (char *) addr, len, laddr) < 0) {
799 if (errno != ESRCH) {
800 perror("umoven: ptrace(PTRACE_READDATA, ...)");
801 abort();
802 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000803 return -1;
804 }
805 len -= n;
806 addr += n;
807 laddr += n;
808 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000809#endif /* SUNOS4 */
810
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000811#ifdef USE_PROCFS
Wichert Akkermanea78f0f1999-11-29 15:34:02 +0000812#ifdef HAVE_MP_PROCFS
John Hughesaa09c6b2001-05-15 14:53:43 +0000813 int fd = tcp->pfd_as;
Wichert Akkerman9ce1a631999-08-29 23:15:07 +0000814#else
John Hughesaa09c6b2001-05-15 14:53:43 +0000815 int fd = tcp->pfd;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000816#endif
John Hughesaa09c6b2001-05-15 14:53:43 +0000817 lseek(fd, addr, SEEK_SET);
818 if (read(fd, laddr, len) == -1)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000819 return -1;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000820#endif /* USE_PROCFS */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000821
822 return 0;
823}
824
825/*
826 * like `umove' but make the additional effort of looking
827 * for a terminating zero byte.
828 */
829int
Denys Vlasenkoef2fbf82009-01-06 21:45:06 +0000830umovestr(struct tcb *tcp, long addr, int len, char *laddr)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000831{
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000832#ifdef USE_PROCFS
John Hughesaa09c6b2001-05-15 14:53:43 +0000833#ifdef HAVE_MP_PROCFS
834 int fd = tcp->pfd_as;
835#else
836 int fd = tcp->pfd;
837#endif
838 /* Some systems (e.g. FreeBSD) can be upset if we read off the
839 end of valid memory, avoid this by trying to read up
840 to page boundaries. But we don't know what a page is (and
841 getpagesize(2) (if it exists) doesn't necessarily return
842 hardware page size). Assume all pages >= 1024 (a-historical
843 I know) */
844
Denys Vlasenkob63256e2011-06-07 12:13:24 +0200845 int page = 1024; /* How to find this? */
John Hughesaa09c6b2001-05-15 14:53:43 +0000846 int move = page - (addr & (page - 1));
847 int left = len;
848
849 lseek(fd, addr, SEEK_SET);
850
851 while (left) {
Denys Vlasenko5d645812011-08-20 12:48:18 +0200852 if (move > left)
853 move = left;
854 move = read(fd, laddr, move);
855 if (move <= 0)
John Hughesaa09c6b2001-05-15 14:53:43 +0000856 return left != len ? 0 : -1;
Denys Vlasenko5d645812011-08-20 12:48:18 +0200857 if (memchr(laddr, 0, move))
858 break;
John Hughesaa09c6b2001-05-15 14:53:43 +0000859 left -= move;
860 laddr += move;
861 addr += move;
862 move = page;
863 }
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000864#else /* !USE_PROCFS */
Wichert Akkerman5daa0281999-03-15 19:49:42 +0000865 int started = 0;
Roland McGratheb9e2e82009-06-02 16:49:22 -0700866 int pid = tcp->pid;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000867 int i, n, m;
868 union {
869 long val;
870 char x[sizeof(long)];
871 } u;
872
873 if (addr & (sizeof(long) - 1)) {
874 /* addr not a multiple of sizeof(long) */
875 n = addr - (addr & -sizeof(long)); /* residue */
876 addr &= -sizeof(long); /* residue */
Roland McGratheb9e2e82009-06-02 16:49:22 -0700877 errno = 0;
878 u.val = ptrace(PTRACE_PEEKDATA, pid, (char *)addr, 0);
879 if (errno) {
880 if (started && (errno==EPERM || errno==EIO)) {
881 /* Ran into 'end of memory' - stupid "printpath" */
882 return 0;
883 }
884 if (addr != 0 && errno != EIO && errno != ESRCH)
885 perror("umovestr");
886 return -1;
887 }
Wichert Akkerman5daa0281999-03-15 19:49:42 +0000888 started = 1;
Denys Vlasenkob63256e2011-06-07 12:13:24 +0200889 memcpy(laddr, &u.x[n], m = MIN(sizeof(long)-n, len));
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000890 while (n & (sizeof(long) - 1))
891 if (u.x[n++] == '\0')
892 return 0;
893 addr += sizeof(long), laddr += m, len -= m;
894 }
895 while (len) {
Roland McGratheb9e2e82009-06-02 16:49:22 -0700896 errno = 0;
897 u.val = ptrace(PTRACE_PEEKDATA, pid, (char *)addr, 0);
898 if (errno) {
899 if (started && (errno==EPERM || errno==EIO)) {
900 /* Ran into 'end of memory' - stupid "printpath" */
901 return 0;
902 }
903 if (addr != 0 && errno != EIO && errno != ESRCH)
904 perror("umovestr");
905 return -1;
906 }
Wichert Akkerman5daa0281999-03-15 19:49:42 +0000907 started = 1;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000908 memcpy(laddr, u.x, m = MIN(sizeof(long), len));
909 for (i = 0; i < sizeof(long); i++)
910 if (u.x[i] == '\0')
911 return 0;
912
913 addr += sizeof(long), laddr += m, len -= m;
914 }
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000915#endif /* !USE_PROCFS */
John Hughesaa09c6b2001-05-15 14:53:43 +0000916 return 0;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000917}
918
919#ifdef LINUX
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +0000920# if !defined (SPARC) && !defined(SPARC64)
921# define PTRACE_WRITETEXT 101
922# define PTRACE_WRITEDATA 102
923# endif /* !SPARC && !SPARC64 */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000924#endif /* LINUX */
925
926#ifdef SUNOS4
927
928static int
Denys Vlasenko12014262011-05-30 14:00:14 +0200929uload(int cmd, int pid, long addr, int len, char *laddr)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000930{
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000931 int peek, poke;
932 int n, m;
933 union {
934 long val;
935 char x[sizeof(long)];
936 } u;
937
938 if (cmd == PTRACE_WRITETEXT) {
939 peek = PTRACE_PEEKTEXT;
940 poke = PTRACE_POKETEXT;
941 }
942 else {
943 peek = PTRACE_PEEKDATA;
944 poke = PTRACE_POKEDATA;
945 }
946 if (addr & (sizeof(long) - 1)) {
947 /* addr not a multiple of sizeof(long) */
948 n = addr - (addr & -sizeof(long)); /* residue */
949 addr &= -sizeof(long);
Roland McGratheb9e2e82009-06-02 16:49:22 -0700950 errno = 0;
951 u.val = ptrace(peek, pid, (char *) addr, 0);
952 if (errno) {
953 perror("uload: POKE");
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000954 return -1;
955 }
Roland McGratheb9e2e82009-06-02 16:49:22 -0700956 memcpy(&u.x[n], laddr, m = MIN(sizeof(long) - n, len));
957 if (ptrace(poke, pid, (char *)addr, u.val) < 0) {
958 perror("uload: POKE");
959 return -1;
960 }
961 addr += sizeof(long), laddr += m, len -= m;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000962 }
963 while (len) {
964 if (len < sizeof(long))
Roland McGratheb9e2e82009-06-02 16:49:22 -0700965 u.val = ptrace(peek, pid, (char *) addr, 0);
966 memcpy(u.x, laddr, m = MIN(sizeof(long), len));
967 if (ptrace(poke, pid, (char *) addr, u.val) < 0) {
968 perror("uload: POKE");
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000969 return -1;
970 }
Roland McGratheb9e2e82009-06-02 16:49:22 -0700971 addr += sizeof(long), laddr += m, len -= m;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000972 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000973 return 0;
974}
975
Roland McGratheb9e2e82009-06-02 16:49:22 -0700976int
Denys Vlasenko12014262011-05-30 14:00:14 +0200977tload(int pid, int addr, int len, char *laddr)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000978{
Roland McGratheb9e2e82009-06-02 16:49:22 -0700979 return uload(PTRACE_WRITETEXT, pid, addr, len, laddr);
980}
981
982int
Denys Vlasenko12014262011-05-30 14:00:14 +0200983dload(int pid, int addr, int len, char *laddr)
Roland McGratheb9e2e82009-06-02 16:49:22 -0700984{
985 return uload(PTRACE_WRITEDATA, pid, addr, len, laddr);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000986}
987
988#endif /* SUNOS4 */
989
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000990#ifndef USE_PROCFS
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000991
992int
Denys Vlasenko12014262011-05-30 14:00:14 +0200993upeek(struct tcb *tcp, long off, long *res)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000994{
995 long val;
996
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +0000997# ifdef SUNOS4_KERNEL_ARCH_KLUDGE
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000998 {
999 static int is_sun4m = -1;
1000 struct utsname name;
1001
1002 /* Round up the usual suspects. */
1003 if (is_sun4m == -1) {
1004 if (uname(&name) < 0) {
1005 perror("upeek: uname?");
1006 exit(1);
1007 }
1008 is_sun4m = strcmp(name.machine, "sun4m") == 0;
1009 if (is_sun4m) {
Roland McGrathd9f816f2004-09-04 03:39:20 +00001010 const struct xlat *x;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001011
1012 for (x = struct_user_offsets; x->str; x++)
1013 x->val += 1024;
1014 }
1015 }
1016 if (is_sun4m)
1017 off += 1024;
1018 }
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001019# endif /* SUNOS4_KERNEL_ARCH_KLUDGE */
Roland McGratheb9e2e82009-06-02 16:49:22 -07001020 errno = 0;
Denys Vlasenko732d1bf2008-12-17 19:21:59 +00001021 val = do_ptrace(PTRACE_PEEKUSER, tcp, (char *) off, 0);
Roland McGratheb9e2e82009-06-02 16:49:22 -07001022 if (val == -1 && errno) {
1023 if (errno != ESRCH) {
1024 char buf[60];
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001025 sprintf(buf, "upeek: ptrace(PTRACE_PEEKUSER,%d,%lu,0)", tcp->pid, off);
Roland McGratheb9e2e82009-06-02 16:49:22 -07001026 perror(buf);
1027 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001028 return -1;
Roland McGratheb9e2e82009-06-02 16:49:22 -07001029 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001030 *res = val;
1031 return 0;
1032}
1033
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001034#endif /* !USE_PROCFS */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001035
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001036void
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001037printcall(struct tcb *tcp)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001038{
Roland McGrath7a918832005-02-02 20:55:23 +00001039#define PRINTBADPC tprintf(sizeof(long) == 4 ? "[????????] " : \
1040 sizeof(long) == 8 ? "[????????????????] " : \
1041 NULL /* crash */)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001042
1043#ifdef LINUX
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001044# ifdef I386
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001045 long eip;
1046
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001047 if (upeek(tcp, 4*EIP, &eip) < 0) {
Roland McGrath7a918832005-02-02 20:55:23 +00001048 PRINTBADPC;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001049 return;
1050 }
1051 tprintf("[%08lx] ", eip);
Roland McGratheac26fc2005-02-02 02:48:53 +00001052
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001053# elif defined(S390) || defined(S390X)
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001054 long psw;
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001055 if (upeek(tcp, PT_PSWADDR, &psw) < 0) {
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001056 PRINTBADPC;
1057 return;
1058 }
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001059# ifdef S390
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001060 tprintf("[%08lx] ", psw);
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001061# elif S390X
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001062 tprintf("[%16lx] ", psw);
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001063# endif
Roland McGratheac26fc2005-02-02 02:48:53 +00001064
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001065# elif defined(X86_64)
Michal Ludvig0e035502002-09-23 15:41:01 +00001066 long rip;
1067
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001068 if (upeek(tcp, 8*RIP, &rip) < 0) {
Roland McGrath7a918832005-02-02 20:55:23 +00001069 PRINTBADPC;
Michal Ludvig0e035502002-09-23 15:41:01 +00001070 return;
1071 }
1072 tprintf("[%16lx] ", rip);
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001073# elif defined(IA64)
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00001074 long ip;
1075
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001076 if (upeek(tcp, PT_B0, &ip) < 0) {
Roland McGrath7a918832005-02-02 20:55:23 +00001077 PRINTBADPC;
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00001078 return;
1079 }
1080 tprintf("[%08lx] ", ip);
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001081# elif defined(POWERPC)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001082 long pc;
1083
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001084 if (upeek(tcp, sizeof(unsigned long)*PT_NIP, &pc) < 0) {
Andreas Schwabd69fa492010-07-12 21:39:57 +02001085 PRINTBADPC;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001086 return;
1087 }
Andreas Schwabd69fa492010-07-12 21:39:57 +02001088# ifdef POWERPC64
1089 tprintf("[%016lx] ", pc);
1090# else
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001091 tprintf("[%08lx] ", pc);
Andreas Schwabd69fa492010-07-12 21:39:57 +02001092# endif
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001093# elif defined(M68K)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001094 long pc;
1095
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001096 if (upeek(tcp, 4*PT_PC, &pc) < 0) {
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001097 tprintf("[????????] ");
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001098 return;
1099 }
1100 tprintf("[%08lx] ", pc);
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001101# elif defined(ALPHA)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001102 long pc;
1103
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001104 if (upeek(tcp, REG_PC, &pc) < 0) {
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001105 tprintf("[????????????????] ");
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001106 return;
1107 }
1108 tprintf("[%08lx] ", pc);
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001109# elif defined(SPARC) || defined(SPARC64)
Mike Frysinger8566c502009-10-12 11:05:14 -04001110 struct pt_regs regs;
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001111 if (ptrace(PTRACE_GETREGS, tcp->pid, (char *)&regs, 0) < 0) {
Roland McGrath7a918832005-02-02 20:55:23 +00001112 PRINTBADPC;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001113 return;
1114 }
Mike Frysinger8566c502009-10-12 11:05:14 -04001115# if defined(SPARC64)
1116 tprintf("[%08lx] ", regs.tpc);
1117# else
1118 tprintf("[%08lx] ", regs.pc);
1119# endif
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001120# elif defined(HPPA)
Wichert Akkermanc1652e22001-03-27 12:17:16 +00001121 long pc;
1122
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001123 if (upeek(tcp, PT_IAOQ0, &pc) < 0) {
1124 tprintf("[????????] ");
Wichert Akkermanc1652e22001-03-27 12:17:16 +00001125 return;
1126 }
1127 tprintf("[%08lx] ", pc);
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001128# elif defined(MIPS)
Wichert Akkerman75c422b2001-04-10 10:22:50 +00001129 long pc;
1130
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001131 if (upeek(tcp, REG_EPC, &pc) < 0) {
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001132 tprintf("[????????] ");
Wichert Akkerman75c422b2001-04-10 10:22:50 +00001133 return;
1134 }
1135 tprintf("[%08lx] ", pc);
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001136# elif defined(SH)
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001137 long pc;
Wichert Akkermanccef6372002-05-01 16:39:22 +00001138
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001139 if (upeek(tcp, 4*REG_PC, &pc) < 0) {
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001140 tprintf("[????????] ");
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001141 return;
1142 }
1143 tprintf("[%08lx] ", pc);
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001144# elif defined(SH64)
Roland McGrathe1e584b2003-06-02 19:18:58 +00001145 long pc;
1146
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001147 if (upeek(tcp, REG_PC, &pc) < 0) {
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001148 tprintf("[????????????????] ");
Roland McGrathe1e584b2003-06-02 19:18:58 +00001149 return;
1150 }
1151 tprintf("[%08lx] ", pc);
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001152# elif defined(ARM)
Roland McGrathef388682003-06-03 23:28:59 +00001153 long pc;
Roland McGrathe1e584b2003-06-02 19:18:58 +00001154
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001155 if (upeek(tcp, 4*15, &pc) < 0) {
Roland McGrath7a918832005-02-02 20:55:23 +00001156 PRINTBADPC;
Roland McGrathef388682003-06-03 23:28:59 +00001157 return;
1158 }
1159 tprintf("[%08lx] ", pc);
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00001160# elif defined(AVR32)
1161 long pc;
1162
1163 if (upeek(tcp, REG_PC, &pc) < 0) {
1164 tprintf("[????????] ");
1165 return;
1166 }
1167 tprintf("[%08lx] ", pc);
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001168# elif defined(BFIN)
Dmitry V. Levin87ea1f42008-11-10 22:21:41 +00001169 long pc;
1170
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001171 if (upeek(tcp, PT_PC, &pc) < 0) {
Dmitry V. Levin87ea1f42008-11-10 22:21:41 +00001172 PRINTBADPC;
1173 return;
1174 }
1175 tprintf("[%08lx] ", pc);
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001176#elif defined(CRISV10)
1177 long pc;
1178
Edgar E. Iglesiaseeb9ce32009-10-05 14:41:02 +00001179 if (upeek(tcp, 4*PT_IRP, &pc) < 0) {
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001180 PRINTBADPC;
1181 return;
1182 }
1183 tprintf("[%08lx] ", pc);
1184#elif defined(CRISV32)
1185 long pc;
1186
Edgar E. Iglesiaseeb9ce32009-10-05 14:41:02 +00001187 if (upeek(tcp, 4*PT_ERP, &pc) < 0) {
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001188 PRINTBADPC;
1189 return;
1190 }
1191 tprintf("[%08lx] ", pc);
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001192# endif /* architecture */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001193#endif /* LINUX */
1194
1195#ifdef SUNOS4
1196 struct regs regs;
1197
Roland McGratheb9e2e82009-06-02 16:49:22 -07001198 if (ptrace(PTRACE_GETREGS, tcp->pid, (char *) &regs, 0) < 0) {
1199 perror("printcall: ptrace(PTRACE_GETREGS, ...)");
Roland McGrath7a918832005-02-02 20:55:23 +00001200 PRINTBADPC;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001201 return;
1202 }
1203 tprintf("[%08x] ", regs.r_o7);
1204#endif /* SUNOS4 */
1205
1206#ifdef SVR4
1207 /* XXX */
Roland McGrath7a918832005-02-02 20:55:23 +00001208 PRINTBADPC;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001209#endif
1210
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001211#ifdef FREEBSD
1212 struct reg regs;
1213 pread(tcp->pfd_reg, &regs, sizeof(regs), 0);
1214 tprintf("[%08x] ", regs.r_eip);
1215#endif /* FREEBSD */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001216}
1217
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001218
1219/*
1220 * These #if's are huge, please indent them correctly.
1221 * It's easy to get confused otherwise.
1222 */
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001223#ifndef USE_PROCFS
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001224
Denys Vlasenkoe7c90242011-06-22 00:09:25 +02001225# ifdef LINUX
Roland McGrathd81f1d92003-01-09 06:53:34 +00001226
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001227# include "syscall.h"
Roland McGrath3291ef22008-05-20 00:34:34 +00001228
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001229# include <sys/syscall.h>
1230# ifndef CLONE_PTRACE
1231# define CLONE_PTRACE 0x00002000
1232# endif
1233# ifndef CLONE_VFORK
1234# define CLONE_VFORK 0x00004000
1235# endif
1236# ifndef CLONE_VM
1237# define CLONE_VM 0x00000100
1238# endif
1239# ifndef CLONE_STOPPED
1240# define CLONE_STOPPED 0x02000000
1241# endif
Roland McGrathd81f1d92003-01-09 06:53:34 +00001242
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001243# ifdef IA64
Roland McGrathd81f1d92003-01-09 06:53:34 +00001244
Roland McGrath08267b82004-02-20 22:56:43 +00001245/* We don't have fork()/vfork() syscalls on ia64 itself, but the ia32
1246 subsystem has them for x86... */
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001247# define SYS_fork 2
1248# define SYS_vfork 190
Roland McGrath08267b82004-02-20 22:56:43 +00001249
Roland McGrathd81f1d92003-01-09 06:53:34 +00001250typedef unsigned long *arg_setup_state;
1251
1252static int
1253arg_setup(struct tcb *tcp, arg_setup_state *state)
1254{
Jan Kratochvil1f942712008-08-06 21:38:52 +00001255 unsigned long cfm, sof, sol;
1256 long bsp;
Roland McGrathd81f1d92003-01-09 06:53:34 +00001257
Jan Kratochvil1f942712008-08-06 21:38:52 +00001258 if (ia32) {
1259 /* Satisfy a false GCC warning. */
1260 *state = NULL;
Roland McGrath08267b82004-02-20 22:56:43 +00001261 return 0;
Jan Kratochvil1f942712008-08-06 21:38:52 +00001262 }
Roland McGrath08267b82004-02-20 22:56:43 +00001263
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001264 if (upeek(tcp, PT_AR_BSP, &bsp) < 0)
Roland McGrathd81f1d92003-01-09 06:53:34 +00001265 return -1;
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001266 if (upeek(tcp, PT_CFM, (long *) &cfm) < 0)
Roland McGrathd81f1d92003-01-09 06:53:34 +00001267 return -1;
1268
1269 sof = (cfm >> 0) & 0x7f;
1270 sol = (cfm >> 7) & 0x7f;
Jan Kratochvil1f942712008-08-06 21:38:52 +00001271 bsp = (long) ia64_rse_skip_regs((unsigned long *) bsp, -sof + sol);
Roland McGrathd81f1d92003-01-09 06:53:34 +00001272
Jan Kratochvil1f942712008-08-06 21:38:52 +00001273 *state = (unsigned long *) bsp;
Roland McGrathd81f1d92003-01-09 06:53:34 +00001274 return 0;
1275}
1276
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001277# define arg_finish_change(tcp, state) 0
Roland McGrathd81f1d92003-01-09 06:53:34 +00001278
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001279# ifdef SYS_fork
Roland McGrathd81f1d92003-01-09 06:53:34 +00001280static int
Denys Vlasenko12014262011-05-30 14:00:14 +02001281get_arg0(struct tcb *tcp, arg_setup_state *state, long *valp)
Roland McGrathd81f1d92003-01-09 06:53:34 +00001282{
Roland McGrath08267b82004-02-20 22:56:43 +00001283 int ret;
1284
1285 if (ia32)
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001286 ret = upeek(tcp, PT_R11, valp);
Roland McGrath08267b82004-02-20 22:56:43 +00001287 else
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001288 ret = umoven(tcp,
Roland McGrath08267b82004-02-20 22:56:43 +00001289 (unsigned long) ia64_rse_skip_regs(*state, 0),
1290 sizeof(long), (void *) valp);
1291 return ret;
Roland McGrathd81f1d92003-01-09 06:53:34 +00001292}
1293
1294static int
Denys Vlasenko12014262011-05-30 14:00:14 +02001295get_arg1(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_R9, 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, 1),
1304 sizeof(long), (void *) valp);
1305 return ret;
Roland McGrathd81f1d92003-01-09 06:53:34 +00001306}
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001307# endif
Roland McGrathd81f1d92003-01-09 06:53:34 +00001308
1309static int
Denys Vlasenko12014262011-05-30 14:00:14 +02001310set_arg0(struct tcb *tcp, arg_setup_state *state, long val)
Roland McGrathd81f1d92003-01-09 06:53:34 +00001311{
Roland McGrath08267b82004-02-20 22:56:43 +00001312 int req = PTRACE_POKEDATA;
1313 void *ap;
1314
1315 if (ia32) {
1316 ap = (void *) (intptr_t) PT_R11; /* r11 == EBX */
1317 req = PTRACE_POKEUSER;
1318 } else
1319 ap = ia64_rse_skip_regs(*state, 0);
Roland McGratheb9e2e82009-06-02 16:49:22 -07001320 errno = 0;
1321 ptrace(req, tcp->pid, ap, val);
1322 return errno ? -1 : 0;
Roland McGrathd81f1d92003-01-09 06:53:34 +00001323}
1324
1325static int
Denys Vlasenko12014262011-05-30 14:00:14 +02001326set_arg1(struct tcb *tcp, arg_setup_state *state, long val)
Roland McGrathd81f1d92003-01-09 06:53:34 +00001327{
Roland McGrath08267b82004-02-20 22:56:43 +00001328 int req = PTRACE_POKEDATA;
1329 void *ap;
1330
1331 if (ia32) {
1332 ap = (void *) (intptr_t) PT_R9; /* r9 == ECX */
1333 req = PTRACE_POKEUSER;
1334 } else
1335 ap = ia64_rse_skip_regs(*state, 1);
Roland McGratheb9e2e82009-06-02 16:49:22 -07001336 errno = 0;
1337 ptrace(req, tcp->pid, ap, val);
1338 return errno ? -1 : 0;
Roland McGrathd81f1d92003-01-09 06:53:34 +00001339}
1340
Roland McGrathb659f872008-07-18 01:19:36 +00001341/* ia64 does not return the input arguments from functions (and syscalls)
1342 according to ia64 RSE (Register Stack Engine) behavior. */
1343
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001344# define restore_arg0(tcp, state, val) ((void) (state), 0)
1345# define restore_arg1(tcp, state, val) ((void) (state), 0)
Roland McGrathb659f872008-07-18 01:19:36 +00001346
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001347# elif defined (SPARC) || defined (SPARC64)
Roland McGrathd81f1d92003-01-09 06:53:34 +00001348
Mike Frysinger8566c502009-10-12 11:05:14 -04001349typedef struct pt_regs arg_setup_state;
Roland McGrathd81f1d92003-01-09 06:53:34 +00001350
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001351# define arg_setup(tcp, state) \
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001352 (ptrace(PTRACE_GETREGS, tcp->pid, (char *) (state), 0))
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001353# define arg_finish_change(tcp, state) \
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001354 (ptrace(PTRACE_SETREGS, tcp->pid, (char *) (state), 0))
Roland McGrathd81f1d92003-01-09 06:53:34 +00001355
Mike Frysinger8566c502009-10-12 11:05:14 -04001356# define get_arg0(tcp, state, valp) (*(valp) = (state)->u_regs[U_REG_O0], 0)
1357# define get_arg1(tcp, state, valp) (*(valp) = (state)->u_regs[U_REG_O1], 0)
1358# define set_arg0(tcp, state, val) ((state)->u_regs[U_REG_O0] = (val), 0)
1359# define set_arg1(tcp, state, val) ((state)->u_regs[U_REG_O1] = (val), 0)
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001360# define restore_arg0(tcp, state, val) 0
Roland McGrathd81f1d92003-01-09 06:53:34 +00001361
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001362# else /* other architectures */
Roland McGrathd81f1d92003-01-09 06:53:34 +00001363
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001364# if defined S390 || defined S390X
Roland McGrath7b308222003-01-20 09:04:36 +00001365/* Note: this is only true for the `clone' system call, which handles
1366 arguments specially. We could as well say that its first two arguments
1367 are swapped relative to other architectures, but that would just be
1368 another #ifdef in the calls. */
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001369# define arg0_offset PT_GPR3
1370# define arg1_offset PT_ORIGGPR2
1371# define restore_arg0(tcp, state, val) ((void) (state), 0)
1372# define restore_arg1(tcp, state, val) ((void) (state), 0)
1373# define arg0_index 1
1374# define arg1_index 0
1375# elif defined (ALPHA) || defined (MIPS)
1376# define arg0_offset REG_A0
1377# define arg1_offset (REG_A0+1)
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00001378# elif defined (AVR32)
1379# define arg0_offset (REG_R12)
1380# define arg1_offset (REG_R11)
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001381# elif defined (POWERPC)
1382# define arg0_offset (sizeof(unsigned long)*PT_R3)
1383# define arg1_offset (sizeof(unsigned long)*PT_R4)
1384# define restore_arg0(tcp, state, val) ((void) (state), 0)
1385# elif defined (HPPA)
1386# define arg0_offset PT_GR26
1387# define arg1_offset (PT_GR26-4)
1388# elif defined (X86_64)
1389# define arg0_offset ((long)(8*(current_personality ? RBX : RDI)))
1390# define arg1_offset ((long)(8*(current_personality ? RCX : RSI)))
1391# elif defined (SH)
1392# define arg0_offset (4*(REG_REG0+4))
1393# define arg1_offset (4*(REG_REG0+5))
1394# elif defined (SH64)
1395 /* ABI defines arg0 & 1 in r2 & r3 */
1396# define arg0_offset (REG_OFFSET+16)
1397# define arg1_offset (REG_OFFSET+24)
1398# define restore_arg0(tcp, state, val) 0
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001399# elif defined CRISV10 || defined CRISV32
1400# define arg0_offset (4*PT_R11)
1401# define arg1_offset (4*PT_ORIG_R10)
1402# define restore_arg0(tcp, state, val) 0
1403# define restore_arg1(tcp, state, val) 0
1404# define arg0_index 1
1405# define arg1_index 0
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001406# else
1407# define arg0_offset 0
1408# define arg1_offset 4
1409# if defined ARM
1410# define restore_arg0(tcp, state, val) 0
1411# endif
1412# endif
Roland McGrathd81f1d92003-01-09 06:53:34 +00001413
1414typedef int arg_setup_state;
1415
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001416# define arg_setup(tcp, state) (0)
1417# define arg_finish_change(tcp, state) 0
1418# define get_arg0(tcp, cookie, valp) \
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001419 (upeek((tcp), arg0_offset, (valp)))
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001420# define get_arg1(tcp, cookie, valp) \
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001421 (upeek((tcp), arg1_offset, (valp)))
Roland McGrathd81f1d92003-01-09 06:53:34 +00001422
1423static int
Denys Vlasenko12014262011-05-30 14:00:14 +02001424set_arg0(struct tcb *tcp, void *cookie, long val)
Roland McGrathd81f1d92003-01-09 06:53:34 +00001425{
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001426 return ptrace(PTRACE_POKEUSER, tcp->pid, (char*)arg0_offset, val);
Roland McGrathd81f1d92003-01-09 06:53:34 +00001427}
1428
1429static int
Denys Vlasenko12014262011-05-30 14:00:14 +02001430set_arg1(struct tcb *tcp, void *cookie, long val)
Roland McGrathd81f1d92003-01-09 06:53:34 +00001431{
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001432 return ptrace(PTRACE_POKEUSER, tcp->pid, (char*)arg1_offset, val);
Roland McGrathd81f1d92003-01-09 06:53:34 +00001433}
1434
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001435# endif /* architectures */
Roland McGrathd81f1d92003-01-09 06:53:34 +00001436
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001437# ifndef restore_arg0
1438# define restore_arg0(tcp, state, val) set_arg0((tcp), (state), (val))
1439# endif
1440# ifndef restore_arg1
1441# define restore_arg1(tcp, state, val) set_arg1((tcp), (state), (val))
1442# endif
Roland McGrathd81f1d92003-01-09 06:53:34 +00001443
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001444# ifndef arg0_index
1445# define arg0_index 0
1446# define arg1_index 1
1447# endif
Roland McGrath90d0afd2004-03-01 21:05:16 +00001448
Roland McGrathd81f1d92003-01-09 06:53:34 +00001449int
Denys Vlasenko418d66a2009-01-17 01:52:54 +00001450setbpt(struct tcb *tcp)
Roland McGrathd81f1d92003-01-09 06:53:34 +00001451{
Roland McGrath3291ef22008-05-20 00:34:34 +00001452 static int clone_scno[SUPPORTED_PERSONALITIES] = { SYS_clone };
Roland McGrathd81f1d92003-01-09 06:53:34 +00001453 arg_setup_state state;
1454
1455 if (tcp->flags & TCB_BPTSET) {
1456 fprintf(stderr, "PANIC: TCB already set in pid %u\n", tcp->pid);
1457 return -1;
1458 }
1459
Roland McGrath3291ef22008-05-20 00:34:34 +00001460 /*
1461 * It's a silly kludge to initialize this with a search at runtime.
1462 * But it's better than maintaining another magic thing in the
1463 * godforsaken tables.
1464 */
1465 if (clone_scno[current_personality] == 0) {
1466 int i;
1467 for (i = 0; i < nsyscalls; ++i)
1468 if (sysent[i].sys_func == sys_clone) {
1469 clone_scno[current_personality] = i;
1470 break;
1471 }
1472 }
1473
Roland McGrath76989d72005-06-07 23:21:31 +00001474 switch (known_scno(tcp)) {
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001475# ifdef SYS_vfork
Roland McGrath9383c6c2003-01-18 00:19:31 +00001476 case SYS_vfork:
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001477# endif
1478# ifdef SYS_fork
Roland McGrathd81f1d92003-01-09 06:53:34 +00001479 case SYS_fork:
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001480# endif
1481# if defined SYS_fork || defined SYS_vfork
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001482 if (arg_setup(tcp, &state) < 0
1483 || get_arg0(tcp, &state, &tcp->inst[0]) < 0
1484 || get_arg1(tcp, &state, &tcp->inst[1]) < 0
Roland McGrath3291ef22008-05-20 00:34:34 +00001485 || change_syscall(tcp, clone_scno[current_personality]) < 0
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001486 || set_arg0(tcp, &state, CLONE_PTRACE|SIGCHLD) < 0
1487 || set_arg1(tcp, &state, 0) < 0
1488 || arg_finish_change(tcp, &state) < 0)
Roland McGrathd81f1d92003-01-09 06:53:34 +00001489 return -1;
Roland McGrathc9dc3c12004-03-01 20:57:09 +00001490 tcp->u_arg[arg0_index] = CLONE_PTRACE|SIGCHLD;
1491 tcp->u_arg[arg1_index] = 0;
Roland McGrathd81f1d92003-01-09 06:53:34 +00001492 tcp->flags |= TCB_BPTSET;
1493 return 0;
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001494# endif
Roland McGrathd81f1d92003-01-09 06:53:34 +00001495
Denys Vlasenkoc133bf02011-06-23 21:57:54 +02001496 case SYS_clone: ;
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001497# ifdef SYS_clone2
Denys Vlasenkoc133bf02011-06-23 21:57:54 +02001498 case SYS_clone2: ;
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001499# endif
Jan Kratochvil8fc95752008-08-06 21:43:35 +00001500 /* ia64 calls directly `clone (CLONE_VFORK | CLONE_VM)'
1501 contrary to x86 SYS_vfork above. Even on x86 we turn the
1502 vfork semantics into plain fork - each application must not
1503 depend on the vfork specifics according to POSIX. We would
1504 hang waiting for the parent resume otherwise. We need to
1505 clear also CLONE_VM but only in the CLONE_VFORK case as
1506 otherwise we would break pthread_create. */
1507
Denys Vlasenkoc133bf02011-06-23 21:57:54 +02001508 long new_arg0 = (tcp->u_arg[arg0_index] | CLONE_PTRACE);
1509 if (new_arg0 & CLONE_VFORK)
1510 new_arg0 &= ~(unsigned long)(CLONE_VFORK | CLONE_VM);
1511 if (arg_setup(tcp, &state) < 0
1512 || set_arg0(tcp, &state, new_arg0) < 0
1513 || arg_finish_change(tcp, &state) < 0)
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00001514 return -1;
Roland McGrathd81f1d92003-01-09 06:53:34 +00001515 tcp->flags |= TCB_BPTSET;
Roland McGrathc9dc3c12004-03-01 20:57:09 +00001516 tcp->inst[0] = tcp->u_arg[arg0_index];
1517 tcp->inst[1] = tcp->u_arg[arg1_index];
Roland McGrathd81f1d92003-01-09 06:53:34 +00001518 return 0;
1519
1520 default:
1521 fprintf(stderr, "PANIC: setbpt for syscall %ld on %u???\n",
1522 tcp->scno, tcp->pid);
1523 break;
1524 }
1525
1526 return -1;
1527}
1528
1529int
Denys Vlasenko12014262011-05-30 14:00:14 +02001530clearbpt(struct tcb *tcp)
Roland McGrathd81f1d92003-01-09 06:53:34 +00001531{
1532 arg_setup_state state;
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001533 if (arg_setup(tcp, &state) < 0
1534 || restore_arg0(tcp, &state, tcp->inst[0]) < 0
1535 || restore_arg1(tcp, &state, tcp->inst[1]) < 0
1536 || arg_finish_change(tcp, &state))
Denys Vlasenkoc133bf02011-06-23 21:57:54 +02001537 if (errno != ESRCH)
1538 return -1;
Roland McGrathd81f1d92003-01-09 06:53:34 +00001539 tcp->flags &= ~TCB_BPTSET;
1540 return 0;
1541}
1542
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001543# else /* !defined LINUX */
Roland McGrathd81f1d92003-01-09 06:53:34 +00001544
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001545int
Denys Vlasenko12014262011-05-30 14:00:14 +02001546setbpt(struct tcb *tcp)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001547{
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001548# ifdef SUNOS4
1549# ifdef SPARC /* This code is slightly sparc specific */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001550
Wichert Akkermane6f876c1999-06-22 15:28:30 +00001551 struct regs regs;
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001552# define BPT 0x91d02001 /* ta 1 */
1553# define LOOP 0x10800000 /* ba 0 */
1554# define LOOPA 0x30800000 /* ba,a 0 */
1555# define NOP 0x01000000
1556# if LOOPA
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001557 static int loopdeloop[1] = {LOOPA};
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001558# else
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001559 static int loopdeloop[2] = {LOOP, NOP};
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001560# endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001561
1562 if (tcp->flags & TCB_BPTSET) {
1563 fprintf(stderr, "PANIC: TCB already set in pid %u\n", tcp->pid);
1564 return -1;
1565 }
Roland McGratheb9e2e82009-06-02 16:49:22 -07001566 if (ptrace(PTRACE_GETREGS, tcp->pid, (char *)&regs, 0) < 0) {
1567 perror("setbpt: ptrace(PTRACE_GETREGS, ...)");
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001568 return -1;
1569 }
1570 tcp->baddr = regs.r_o7 + 8;
Roland McGratheb9e2e82009-06-02 16:49:22 -07001571 if (ptrace(PTRACE_READTEXT, tcp->pid, (char *)tcp->baddr,
1572 sizeof tcp->inst, (char *)tcp->inst) < 0) {
1573 perror("setbpt: ptrace(PTRACE_READTEXT, ...)");
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001574 return -1;
1575 }
1576
1577 /*
1578 * XXX - BRUTAL MODE ON
1579 * We cannot set a real BPT in the child, since it will not be
1580 * traced at the moment it will reach the trap and would probably
1581 * die with a core dump.
1582 * Thus, we are force our way in by taking out two instructions
1583 * and insert an eternal loop in stead, in expectance of the SIGSTOP
1584 * generated by out PTRACE_ATTACH.
1585 * Of cause, if we evaporate ourselves in the middle of all this...
1586 */
Roland McGratheb9e2e82009-06-02 16:49:22 -07001587 if (ptrace(PTRACE_WRITETEXT, tcp->pid, (char *) tcp->baddr,
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001588 sizeof loopdeloop, (char *) loopdeloop) < 0) {
Roland McGratheb9e2e82009-06-02 16:49:22 -07001589 perror("setbpt: ptrace(PTRACE_WRITETEXT, ...)");
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001590 return -1;
1591 }
1592 tcp->flags |= TCB_BPTSET;
1593
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001594# endif /* SPARC */
1595# endif /* SUNOS4 */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001596
1597 return 0;
1598}
1599
1600int
Denys Vlasenko12014262011-05-30 14:00:14 +02001601clearbpt(struct tcb *tcp)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001602{
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001603# ifdef SUNOS4
1604# ifdef SPARC
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001605
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001606# if !LOOPA
Wichert Akkermane6f876c1999-06-22 15:28:30 +00001607 struct regs regs;
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001608# endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001609
1610 if (!(tcp->flags & TCB_BPTSET)) {
1611 fprintf(stderr, "PANIC: TCB not set in pid %u\n", tcp->pid);
1612 return -1;
1613 }
Roland McGratheb9e2e82009-06-02 16:49:22 -07001614 if (ptrace(PTRACE_WRITETEXT, tcp->pid, (char *) tcp->baddr,
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001615 sizeof tcp->inst, (char *) tcp->inst) < 0) {
Roland McGratheb9e2e82009-06-02 16:49:22 -07001616 perror("clearbtp: ptrace(PTRACE_WRITETEXT, ...)");
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001617 return -1;
1618 }
1619 tcp->flags &= ~TCB_BPTSET;
1620
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001621# if !LOOPA
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001622 /*
1623 * Since we don't have a single instruction breakpoint, we may have
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001624 * to adjust the program counter after removing our `breakpoint'.
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001625 */
Roland McGratheb9e2e82009-06-02 16:49:22 -07001626 if (ptrace(PTRACE_GETREGS, tcp->pid, (char *)&regs, 0) < 0) {
1627 perror("clearbpt: ptrace(PTRACE_GETREGS, ...)");
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001628 return -1;
1629 }
Roland McGratheb9e2e82009-06-02 16:49:22 -07001630 if ((regs.r_pc < tcp->baddr) ||
1631 (regs.r_pc > tcp->baddr + 4)) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001632 /* The breakpoint has not been reached yet */
1633 if (debug)
1634 fprintf(stderr,
1635 "NOTE: PC not at bpt (pc %#x baddr %#x)\n",
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001636 regs.r_pc, tcp->baddr);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001637 return 0;
1638 }
1639 if (regs.r_pc != tcp->baddr)
1640 if (debug)
1641 fprintf(stderr, "NOTE: PC adjusted (%#x -> %#x\n",
1642 regs.r_pc, tcp->baddr);
1643
1644 regs.r_pc = tcp->baddr;
Roland McGratheb9e2e82009-06-02 16:49:22 -07001645 if (ptrace(PTRACE_SETREGS, tcp->pid, (char *)&regs, 0) < 0) {
1646 perror("clearbpt: ptrace(PTRACE_SETREGS, ...)");
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001647 return -1;
1648 }
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001649# endif /* LOOPA */
1650# endif /* SPARC */
1651# endif /* SUNOS4 */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001652
1653 return 0;
1654}
1655
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001656# endif /* !defined LINUX */
Roland McGrathd81f1d92003-01-09 06:53:34 +00001657
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001658#endif /* !USE_PROCFS */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001659
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001660
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001661#ifdef SUNOS4
1662
1663static int
Denys Vlasenko12014262011-05-30 14:00:14 +02001664getex(struct tcb *tcp, struct exec *hdr)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001665{
1666 int n;
1667
1668 for (n = 0; n < sizeof *hdr; n += 4) {
1669 long res;
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001670 if (upeek(tcp, uoff(u_exdata) + n, &res) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001671 return -1;
1672 memcpy(((char *) hdr) + n, &res, 4);
1673 }
1674 if (debug) {
1675 fprintf(stderr, "[struct exec: magic: %o version %u Mach %o\n",
1676 hdr->a_magic, hdr->a_toolversion, hdr->a_machtype);
1677 fprintf(stderr, "Text %lu Data %lu Bss %lu Syms %lu Entry %#lx]\n",
1678 hdr->a_text, hdr->a_data, hdr->a_bss, hdr->a_syms, hdr->a_entry);
1679 }
1680 return 0;
1681}
1682
1683int
Denys Vlasenko12014262011-05-30 14:00:14 +02001684fixvfork(struct tcb *tcp)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001685{
1686 int pid = tcp->pid;
1687 /*
1688 * Change `vfork' in a freshly exec'ed dynamically linked
1689 * executable's (internal) symbol table to plain old `fork'
1690 */
1691
1692 struct exec hdr;
1693 struct link_dynamic dyn;
1694 struct link_dynamic_2 ld;
1695 char *strtab, *cp;
1696
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001697 if (getex(tcp, &hdr) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001698 return -1;
1699 if (!hdr.a_dynamic)
1700 return -1;
1701
1702 if (umove(tcp, (int) N_DATADDR(hdr), &dyn) < 0) {
1703 fprintf(stderr, "Cannot read DYNAMIC\n");
1704 return -1;
1705 }
1706 if (umove(tcp, (int) dyn.ld_un.ld_2, &ld) < 0) {
1707 fprintf(stderr, "Cannot read link_dynamic_2\n");
1708 return -1;
1709 }
Denys Vlasenko5d645812011-08-20 12:48:18 +02001710 strtab = malloc((unsigned)ld.ld_symb_size);
1711 if (strtab == NULL) {
Roland McGrath46100d02005-06-01 18:55:42 +00001712 fprintf(stderr, "out of memory\n");
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001713 return -1;
1714 }
Roland McGratheb9e2e82009-06-02 16:49:22 -07001715 if (umoven(tcp, (int)ld.ld_symbols+(int)N_TXTADDR(hdr),
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001716 (int)ld.ld_symb_size, strtab) < 0)
1717 goto err;
1718
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001719 for (cp = strtab; cp < strtab + ld.ld_symb_size; ) {
1720 if (strcmp(cp, "_vfork") == 0) {
1721 if (debug)
1722 fprintf(stderr, "fixvfork: FOUND _vfork\n");
1723 strcpy(cp, "_fork");
1724 break;
1725 }
1726 cp += strlen(cp)+1;
1727 }
1728 if (cp < strtab + ld.ld_symb_size)
1729 /*
1730 * Write entire symbol table back to avoid
1731 * memory alignment bugs in ptrace
1732 */
Roland McGratheb9e2e82009-06-02 16:49:22 -07001733 if (tload(pid, (int)ld.ld_symbols+(int)N_TXTADDR(hdr),
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001734 (int)ld.ld_symb_size, strtab) < 0)
1735 goto err;
1736
1737 free(strtab);
1738 return 0;
1739
1740err:
1741 free(strtab);
1742 return -1;
1743}
1744
1745#endif /* SUNOS4 */