blob: 9ccc5c9303ae9e74fbacd6207e4e89cd71e61992 [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");
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000694 return;
695 }
696 strsize = len;
697 }
698
699 if (umoven(tcp, addr, len, (char *) str) < 0)
700 return;
701
702 for (i = 0; i < len; i += 16) {
703 s = outstr;
704 sprintf(s, " | %05x ", i);
705 s += 9;
706 for (j = 0; j < 16; j++) {
707 if (j == 8)
708 *s++ = ' ';
709 if (i + j < len) {
710 sprintf(s, " %02x", str[i + j]);
711 s += 3;
712 }
713 else {
714 *s++ = ' '; *s++ = ' '; *s++ = ' ';
715 }
716 }
717 *s++ = ' '; *s++ = ' ';
718 for (j = 0; j < 16; j++) {
719 if (j == 8)
720 *s++ = ' ';
721 if (i + j < len) {
722 if (isprint(str[i + j]))
723 *s++ = str[i + j];
724 else
725 *s++ = '.';
726 }
727 else
728 *s++ = ' ';
729 }
730 tprintf("%s |\n", outstr);
731 }
732}
733
734#define PAGMASK (~(PAGSIZ - 1))
735/*
736 * move `len' bytes of data from process `pid'
737 * at address `addr' to our space at `laddr'
738 */
739int
Denys Vlasenkoef2fbf82009-01-06 21:45:06 +0000740umoven(struct tcb *tcp, long addr, int len, char *laddr)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000741{
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000742#ifdef LINUX
Roland McGratheb9e2e82009-06-02 16:49:22 -0700743 int pid = tcp->pid;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000744 int n, m;
Wichert Akkerman5daa0281999-03-15 19:49:42 +0000745 int started = 0;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000746 union {
747 long val;
748 char x[sizeof(long)];
749 } u;
750
751 if (addr & (sizeof(long) - 1)) {
752 /* addr not a multiple of sizeof(long) */
753 n = addr - (addr & -sizeof(long)); /* residue */
754 addr &= -sizeof(long); /* residue */
Roland McGratheb9e2e82009-06-02 16:49:22 -0700755 errno = 0;
756 u.val = ptrace(PTRACE_PEEKDATA, pid, (char *) addr, 0);
757 if (errno) {
758 if (started && (errno==EPERM || errno==EIO)) {
759 /* Ran into 'end of memory' - stupid "printpath" */
760 return 0;
761 }
762 /* But if not started, we had a bogus address. */
763 if (addr != 0 && errno != EIO && errno != ESRCH)
764 perror("ptrace: umoven");
765 return -1;
766 }
Wichert Akkerman5daa0281999-03-15 19:49:42 +0000767 started = 1;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000768 memcpy(laddr, &u.x[n], m = MIN(sizeof(long) - n, len));
769 addr += sizeof(long), laddr += m, len -= m;
770 }
771 while (len) {
Roland McGratheb9e2e82009-06-02 16:49:22 -0700772 errno = 0;
773 u.val = ptrace(PTRACE_PEEKDATA, pid, (char *) addr, 0);
774 if (errno) {
775 if (started && (errno==EPERM || errno==EIO)) {
776 /* Ran into 'end of memory' - stupid "printpath" */
777 return 0;
778 }
779 if (addr != 0 && errno != EIO && errno != ESRCH)
780 perror("ptrace: umoven");
781 return -1;
782 }
Wichert Akkerman5daa0281999-03-15 19:49:42 +0000783 started = 1;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000784 memcpy(laddr, u.x, m = MIN(sizeof(long), len));
785 addr += sizeof(long), laddr += m, len -= m;
786 }
787#endif /* LINUX */
788
789#ifdef SUNOS4
790 int pid = tcp->pid;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000791 int n;
792
793 while (len) {
794 n = MIN(len, PAGSIZ);
795 n = MIN(n, ((addr + PAGSIZ) & PAGMASK) - addr);
Roland McGratheb9e2e82009-06-02 16:49:22 -0700796 if (ptrace(PTRACE_READDATA, pid,
797 (char *) addr, len, laddr) < 0) {
798 if (errno != ESRCH) {
799 perror("umoven: ptrace(PTRACE_READDATA, ...)");
800 abort();
801 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000802 return -1;
803 }
804 len -= n;
805 addr += n;
806 laddr += n;
807 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000808#endif /* SUNOS4 */
809
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000810#ifdef USE_PROCFS
Wichert Akkermanea78f0f1999-11-29 15:34:02 +0000811#ifdef HAVE_MP_PROCFS
John Hughesaa09c6b2001-05-15 14:53:43 +0000812 int fd = tcp->pfd_as;
Wichert Akkerman9ce1a631999-08-29 23:15:07 +0000813#else
John Hughesaa09c6b2001-05-15 14:53:43 +0000814 int fd = tcp->pfd;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000815#endif
John Hughesaa09c6b2001-05-15 14:53:43 +0000816 lseek(fd, addr, SEEK_SET);
817 if (read(fd, laddr, len) == -1)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000818 return -1;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000819#endif /* USE_PROCFS */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000820
821 return 0;
822}
823
824/*
825 * like `umove' but make the additional effort of looking
826 * for a terminating zero byte.
827 */
828int
Denys Vlasenkoef2fbf82009-01-06 21:45:06 +0000829umovestr(struct tcb *tcp, long addr, int len, char *laddr)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000830{
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000831#ifdef USE_PROCFS
John Hughesaa09c6b2001-05-15 14:53:43 +0000832#ifdef HAVE_MP_PROCFS
833 int fd = tcp->pfd_as;
834#else
835 int fd = tcp->pfd;
836#endif
837 /* Some systems (e.g. FreeBSD) can be upset if we read off the
838 end of valid memory, avoid this by trying to read up
839 to page boundaries. But we don't know what a page is (and
840 getpagesize(2) (if it exists) doesn't necessarily return
841 hardware page size). Assume all pages >= 1024 (a-historical
842 I know) */
843
Denys Vlasenkob63256e2011-06-07 12:13:24 +0200844 int page = 1024; /* How to find this? */
John Hughesaa09c6b2001-05-15 14:53:43 +0000845 int move = page - (addr & (page - 1));
846 int left = len;
847
848 lseek(fd, addr, SEEK_SET);
849
850 while (left) {
Denys Vlasenko5d645812011-08-20 12:48:18 +0200851 if (move > left)
852 move = left;
853 move = read(fd, laddr, move);
854 if (move <= 0)
John Hughesaa09c6b2001-05-15 14:53:43 +0000855 return left != len ? 0 : -1;
Denys Vlasenko5d645812011-08-20 12:48:18 +0200856 if (memchr(laddr, 0, move))
857 break;
John Hughesaa09c6b2001-05-15 14:53:43 +0000858 left -= move;
859 laddr += move;
860 addr += move;
861 move = page;
862 }
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000863#else /* !USE_PROCFS */
Wichert Akkerman5daa0281999-03-15 19:49:42 +0000864 int started = 0;
Roland McGratheb9e2e82009-06-02 16:49:22 -0700865 int pid = tcp->pid;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000866 int i, n, m;
867 union {
868 long val;
869 char x[sizeof(long)];
870 } u;
871
872 if (addr & (sizeof(long) - 1)) {
873 /* addr not a multiple of sizeof(long) */
874 n = addr - (addr & -sizeof(long)); /* residue */
875 addr &= -sizeof(long); /* residue */
Roland McGratheb9e2e82009-06-02 16:49:22 -0700876 errno = 0;
877 u.val = ptrace(PTRACE_PEEKDATA, pid, (char *)addr, 0);
878 if (errno) {
879 if (started && (errno==EPERM || errno==EIO)) {
880 /* Ran into 'end of memory' - stupid "printpath" */
881 return 0;
882 }
883 if (addr != 0 && errno != EIO && errno != ESRCH)
884 perror("umovestr");
885 return -1;
886 }
Wichert Akkerman5daa0281999-03-15 19:49:42 +0000887 started = 1;
Denys Vlasenkob63256e2011-06-07 12:13:24 +0200888 memcpy(laddr, &u.x[n], m = MIN(sizeof(long)-n, len));
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000889 while (n & (sizeof(long) - 1))
890 if (u.x[n++] == '\0')
891 return 0;
892 addr += sizeof(long), laddr += m, len -= m;
893 }
894 while (len) {
Roland McGratheb9e2e82009-06-02 16:49:22 -0700895 errno = 0;
896 u.val = ptrace(PTRACE_PEEKDATA, pid, (char *)addr, 0);
897 if (errno) {
898 if (started && (errno==EPERM || errno==EIO)) {
899 /* Ran into 'end of memory' - stupid "printpath" */
900 return 0;
901 }
902 if (addr != 0 && errno != EIO && errno != ESRCH)
903 perror("umovestr");
904 return -1;
905 }
Wichert Akkerman5daa0281999-03-15 19:49:42 +0000906 started = 1;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000907 memcpy(laddr, u.x, m = MIN(sizeof(long), len));
908 for (i = 0; i < sizeof(long); i++)
909 if (u.x[i] == '\0')
910 return 0;
911
912 addr += sizeof(long), laddr += m, len -= m;
913 }
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000914#endif /* !USE_PROCFS */
John Hughesaa09c6b2001-05-15 14:53:43 +0000915 return 0;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000916}
917
918#ifdef LINUX
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +0000919# if !defined (SPARC) && !defined(SPARC64)
920# define PTRACE_WRITETEXT 101
921# define PTRACE_WRITEDATA 102
922# endif /* !SPARC && !SPARC64 */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000923#endif /* LINUX */
924
925#ifdef SUNOS4
926
927static int
Denys Vlasenko12014262011-05-30 14:00:14 +0200928uload(int cmd, int pid, long addr, int len, char *laddr)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000929{
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000930 int peek, poke;
931 int n, m;
932 union {
933 long val;
934 char x[sizeof(long)];
935 } u;
936
937 if (cmd == PTRACE_WRITETEXT) {
938 peek = PTRACE_PEEKTEXT;
939 poke = PTRACE_POKETEXT;
940 }
941 else {
942 peek = PTRACE_PEEKDATA;
943 poke = PTRACE_POKEDATA;
944 }
945 if (addr & (sizeof(long) - 1)) {
946 /* addr not a multiple of sizeof(long) */
947 n = addr - (addr & -sizeof(long)); /* residue */
948 addr &= -sizeof(long);
Roland McGratheb9e2e82009-06-02 16:49:22 -0700949 errno = 0;
950 u.val = ptrace(peek, pid, (char *) addr, 0);
951 if (errno) {
952 perror("uload: POKE");
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000953 return -1;
954 }
Roland McGratheb9e2e82009-06-02 16:49:22 -0700955 memcpy(&u.x[n], laddr, m = MIN(sizeof(long) - n, len));
956 if (ptrace(poke, pid, (char *)addr, u.val) < 0) {
957 perror("uload: POKE");
958 return -1;
959 }
960 addr += sizeof(long), laddr += m, len -= m;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000961 }
962 while (len) {
963 if (len < sizeof(long))
Roland McGratheb9e2e82009-06-02 16:49:22 -0700964 u.val = ptrace(peek, pid, (char *) addr, 0);
965 memcpy(u.x, laddr, m = MIN(sizeof(long), len));
966 if (ptrace(poke, pid, (char *) addr, u.val) < 0) {
967 perror("uload: POKE");
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000968 return -1;
969 }
Roland McGratheb9e2e82009-06-02 16:49:22 -0700970 addr += sizeof(long), laddr += m, len -= m;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000971 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000972 return 0;
973}
974
Roland McGratheb9e2e82009-06-02 16:49:22 -0700975int
Denys Vlasenko12014262011-05-30 14:00:14 +0200976tload(int pid, int addr, int len, char *laddr)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000977{
Roland McGratheb9e2e82009-06-02 16:49:22 -0700978 return uload(PTRACE_WRITETEXT, pid, addr, len, laddr);
979}
980
981int
Denys Vlasenko12014262011-05-30 14:00:14 +0200982dload(int pid, int addr, int len, char *laddr)
Roland McGratheb9e2e82009-06-02 16:49:22 -0700983{
984 return uload(PTRACE_WRITEDATA, pid, addr, len, laddr);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000985}
986
987#endif /* SUNOS4 */
988
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000989#ifndef USE_PROCFS
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000990
991int
Denys Vlasenko12014262011-05-30 14:00:14 +0200992upeek(struct tcb *tcp, long off, long *res)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000993{
994 long val;
995
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +0000996# ifdef SUNOS4_KERNEL_ARCH_KLUDGE
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000997 {
998 static int is_sun4m = -1;
999 struct utsname name;
1000
1001 /* Round up the usual suspects. */
1002 if (is_sun4m == -1) {
1003 if (uname(&name) < 0) {
1004 perror("upeek: uname?");
1005 exit(1);
1006 }
1007 is_sun4m = strcmp(name.machine, "sun4m") == 0;
1008 if (is_sun4m) {
Roland McGrathd9f816f2004-09-04 03:39:20 +00001009 const struct xlat *x;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001010
1011 for (x = struct_user_offsets; x->str; x++)
1012 x->val += 1024;
1013 }
1014 }
1015 if (is_sun4m)
1016 off += 1024;
1017 }
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001018# endif /* SUNOS4_KERNEL_ARCH_KLUDGE */
Roland McGratheb9e2e82009-06-02 16:49:22 -07001019 errno = 0;
Denys Vlasenko732d1bf2008-12-17 19:21:59 +00001020 val = do_ptrace(PTRACE_PEEKUSER, tcp, (char *) off, 0);
Roland McGratheb9e2e82009-06-02 16:49:22 -07001021 if (val == -1 && errno) {
1022 if (errno != ESRCH) {
1023 char buf[60];
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001024 sprintf(buf, "upeek: ptrace(PTRACE_PEEKUSER,%d,%lu,0)", tcp->pid, off);
Roland McGratheb9e2e82009-06-02 16:49:22 -07001025 perror(buf);
1026 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001027 return -1;
Roland McGratheb9e2e82009-06-02 16:49:22 -07001028 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001029 *res = val;
1030 return 0;
1031}
1032
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001033#endif /* !USE_PROCFS */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001034
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001035void
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001036printcall(struct tcb *tcp)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001037{
Roland McGrath7a918832005-02-02 20:55:23 +00001038#define PRINTBADPC tprintf(sizeof(long) == 4 ? "[????????] " : \
1039 sizeof(long) == 8 ? "[????????????????] " : \
1040 NULL /* crash */)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001041
1042#ifdef LINUX
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001043# ifdef I386
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001044 long eip;
1045
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001046 if (upeek(tcp, 4*EIP, &eip) < 0) {
Roland McGrath7a918832005-02-02 20:55:23 +00001047 PRINTBADPC;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001048 return;
1049 }
1050 tprintf("[%08lx] ", eip);
Roland McGratheac26fc2005-02-02 02:48:53 +00001051
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001052# elif defined(S390) || defined(S390X)
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001053 long psw;
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001054 if (upeek(tcp, PT_PSWADDR, &psw) < 0) {
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001055 PRINTBADPC;
1056 return;
1057 }
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001058# ifdef S390
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001059 tprintf("[%08lx] ", psw);
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001060# elif S390X
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001061 tprintf("[%16lx] ", psw);
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001062# endif
Roland McGratheac26fc2005-02-02 02:48:53 +00001063
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001064# elif defined(X86_64)
Michal Ludvig0e035502002-09-23 15:41:01 +00001065 long rip;
1066
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001067 if (upeek(tcp, 8*RIP, &rip) < 0) {
Roland McGrath7a918832005-02-02 20:55:23 +00001068 PRINTBADPC;
Michal Ludvig0e035502002-09-23 15:41:01 +00001069 return;
1070 }
1071 tprintf("[%16lx] ", rip);
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001072# elif defined(IA64)
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00001073 long ip;
1074
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001075 if (upeek(tcp, PT_B0, &ip) < 0) {
Roland McGrath7a918832005-02-02 20:55:23 +00001076 PRINTBADPC;
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00001077 return;
1078 }
1079 tprintf("[%08lx] ", ip);
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001080# elif defined(POWERPC)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001081 long pc;
1082
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001083 if (upeek(tcp, sizeof(unsigned long)*PT_NIP, &pc) < 0) {
Andreas Schwabd69fa492010-07-12 21:39:57 +02001084 PRINTBADPC;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001085 return;
1086 }
Andreas Schwabd69fa492010-07-12 21:39:57 +02001087# ifdef POWERPC64
1088 tprintf("[%016lx] ", pc);
1089# else
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001090 tprintf("[%08lx] ", pc);
Andreas Schwabd69fa492010-07-12 21:39:57 +02001091# endif
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001092# elif defined(M68K)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001093 long pc;
1094
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001095 if (upeek(tcp, 4*PT_PC, &pc) < 0) {
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001096 tprintf("[????????] ");
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001097 return;
1098 }
1099 tprintf("[%08lx] ", pc);
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001100# elif defined(ALPHA)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001101 long pc;
1102
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001103 if (upeek(tcp, REG_PC, &pc) < 0) {
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001104 tprintf("[????????????????] ");
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001105 return;
1106 }
1107 tprintf("[%08lx] ", pc);
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001108# elif defined(SPARC) || defined(SPARC64)
Mike Frysinger8566c502009-10-12 11:05:14 -04001109 struct pt_regs regs;
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001110 if (ptrace(PTRACE_GETREGS, tcp->pid, (char *)&regs, 0) < 0) {
Roland McGrath7a918832005-02-02 20:55:23 +00001111 PRINTBADPC;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001112 return;
1113 }
Mike Frysinger8566c502009-10-12 11:05:14 -04001114# if defined(SPARC64)
1115 tprintf("[%08lx] ", regs.tpc);
1116# else
1117 tprintf("[%08lx] ", regs.pc);
1118# endif
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001119# elif defined(HPPA)
Wichert Akkermanc1652e22001-03-27 12:17:16 +00001120 long pc;
1121
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001122 if (upeek(tcp, PT_IAOQ0, &pc) < 0) {
1123 tprintf("[????????] ");
Wichert Akkermanc1652e22001-03-27 12:17:16 +00001124 return;
1125 }
1126 tprintf("[%08lx] ", pc);
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001127# elif defined(MIPS)
Wichert Akkerman75c422b2001-04-10 10:22:50 +00001128 long pc;
1129
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001130 if (upeek(tcp, REG_EPC, &pc) < 0) {
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001131 tprintf("[????????] ");
Wichert Akkerman75c422b2001-04-10 10:22:50 +00001132 return;
1133 }
1134 tprintf("[%08lx] ", pc);
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001135# elif defined(SH)
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001136 long pc;
Wichert Akkermanccef6372002-05-01 16:39:22 +00001137
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001138 if (upeek(tcp, 4*REG_PC, &pc) < 0) {
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001139 tprintf("[????????] ");
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001140 return;
1141 }
1142 tprintf("[%08lx] ", pc);
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001143# elif defined(SH64)
Roland McGrathe1e584b2003-06-02 19:18:58 +00001144 long pc;
1145
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001146 if (upeek(tcp, REG_PC, &pc) < 0) {
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001147 tprintf("[????????????????] ");
Roland McGrathe1e584b2003-06-02 19:18:58 +00001148 return;
1149 }
1150 tprintf("[%08lx] ", pc);
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001151# elif defined(ARM)
Roland McGrathef388682003-06-03 23:28:59 +00001152 long pc;
Roland McGrathe1e584b2003-06-02 19:18:58 +00001153
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001154 if (upeek(tcp, 4*15, &pc) < 0) {
Roland McGrath7a918832005-02-02 20:55:23 +00001155 PRINTBADPC;
Roland McGrathef388682003-06-03 23:28:59 +00001156 return;
1157 }
1158 tprintf("[%08lx] ", pc);
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00001159# elif defined(AVR32)
1160 long pc;
1161
1162 if (upeek(tcp, REG_PC, &pc) < 0) {
1163 tprintf("[????????] ");
1164 return;
1165 }
1166 tprintf("[%08lx] ", pc);
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001167# elif defined(BFIN)
Dmitry V. Levin87ea1f42008-11-10 22:21:41 +00001168 long pc;
1169
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001170 if (upeek(tcp, PT_PC, &pc) < 0) {
Dmitry V. Levin87ea1f42008-11-10 22:21:41 +00001171 PRINTBADPC;
1172 return;
1173 }
1174 tprintf("[%08lx] ", pc);
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001175#elif defined(CRISV10)
1176 long pc;
1177
Edgar E. Iglesiaseeb9ce32009-10-05 14:41:02 +00001178 if (upeek(tcp, 4*PT_IRP, &pc) < 0) {
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001179 PRINTBADPC;
1180 return;
1181 }
1182 tprintf("[%08lx] ", pc);
1183#elif defined(CRISV32)
1184 long pc;
1185
Edgar E. Iglesiaseeb9ce32009-10-05 14:41:02 +00001186 if (upeek(tcp, 4*PT_ERP, &pc) < 0) {
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001187 PRINTBADPC;
1188 return;
1189 }
1190 tprintf("[%08lx] ", pc);
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001191# endif /* architecture */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001192#endif /* LINUX */
1193
1194#ifdef SUNOS4
1195 struct regs regs;
1196
Roland McGratheb9e2e82009-06-02 16:49:22 -07001197 if (ptrace(PTRACE_GETREGS, tcp->pid, (char *) &regs, 0) < 0) {
1198 perror("printcall: ptrace(PTRACE_GETREGS, ...)");
Roland McGrath7a918832005-02-02 20:55:23 +00001199 PRINTBADPC;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001200 return;
1201 }
1202 tprintf("[%08x] ", regs.r_o7);
1203#endif /* SUNOS4 */
1204
1205#ifdef SVR4
1206 /* XXX */
Roland McGrath7a918832005-02-02 20:55:23 +00001207 PRINTBADPC;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001208#endif
1209
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001210#ifdef FREEBSD
1211 struct reg regs;
1212 pread(tcp->pfd_reg, &regs, sizeof(regs), 0);
1213 tprintf("[%08x] ", regs.r_eip);
1214#endif /* FREEBSD */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001215}
1216
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001217
1218/*
1219 * These #if's are huge, please indent them correctly.
1220 * It's easy to get confused otherwise.
1221 */
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001222#ifndef USE_PROCFS
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001223
Denys Vlasenkoe7c90242011-06-22 00:09:25 +02001224# ifdef LINUX
Roland McGrathd81f1d92003-01-09 06:53:34 +00001225
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001226# include "syscall.h"
Roland McGrath3291ef22008-05-20 00:34:34 +00001227
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001228# include <sys/syscall.h>
1229# ifndef CLONE_PTRACE
1230# define CLONE_PTRACE 0x00002000
1231# endif
1232# ifndef CLONE_VFORK
1233# define CLONE_VFORK 0x00004000
1234# endif
1235# ifndef CLONE_VM
1236# define CLONE_VM 0x00000100
1237# endif
1238# ifndef CLONE_STOPPED
1239# define CLONE_STOPPED 0x02000000
1240# endif
Roland McGrathd81f1d92003-01-09 06:53:34 +00001241
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001242# ifdef IA64
Roland McGrathd81f1d92003-01-09 06:53:34 +00001243
Roland McGrath08267b82004-02-20 22:56:43 +00001244/* We don't have fork()/vfork() syscalls on ia64 itself, but the ia32
1245 subsystem has them for x86... */
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001246# define SYS_fork 2
1247# define SYS_vfork 190
Roland McGrath08267b82004-02-20 22:56:43 +00001248
Roland McGrathd81f1d92003-01-09 06:53:34 +00001249typedef unsigned long *arg_setup_state;
1250
1251static int
1252arg_setup(struct tcb *tcp, arg_setup_state *state)
1253{
Jan Kratochvil1f942712008-08-06 21:38:52 +00001254 unsigned long cfm, sof, sol;
1255 long bsp;
Roland McGrathd81f1d92003-01-09 06:53:34 +00001256
Jan Kratochvil1f942712008-08-06 21:38:52 +00001257 if (ia32) {
1258 /* Satisfy a false GCC warning. */
1259 *state = NULL;
Roland McGrath08267b82004-02-20 22:56:43 +00001260 return 0;
Jan Kratochvil1f942712008-08-06 21:38:52 +00001261 }
Roland McGrath08267b82004-02-20 22:56:43 +00001262
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001263 if (upeek(tcp, PT_AR_BSP, &bsp) < 0)
Roland McGrathd81f1d92003-01-09 06:53:34 +00001264 return -1;
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001265 if (upeek(tcp, PT_CFM, (long *) &cfm) < 0)
Roland McGrathd81f1d92003-01-09 06:53:34 +00001266 return -1;
1267
1268 sof = (cfm >> 0) & 0x7f;
1269 sol = (cfm >> 7) & 0x7f;
Jan Kratochvil1f942712008-08-06 21:38:52 +00001270 bsp = (long) ia64_rse_skip_regs((unsigned long *) bsp, -sof + sol);
Roland McGrathd81f1d92003-01-09 06:53:34 +00001271
Jan Kratochvil1f942712008-08-06 21:38:52 +00001272 *state = (unsigned long *) bsp;
Roland McGrathd81f1d92003-01-09 06:53:34 +00001273 return 0;
1274}
1275
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001276# define arg_finish_change(tcp, state) 0
Roland McGrathd81f1d92003-01-09 06:53:34 +00001277
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001278# ifdef SYS_fork
Roland McGrathd81f1d92003-01-09 06:53:34 +00001279static int
Denys Vlasenko12014262011-05-30 14:00:14 +02001280get_arg0(struct tcb *tcp, arg_setup_state *state, long *valp)
Roland McGrathd81f1d92003-01-09 06:53:34 +00001281{
Roland McGrath08267b82004-02-20 22:56:43 +00001282 int ret;
1283
1284 if (ia32)
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001285 ret = upeek(tcp, PT_R11, valp);
Roland McGrath08267b82004-02-20 22:56:43 +00001286 else
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001287 ret = umoven(tcp,
Roland McGrath08267b82004-02-20 22:56:43 +00001288 (unsigned long) ia64_rse_skip_regs(*state, 0),
1289 sizeof(long), (void *) valp);
1290 return ret;
Roland McGrathd81f1d92003-01-09 06:53:34 +00001291}
1292
1293static int
Denys Vlasenko12014262011-05-30 14:00:14 +02001294get_arg1(struct tcb *tcp, arg_setup_state *state, long *valp)
Roland McGrathd81f1d92003-01-09 06:53:34 +00001295{
Roland McGrath08267b82004-02-20 22:56:43 +00001296 int ret;
1297
1298 if (ia32)
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001299 ret = upeek(tcp, PT_R9, valp);
Roland McGrath08267b82004-02-20 22:56:43 +00001300 else
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001301 ret = umoven(tcp,
Roland McGrath08267b82004-02-20 22:56:43 +00001302 (unsigned long) ia64_rse_skip_regs(*state, 1),
1303 sizeof(long), (void *) valp);
1304 return ret;
Roland McGrathd81f1d92003-01-09 06:53:34 +00001305}
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001306# endif
Roland McGrathd81f1d92003-01-09 06:53:34 +00001307
1308static int
Denys Vlasenko12014262011-05-30 14:00:14 +02001309set_arg0(struct tcb *tcp, arg_setup_state *state, long val)
Roland McGrathd81f1d92003-01-09 06:53:34 +00001310{
Roland McGrath08267b82004-02-20 22:56:43 +00001311 int req = PTRACE_POKEDATA;
1312 void *ap;
1313
1314 if (ia32) {
1315 ap = (void *) (intptr_t) PT_R11; /* r11 == EBX */
1316 req = PTRACE_POKEUSER;
1317 } else
1318 ap = ia64_rse_skip_regs(*state, 0);
Roland McGratheb9e2e82009-06-02 16:49:22 -07001319 errno = 0;
1320 ptrace(req, tcp->pid, ap, val);
1321 return errno ? -1 : 0;
Roland McGrathd81f1d92003-01-09 06:53:34 +00001322}
1323
1324static int
Denys Vlasenko12014262011-05-30 14:00:14 +02001325set_arg1(struct tcb *tcp, arg_setup_state *state, long val)
Roland McGrathd81f1d92003-01-09 06:53:34 +00001326{
Roland McGrath08267b82004-02-20 22:56:43 +00001327 int req = PTRACE_POKEDATA;
1328 void *ap;
1329
1330 if (ia32) {
1331 ap = (void *) (intptr_t) PT_R9; /* r9 == ECX */
1332 req = PTRACE_POKEUSER;
1333 } else
1334 ap = ia64_rse_skip_regs(*state, 1);
Roland McGratheb9e2e82009-06-02 16:49:22 -07001335 errno = 0;
1336 ptrace(req, tcp->pid, ap, val);
1337 return errno ? -1 : 0;
Roland McGrathd81f1d92003-01-09 06:53:34 +00001338}
1339
Roland McGrathb659f872008-07-18 01:19:36 +00001340/* ia64 does not return the input arguments from functions (and syscalls)
1341 according to ia64 RSE (Register Stack Engine) behavior. */
1342
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001343# define restore_arg0(tcp, state, val) ((void) (state), 0)
1344# define restore_arg1(tcp, state, val) ((void) (state), 0)
Roland McGrathb659f872008-07-18 01:19:36 +00001345
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001346# elif defined (SPARC) || defined (SPARC64)
Roland McGrathd81f1d92003-01-09 06:53:34 +00001347
Mike Frysinger8566c502009-10-12 11:05:14 -04001348typedef struct pt_regs arg_setup_state;
Roland McGrathd81f1d92003-01-09 06:53:34 +00001349
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001350# define arg_setup(tcp, state) \
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001351 (ptrace(PTRACE_GETREGS, tcp->pid, (char *) (state), 0))
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001352# define arg_finish_change(tcp, state) \
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001353 (ptrace(PTRACE_SETREGS, tcp->pid, (char *) (state), 0))
Roland McGrathd81f1d92003-01-09 06:53:34 +00001354
Mike Frysinger8566c502009-10-12 11:05:14 -04001355# define get_arg0(tcp, state, valp) (*(valp) = (state)->u_regs[U_REG_O0], 0)
1356# define get_arg1(tcp, state, valp) (*(valp) = (state)->u_regs[U_REG_O1], 0)
1357# define set_arg0(tcp, state, val) ((state)->u_regs[U_REG_O0] = (val), 0)
1358# define set_arg1(tcp, state, val) ((state)->u_regs[U_REG_O1] = (val), 0)
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001359# define restore_arg0(tcp, state, val) 0
Roland McGrathd81f1d92003-01-09 06:53:34 +00001360
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001361# else /* other architectures */
Roland McGrathd81f1d92003-01-09 06:53:34 +00001362
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001363# if defined S390 || defined S390X
Roland McGrath7b308222003-01-20 09:04:36 +00001364/* Note: this is only true for the `clone' system call, which handles
1365 arguments specially. We could as well say that its first two arguments
1366 are swapped relative to other architectures, but that would just be
1367 another #ifdef in the calls. */
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001368# define arg0_offset PT_GPR3
1369# define arg1_offset PT_ORIGGPR2
1370# define restore_arg0(tcp, state, val) ((void) (state), 0)
1371# define restore_arg1(tcp, state, val) ((void) (state), 0)
1372# define arg0_index 1
1373# define arg1_index 0
1374# elif defined (ALPHA) || defined (MIPS)
1375# define arg0_offset REG_A0
1376# define arg1_offset (REG_A0+1)
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00001377# elif defined (AVR32)
1378# define arg0_offset (REG_R12)
1379# define arg1_offset (REG_R11)
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001380# elif defined (POWERPC)
1381# define arg0_offset (sizeof(unsigned long)*PT_R3)
1382# define arg1_offset (sizeof(unsigned long)*PT_R4)
1383# define restore_arg0(tcp, state, val) ((void) (state), 0)
1384# elif defined (HPPA)
1385# define arg0_offset PT_GR26
1386# define arg1_offset (PT_GR26-4)
1387# elif defined (X86_64)
1388# define arg0_offset ((long)(8*(current_personality ? RBX : RDI)))
1389# define arg1_offset ((long)(8*(current_personality ? RCX : RSI)))
1390# elif defined (SH)
1391# define arg0_offset (4*(REG_REG0+4))
1392# define arg1_offset (4*(REG_REG0+5))
1393# elif defined (SH64)
1394 /* ABI defines arg0 & 1 in r2 & r3 */
1395# define arg0_offset (REG_OFFSET+16)
1396# define arg1_offset (REG_OFFSET+24)
1397# define restore_arg0(tcp, state, val) 0
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001398# elif defined CRISV10 || defined CRISV32
1399# define arg0_offset (4*PT_R11)
1400# define arg1_offset (4*PT_ORIG_R10)
1401# define restore_arg0(tcp, state, val) 0
1402# define restore_arg1(tcp, state, val) 0
1403# define arg0_index 1
1404# define arg1_index 0
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001405# else
1406# define arg0_offset 0
1407# define arg1_offset 4
1408# if defined ARM
1409# define restore_arg0(tcp, state, val) 0
1410# endif
1411# endif
Roland McGrathd81f1d92003-01-09 06:53:34 +00001412
1413typedef int arg_setup_state;
1414
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001415# define arg_setup(tcp, state) (0)
1416# define arg_finish_change(tcp, state) 0
1417# define get_arg0(tcp, cookie, valp) \
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001418 (upeek((tcp), arg0_offset, (valp)))
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001419# define get_arg1(tcp, cookie, valp) \
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001420 (upeek((tcp), arg1_offset, (valp)))
Roland McGrathd81f1d92003-01-09 06:53:34 +00001421
1422static int
Denys Vlasenko12014262011-05-30 14:00:14 +02001423set_arg0(struct tcb *tcp, void *cookie, long val)
Roland McGrathd81f1d92003-01-09 06:53:34 +00001424{
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001425 return ptrace(PTRACE_POKEUSER, tcp->pid, (char*)arg0_offset, val);
Roland McGrathd81f1d92003-01-09 06:53:34 +00001426}
1427
1428static int
Denys Vlasenko12014262011-05-30 14:00:14 +02001429set_arg1(struct tcb *tcp, void *cookie, long val)
Roland McGrathd81f1d92003-01-09 06:53:34 +00001430{
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001431 return ptrace(PTRACE_POKEUSER, tcp->pid, (char*)arg1_offset, val);
Roland McGrathd81f1d92003-01-09 06:53:34 +00001432}
1433
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001434# endif /* architectures */
Roland McGrathd81f1d92003-01-09 06:53:34 +00001435
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001436# ifndef restore_arg0
1437# define restore_arg0(tcp, state, val) set_arg0((tcp), (state), (val))
1438# endif
1439# ifndef restore_arg1
1440# define restore_arg1(tcp, state, val) set_arg1((tcp), (state), (val))
1441# endif
Roland McGrathd81f1d92003-01-09 06:53:34 +00001442
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001443# ifndef arg0_index
1444# define arg0_index 0
1445# define arg1_index 1
1446# endif
Roland McGrath90d0afd2004-03-01 21:05:16 +00001447
Roland McGrathd81f1d92003-01-09 06:53:34 +00001448int
Denys Vlasenko418d66a2009-01-17 01:52:54 +00001449setbpt(struct tcb *tcp)
Roland McGrathd81f1d92003-01-09 06:53:34 +00001450{
Roland McGrath3291ef22008-05-20 00:34:34 +00001451 static int clone_scno[SUPPORTED_PERSONALITIES] = { SYS_clone };
Roland McGrathd81f1d92003-01-09 06:53:34 +00001452 arg_setup_state state;
1453
1454 if (tcp->flags & TCB_BPTSET) {
1455 fprintf(stderr, "PANIC: TCB already set in pid %u\n", tcp->pid);
1456 return -1;
1457 }
1458
Roland McGrath3291ef22008-05-20 00:34:34 +00001459 /*
1460 * It's a silly kludge to initialize this with a search at runtime.
1461 * But it's better than maintaining another magic thing in the
1462 * godforsaken tables.
1463 */
1464 if (clone_scno[current_personality] == 0) {
1465 int i;
1466 for (i = 0; i < nsyscalls; ++i)
1467 if (sysent[i].sys_func == sys_clone) {
1468 clone_scno[current_personality] = i;
1469 break;
1470 }
1471 }
1472
Roland McGrath76989d72005-06-07 23:21:31 +00001473 switch (known_scno(tcp)) {
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001474# ifdef SYS_vfork
Roland McGrath9383c6c2003-01-18 00:19:31 +00001475 case SYS_vfork:
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001476# endif
1477# ifdef SYS_fork
Roland McGrathd81f1d92003-01-09 06:53:34 +00001478 case SYS_fork:
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001479# endif
1480# if defined SYS_fork || defined SYS_vfork
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001481 if (arg_setup(tcp, &state) < 0
1482 || get_arg0(tcp, &state, &tcp->inst[0]) < 0
1483 || get_arg1(tcp, &state, &tcp->inst[1]) < 0
Roland McGrath3291ef22008-05-20 00:34:34 +00001484 || change_syscall(tcp, clone_scno[current_personality]) < 0
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001485 || set_arg0(tcp, &state, CLONE_PTRACE|SIGCHLD) < 0
1486 || set_arg1(tcp, &state, 0) < 0
1487 || arg_finish_change(tcp, &state) < 0)
Roland McGrathd81f1d92003-01-09 06:53:34 +00001488 return -1;
Roland McGrathc9dc3c12004-03-01 20:57:09 +00001489 tcp->u_arg[arg0_index] = CLONE_PTRACE|SIGCHLD;
1490 tcp->u_arg[arg1_index] = 0;
Roland McGrathd81f1d92003-01-09 06:53:34 +00001491 tcp->flags |= TCB_BPTSET;
1492 return 0;
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001493# endif
Roland McGrathd81f1d92003-01-09 06:53:34 +00001494
Denys Vlasenkoc133bf02011-06-23 21:57:54 +02001495 case SYS_clone: ;
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001496# ifdef SYS_clone2
Denys Vlasenkoc133bf02011-06-23 21:57:54 +02001497 case SYS_clone2: ;
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001498# endif
Jan Kratochvil8fc95752008-08-06 21:43:35 +00001499 /* ia64 calls directly `clone (CLONE_VFORK | CLONE_VM)'
1500 contrary to x86 SYS_vfork above. Even on x86 we turn the
1501 vfork semantics into plain fork - each application must not
1502 depend on the vfork specifics according to POSIX. We would
1503 hang waiting for the parent resume otherwise. We need to
1504 clear also CLONE_VM but only in the CLONE_VFORK case as
1505 otherwise we would break pthread_create. */
1506
Denys Vlasenkoc133bf02011-06-23 21:57:54 +02001507 long new_arg0 = (tcp->u_arg[arg0_index] | CLONE_PTRACE);
1508 if (new_arg0 & CLONE_VFORK)
1509 new_arg0 &= ~(unsigned long)(CLONE_VFORK | CLONE_VM);
1510 if (arg_setup(tcp, &state) < 0
1511 || set_arg0(tcp, &state, new_arg0) < 0
1512 || arg_finish_change(tcp, &state) < 0)
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00001513 return -1;
Roland McGrathd81f1d92003-01-09 06:53:34 +00001514 tcp->flags |= TCB_BPTSET;
Roland McGrathc9dc3c12004-03-01 20:57:09 +00001515 tcp->inst[0] = tcp->u_arg[arg0_index];
1516 tcp->inst[1] = tcp->u_arg[arg1_index];
Roland McGrathd81f1d92003-01-09 06:53:34 +00001517 return 0;
1518
1519 default:
1520 fprintf(stderr, "PANIC: setbpt for syscall %ld on %u???\n",
1521 tcp->scno, tcp->pid);
1522 break;
1523 }
1524
1525 return -1;
1526}
1527
1528int
Denys Vlasenko12014262011-05-30 14:00:14 +02001529clearbpt(struct tcb *tcp)
Roland McGrathd81f1d92003-01-09 06:53:34 +00001530{
1531 arg_setup_state state;
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001532 if (arg_setup(tcp, &state) < 0
1533 || restore_arg0(tcp, &state, tcp->inst[0]) < 0
1534 || restore_arg1(tcp, &state, tcp->inst[1]) < 0
1535 || arg_finish_change(tcp, &state))
Denys Vlasenkoc133bf02011-06-23 21:57:54 +02001536 if (errno != ESRCH)
1537 return -1;
Roland McGrathd81f1d92003-01-09 06:53:34 +00001538 tcp->flags &= ~TCB_BPTSET;
1539 return 0;
1540}
1541
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001542# else /* !defined LINUX */
Roland McGrathd81f1d92003-01-09 06:53:34 +00001543
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001544int
Denys Vlasenko12014262011-05-30 14:00:14 +02001545setbpt(struct tcb *tcp)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001546{
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001547# ifdef SUNOS4
1548# ifdef SPARC /* This code is slightly sparc specific */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001549
Wichert Akkermane6f876c1999-06-22 15:28:30 +00001550 struct regs regs;
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001551# define BPT 0x91d02001 /* ta 1 */
1552# define LOOP 0x10800000 /* ba 0 */
1553# define LOOPA 0x30800000 /* ba,a 0 */
1554# define NOP 0x01000000
1555# if LOOPA
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001556 static int loopdeloop[1] = {LOOPA};
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001557# else
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001558 static int loopdeloop[2] = {LOOP, NOP};
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001559# endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001560
1561 if (tcp->flags & TCB_BPTSET) {
1562 fprintf(stderr, "PANIC: TCB already set in pid %u\n", tcp->pid);
1563 return -1;
1564 }
Roland McGratheb9e2e82009-06-02 16:49:22 -07001565 if (ptrace(PTRACE_GETREGS, tcp->pid, (char *)&regs, 0) < 0) {
1566 perror("setbpt: ptrace(PTRACE_GETREGS, ...)");
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001567 return -1;
1568 }
1569 tcp->baddr = regs.r_o7 + 8;
Roland McGratheb9e2e82009-06-02 16:49:22 -07001570 if (ptrace(PTRACE_READTEXT, tcp->pid, (char *)tcp->baddr,
1571 sizeof tcp->inst, (char *)tcp->inst) < 0) {
1572 perror("setbpt: ptrace(PTRACE_READTEXT, ...)");
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001573 return -1;
1574 }
1575
1576 /*
1577 * XXX - BRUTAL MODE ON
1578 * We cannot set a real BPT in the child, since it will not be
1579 * traced at the moment it will reach the trap and would probably
1580 * die with a core dump.
1581 * Thus, we are force our way in by taking out two instructions
1582 * and insert an eternal loop in stead, in expectance of the SIGSTOP
1583 * generated by out PTRACE_ATTACH.
1584 * Of cause, if we evaporate ourselves in the middle of all this...
1585 */
Roland McGratheb9e2e82009-06-02 16:49:22 -07001586 if (ptrace(PTRACE_WRITETEXT, tcp->pid, (char *) tcp->baddr,
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001587 sizeof loopdeloop, (char *) loopdeloop) < 0) {
Roland McGratheb9e2e82009-06-02 16:49:22 -07001588 perror("setbpt: ptrace(PTRACE_WRITETEXT, ...)");
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001589 return -1;
1590 }
1591 tcp->flags |= TCB_BPTSET;
1592
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001593# endif /* SPARC */
1594# endif /* SUNOS4 */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001595
1596 return 0;
1597}
1598
1599int
Denys Vlasenko12014262011-05-30 14:00:14 +02001600clearbpt(struct tcb *tcp)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001601{
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001602# ifdef SUNOS4
1603# ifdef SPARC
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001604
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001605# if !LOOPA
Wichert Akkermane6f876c1999-06-22 15:28:30 +00001606 struct regs regs;
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001607# endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001608
1609 if (!(tcp->flags & TCB_BPTSET)) {
1610 fprintf(stderr, "PANIC: TCB not set in pid %u\n", tcp->pid);
1611 return -1;
1612 }
Roland McGratheb9e2e82009-06-02 16:49:22 -07001613 if (ptrace(PTRACE_WRITETEXT, tcp->pid, (char *) tcp->baddr,
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001614 sizeof tcp->inst, (char *) tcp->inst) < 0) {
Roland McGratheb9e2e82009-06-02 16:49:22 -07001615 perror("clearbtp: ptrace(PTRACE_WRITETEXT, ...)");
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001616 return -1;
1617 }
1618 tcp->flags &= ~TCB_BPTSET;
1619
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001620# if !LOOPA
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001621 /*
1622 * Since we don't have a single instruction breakpoint, we may have
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001623 * to adjust the program counter after removing our `breakpoint'.
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001624 */
Roland McGratheb9e2e82009-06-02 16:49:22 -07001625 if (ptrace(PTRACE_GETREGS, tcp->pid, (char *)&regs, 0) < 0) {
1626 perror("clearbpt: ptrace(PTRACE_GETREGS, ...)");
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001627 return -1;
1628 }
Roland McGratheb9e2e82009-06-02 16:49:22 -07001629 if ((regs.r_pc < tcp->baddr) ||
1630 (regs.r_pc > tcp->baddr + 4)) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001631 /* The breakpoint has not been reached yet */
1632 if (debug)
1633 fprintf(stderr,
1634 "NOTE: PC not at bpt (pc %#x baddr %#x)\n",
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001635 regs.r_pc, tcp->baddr);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001636 return 0;
1637 }
1638 if (regs.r_pc != tcp->baddr)
1639 if (debug)
1640 fprintf(stderr, "NOTE: PC adjusted (%#x -> %#x\n",
1641 regs.r_pc, tcp->baddr);
1642
1643 regs.r_pc = tcp->baddr;
Roland McGratheb9e2e82009-06-02 16:49:22 -07001644 if (ptrace(PTRACE_SETREGS, tcp->pid, (char *)&regs, 0) < 0) {
1645 perror("clearbpt: ptrace(PTRACE_SETREGS, ...)");
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001646 return -1;
1647 }
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001648# endif /* LOOPA */
1649# endif /* SPARC */
1650# endif /* SUNOS4 */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001651
1652 return 0;
1653}
1654
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001655# endif /* !defined LINUX */
Roland McGrathd81f1d92003-01-09 06:53:34 +00001656
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001657#endif /* !USE_PROCFS */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001658
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001659
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001660#ifdef SUNOS4
1661
1662static int
Denys Vlasenko12014262011-05-30 14:00:14 +02001663getex(struct tcb *tcp, struct exec *hdr)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001664{
1665 int n;
1666
1667 for (n = 0; n < sizeof *hdr; n += 4) {
1668 long res;
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001669 if (upeek(tcp, uoff(u_exdata) + n, &res) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001670 return -1;
1671 memcpy(((char *) hdr) + n, &res, 4);
1672 }
1673 if (debug) {
1674 fprintf(stderr, "[struct exec: magic: %o version %u Mach %o\n",
1675 hdr->a_magic, hdr->a_toolversion, hdr->a_machtype);
1676 fprintf(stderr, "Text %lu Data %lu Bss %lu Syms %lu Entry %#lx]\n",
1677 hdr->a_text, hdr->a_data, hdr->a_bss, hdr->a_syms, hdr->a_entry);
1678 }
1679 return 0;
1680}
1681
1682int
Denys Vlasenko12014262011-05-30 14:00:14 +02001683fixvfork(struct tcb *tcp)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001684{
1685 int pid = tcp->pid;
1686 /*
1687 * Change `vfork' in a freshly exec'ed dynamically linked
1688 * executable's (internal) symbol table to plain old `fork'
1689 */
1690
1691 struct exec hdr;
1692 struct link_dynamic dyn;
1693 struct link_dynamic_2 ld;
1694 char *strtab, *cp;
1695
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001696 if (getex(tcp, &hdr) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001697 return -1;
1698 if (!hdr.a_dynamic)
1699 return -1;
1700
1701 if (umove(tcp, (int) N_DATADDR(hdr), &dyn) < 0) {
1702 fprintf(stderr, "Cannot read DYNAMIC\n");
1703 return -1;
1704 }
1705 if (umove(tcp, (int) dyn.ld_un.ld_2, &ld) < 0) {
1706 fprintf(stderr, "Cannot read link_dynamic_2\n");
1707 return -1;
1708 }
Denys Vlasenko5d645812011-08-20 12:48:18 +02001709 strtab = malloc((unsigned)ld.ld_symb_size);
1710 if (strtab == NULL) {
Roland McGrath46100d02005-06-01 18:55:42 +00001711 fprintf(stderr, "out of memory\n");
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001712 return -1;
1713 }
Roland McGratheb9e2e82009-06-02 16:49:22 -07001714 if (umoven(tcp, (int)ld.ld_symbols+(int)N_TXTADDR(hdr),
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001715 (int)ld.ld_symb_size, strtab) < 0)
1716 goto err;
1717
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001718 for (cp = strtab; cp < strtab + ld.ld_symb_size; ) {
1719 if (strcmp(cp, "_vfork") == 0) {
1720 if (debug)
1721 fprintf(stderr, "fixvfork: FOUND _vfork\n");
1722 strcpy(cp, "_fork");
1723 break;
1724 }
1725 cp += strlen(cp)+1;
1726 }
1727 if (cp < strtab + ld.ld_symb_size)
1728 /*
1729 * Write entire symbol table back to avoid
1730 * memory alignment bugs in ptrace
1731 */
Roland McGratheb9e2e82009-06-02 16:49:22 -07001732 if (tload(pid, (int)ld.ld_symbols+(int)N_TXTADDR(hdr),
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001733 (int)ld.ld_symb_size, strtab) < 0)
1734 goto err;
1735
1736 free(strtab);
1737 return 0;
1738
1739err:
1740 free(strtab);
1741 return -1;
1742}
1743
1744#endif /* SUNOS4 */