blob: bfa2856a1d5d87e41814c54814c1b03117701db0 [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) {
690 if (str)
691 free(str);
692 if ((str = malloc(len)) == 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) {
851 if (move > left) move = left;
John Hughes9cecf7f2001-10-16 10:20:22 +0000852 if ((move = read(fd, laddr, move)) <= 0)
John Hughesaa09c6b2001-05-15 14:53:43 +0000853 return left != len ? 0 : -1;
Denys Vlasenkob63256e2011-06-07 12:13:24 +0200854 if (memchr(laddr, 0, move)) break;
John Hughesaa09c6b2001-05-15 14:53:43 +0000855 left -= move;
856 laddr += move;
857 addr += move;
858 move = page;
859 }
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000860#else /* !USE_PROCFS */
Wichert Akkerman5daa0281999-03-15 19:49:42 +0000861 int started = 0;
Roland McGratheb9e2e82009-06-02 16:49:22 -0700862 int pid = tcp->pid;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000863 int i, n, m;
864 union {
865 long val;
866 char x[sizeof(long)];
867 } u;
868
869 if (addr & (sizeof(long) - 1)) {
870 /* addr not a multiple of sizeof(long) */
871 n = addr - (addr & -sizeof(long)); /* residue */
872 addr &= -sizeof(long); /* residue */
Roland McGratheb9e2e82009-06-02 16:49:22 -0700873 errno = 0;
874 u.val = ptrace(PTRACE_PEEKDATA, pid, (char *)addr, 0);
875 if (errno) {
876 if (started && (errno==EPERM || errno==EIO)) {
877 /* Ran into 'end of memory' - stupid "printpath" */
878 return 0;
879 }
880 if (addr != 0 && errno != EIO && errno != ESRCH)
881 perror("umovestr");
882 return -1;
883 }
Wichert Akkerman5daa0281999-03-15 19:49:42 +0000884 started = 1;
Denys Vlasenkob63256e2011-06-07 12:13:24 +0200885 memcpy(laddr, &u.x[n], m = MIN(sizeof(long)-n, len));
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000886 while (n & (sizeof(long) - 1))
887 if (u.x[n++] == '\0')
888 return 0;
889 addr += sizeof(long), laddr += m, len -= m;
890 }
891 while (len) {
Roland McGratheb9e2e82009-06-02 16:49:22 -0700892 errno = 0;
893 u.val = ptrace(PTRACE_PEEKDATA, pid, (char *)addr, 0);
894 if (errno) {
895 if (started && (errno==EPERM || errno==EIO)) {
896 /* Ran into 'end of memory' - stupid "printpath" */
897 return 0;
898 }
899 if (addr != 0 && errno != EIO && errno != ESRCH)
900 perror("umovestr");
901 return -1;
902 }
Wichert Akkerman5daa0281999-03-15 19:49:42 +0000903 started = 1;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000904 memcpy(laddr, u.x, m = MIN(sizeof(long), len));
905 for (i = 0; i < sizeof(long); i++)
906 if (u.x[i] == '\0')
907 return 0;
908
909 addr += sizeof(long), laddr += m, len -= m;
910 }
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000911#endif /* !USE_PROCFS */
John Hughesaa09c6b2001-05-15 14:53:43 +0000912 return 0;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000913}
914
915#ifdef LINUX
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +0000916# if !defined (SPARC) && !defined(SPARC64)
917# define PTRACE_WRITETEXT 101
918# define PTRACE_WRITEDATA 102
919# endif /* !SPARC && !SPARC64 */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000920#endif /* LINUX */
921
922#ifdef SUNOS4
923
924static int
Denys Vlasenko12014262011-05-30 14:00:14 +0200925uload(int cmd, int pid, long addr, int len, char *laddr)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000926{
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000927 int peek, poke;
928 int n, m;
929 union {
930 long val;
931 char x[sizeof(long)];
932 } u;
933
934 if (cmd == PTRACE_WRITETEXT) {
935 peek = PTRACE_PEEKTEXT;
936 poke = PTRACE_POKETEXT;
937 }
938 else {
939 peek = PTRACE_PEEKDATA;
940 poke = PTRACE_POKEDATA;
941 }
942 if (addr & (sizeof(long) - 1)) {
943 /* addr not a multiple of sizeof(long) */
944 n = addr - (addr & -sizeof(long)); /* residue */
945 addr &= -sizeof(long);
Roland McGratheb9e2e82009-06-02 16:49:22 -0700946 errno = 0;
947 u.val = ptrace(peek, pid, (char *) addr, 0);
948 if (errno) {
949 perror("uload: POKE");
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000950 return -1;
951 }
Roland McGratheb9e2e82009-06-02 16:49:22 -0700952 memcpy(&u.x[n], laddr, m = MIN(sizeof(long) - n, len));
953 if (ptrace(poke, pid, (char *)addr, u.val) < 0) {
954 perror("uload: POKE");
955 return -1;
956 }
957 addr += sizeof(long), laddr += m, len -= m;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000958 }
959 while (len) {
960 if (len < sizeof(long))
Roland McGratheb9e2e82009-06-02 16:49:22 -0700961 u.val = ptrace(peek, pid, (char *) addr, 0);
962 memcpy(u.x, laddr, m = MIN(sizeof(long), len));
963 if (ptrace(poke, pid, (char *) addr, u.val) < 0) {
964 perror("uload: POKE");
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000965 return -1;
966 }
Roland McGratheb9e2e82009-06-02 16:49:22 -0700967 addr += sizeof(long), laddr += m, len -= m;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000968 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000969 return 0;
970}
971
Roland McGratheb9e2e82009-06-02 16:49:22 -0700972int
Denys Vlasenko12014262011-05-30 14:00:14 +0200973tload(int pid, int addr, int len, char *laddr)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000974{
Roland McGratheb9e2e82009-06-02 16:49:22 -0700975 return uload(PTRACE_WRITETEXT, pid, addr, len, laddr);
976}
977
978int
Denys Vlasenko12014262011-05-30 14:00:14 +0200979dload(int pid, int addr, int len, char *laddr)
Roland McGratheb9e2e82009-06-02 16:49:22 -0700980{
981 return uload(PTRACE_WRITEDATA, pid, addr, len, laddr);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000982}
983
984#endif /* SUNOS4 */
985
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000986#ifndef USE_PROCFS
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000987
988int
Denys Vlasenko12014262011-05-30 14:00:14 +0200989upeek(struct tcb *tcp, long off, long *res)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000990{
991 long val;
992
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +0000993# ifdef SUNOS4_KERNEL_ARCH_KLUDGE
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000994 {
995 static int is_sun4m = -1;
996 struct utsname name;
997
998 /* Round up the usual suspects. */
999 if (is_sun4m == -1) {
1000 if (uname(&name) < 0) {
1001 perror("upeek: uname?");
1002 exit(1);
1003 }
1004 is_sun4m = strcmp(name.machine, "sun4m") == 0;
1005 if (is_sun4m) {
Roland McGrathd9f816f2004-09-04 03:39:20 +00001006 const struct xlat *x;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001007
1008 for (x = struct_user_offsets; x->str; x++)
1009 x->val += 1024;
1010 }
1011 }
1012 if (is_sun4m)
1013 off += 1024;
1014 }
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001015# endif /* SUNOS4_KERNEL_ARCH_KLUDGE */
Roland McGratheb9e2e82009-06-02 16:49:22 -07001016 errno = 0;
Denys Vlasenko732d1bf2008-12-17 19:21:59 +00001017 val = do_ptrace(PTRACE_PEEKUSER, tcp, (char *) off, 0);
Roland McGratheb9e2e82009-06-02 16:49:22 -07001018 if (val == -1 && errno) {
1019 if (errno != ESRCH) {
1020 char buf[60];
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001021 sprintf(buf, "upeek: ptrace(PTRACE_PEEKUSER,%d,%lu,0)", tcp->pid, off);
Roland McGratheb9e2e82009-06-02 16:49:22 -07001022 perror(buf);
1023 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001024 return -1;
Roland McGratheb9e2e82009-06-02 16:49:22 -07001025 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001026 *res = val;
1027 return 0;
1028}
1029
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001030#endif /* !USE_PROCFS */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001031
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001032void
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001033printcall(struct tcb *tcp)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001034{
Roland McGrath7a918832005-02-02 20:55:23 +00001035#define PRINTBADPC tprintf(sizeof(long) == 4 ? "[????????] " : \
1036 sizeof(long) == 8 ? "[????????????????] " : \
1037 NULL /* crash */)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001038
1039#ifdef LINUX
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001040# ifdef I386
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001041 long eip;
1042
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001043 if (upeek(tcp, 4*EIP, &eip) < 0) {
Roland McGrath7a918832005-02-02 20:55:23 +00001044 PRINTBADPC;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001045 return;
1046 }
1047 tprintf("[%08lx] ", eip);
Roland McGratheac26fc2005-02-02 02:48:53 +00001048
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001049# elif defined(S390) || defined(S390X)
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001050 long psw;
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001051 if (upeek(tcp, PT_PSWADDR, &psw) < 0) {
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001052 PRINTBADPC;
1053 return;
1054 }
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001055# ifdef S390
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001056 tprintf("[%08lx] ", psw);
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001057# elif S390X
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001058 tprintf("[%16lx] ", psw);
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001059# endif
Roland McGratheac26fc2005-02-02 02:48:53 +00001060
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001061# elif defined(X86_64)
Michal Ludvig0e035502002-09-23 15:41:01 +00001062 long rip;
1063
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001064 if (upeek(tcp, 8*RIP, &rip) < 0) {
Roland McGrath7a918832005-02-02 20:55:23 +00001065 PRINTBADPC;
Michal Ludvig0e035502002-09-23 15:41:01 +00001066 return;
1067 }
1068 tprintf("[%16lx] ", rip);
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001069# elif defined(IA64)
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00001070 long ip;
1071
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001072 if (upeek(tcp, PT_B0, &ip) < 0) {
Roland McGrath7a918832005-02-02 20:55:23 +00001073 PRINTBADPC;
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00001074 return;
1075 }
1076 tprintf("[%08lx] ", ip);
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001077# elif defined(POWERPC)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001078 long pc;
1079
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001080 if (upeek(tcp, sizeof(unsigned long)*PT_NIP, &pc) < 0) {
Andreas Schwabd69fa492010-07-12 21:39:57 +02001081 PRINTBADPC;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001082 return;
1083 }
Andreas Schwabd69fa492010-07-12 21:39:57 +02001084# ifdef POWERPC64
1085 tprintf("[%016lx] ", pc);
1086# else
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001087 tprintf("[%08lx] ", pc);
Andreas Schwabd69fa492010-07-12 21:39:57 +02001088# endif
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001089# elif defined(M68K)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001090 long pc;
1091
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001092 if (upeek(tcp, 4*PT_PC, &pc) < 0) {
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001093 tprintf("[????????] ");
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001094 return;
1095 }
1096 tprintf("[%08lx] ", pc);
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001097# elif defined(ALPHA)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001098 long pc;
1099
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001100 if (upeek(tcp, REG_PC, &pc) < 0) {
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001101 tprintf("[????????????????] ");
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001102 return;
1103 }
1104 tprintf("[%08lx] ", pc);
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001105# elif defined(SPARC) || defined(SPARC64)
Mike Frysinger8566c502009-10-12 11:05:14 -04001106 struct pt_regs regs;
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001107 if (ptrace(PTRACE_GETREGS, tcp->pid, (char *)&regs, 0) < 0) {
Roland McGrath7a918832005-02-02 20:55:23 +00001108 PRINTBADPC;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001109 return;
1110 }
Mike Frysinger8566c502009-10-12 11:05:14 -04001111# if defined(SPARC64)
1112 tprintf("[%08lx] ", regs.tpc);
1113# else
1114 tprintf("[%08lx] ", regs.pc);
1115# endif
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001116# elif defined(HPPA)
Wichert Akkermanc1652e22001-03-27 12:17:16 +00001117 long pc;
1118
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001119 if (upeek(tcp, PT_IAOQ0, &pc) < 0) {
1120 tprintf("[????????] ");
Wichert Akkermanc1652e22001-03-27 12:17:16 +00001121 return;
1122 }
1123 tprintf("[%08lx] ", pc);
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001124# elif defined(MIPS)
Wichert Akkerman75c422b2001-04-10 10:22:50 +00001125 long pc;
1126
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001127 if (upeek(tcp, REG_EPC, &pc) < 0) {
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001128 tprintf("[????????] ");
Wichert Akkerman75c422b2001-04-10 10:22:50 +00001129 return;
1130 }
1131 tprintf("[%08lx] ", pc);
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001132# elif defined(SH)
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001133 long pc;
Wichert Akkermanccef6372002-05-01 16:39:22 +00001134
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001135 if (upeek(tcp, 4*REG_PC, &pc) < 0) {
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001136 tprintf("[????????] ");
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001137 return;
1138 }
1139 tprintf("[%08lx] ", pc);
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001140# elif defined(SH64)
Roland McGrathe1e584b2003-06-02 19:18:58 +00001141 long pc;
1142
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001143 if (upeek(tcp, REG_PC, &pc) < 0) {
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001144 tprintf("[????????????????] ");
Roland McGrathe1e584b2003-06-02 19:18:58 +00001145 return;
1146 }
1147 tprintf("[%08lx] ", pc);
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001148# elif defined(ARM)
Roland McGrathef388682003-06-03 23:28:59 +00001149 long pc;
Roland McGrathe1e584b2003-06-02 19:18:58 +00001150
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001151 if (upeek(tcp, 4*15, &pc) < 0) {
Roland McGrath7a918832005-02-02 20:55:23 +00001152 PRINTBADPC;
Roland McGrathef388682003-06-03 23:28:59 +00001153 return;
1154 }
1155 tprintf("[%08lx] ", pc);
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00001156# elif defined(AVR32)
1157 long pc;
1158
1159 if (upeek(tcp, REG_PC, &pc) < 0) {
1160 tprintf("[????????] ");
1161 return;
1162 }
1163 tprintf("[%08lx] ", pc);
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001164# elif defined(BFIN)
Dmitry V. Levin87ea1f42008-11-10 22:21:41 +00001165 long pc;
1166
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001167 if (upeek(tcp, PT_PC, &pc) < 0) {
Dmitry V. Levin87ea1f42008-11-10 22:21:41 +00001168 PRINTBADPC;
1169 return;
1170 }
1171 tprintf("[%08lx] ", pc);
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001172#elif defined(CRISV10)
1173 long pc;
1174
Edgar E. Iglesiaseeb9ce32009-10-05 14:41:02 +00001175 if (upeek(tcp, 4*PT_IRP, &pc) < 0) {
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001176 PRINTBADPC;
1177 return;
1178 }
1179 tprintf("[%08lx] ", pc);
1180#elif defined(CRISV32)
1181 long pc;
1182
Edgar E. Iglesiaseeb9ce32009-10-05 14:41:02 +00001183 if (upeek(tcp, 4*PT_ERP, &pc) < 0) {
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001184 PRINTBADPC;
1185 return;
1186 }
1187 tprintf("[%08lx] ", pc);
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001188# endif /* architecture */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001189#endif /* LINUX */
1190
1191#ifdef SUNOS4
1192 struct regs regs;
1193
Roland McGratheb9e2e82009-06-02 16:49:22 -07001194 if (ptrace(PTRACE_GETREGS, tcp->pid, (char *) &regs, 0) < 0) {
1195 perror("printcall: ptrace(PTRACE_GETREGS, ...)");
Roland McGrath7a918832005-02-02 20:55:23 +00001196 PRINTBADPC;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001197 return;
1198 }
1199 tprintf("[%08x] ", regs.r_o7);
1200#endif /* SUNOS4 */
1201
1202#ifdef SVR4
1203 /* XXX */
Roland McGrath7a918832005-02-02 20:55:23 +00001204 PRINTBADPC;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001205#endif
1206
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001207#ifdef FREEBSD
1208 struct reg regs;
1209 pread(tcp->pfd_reg, &regs, sizeof(regs), 0);
1210 tprintf("[%08x] ", regs.r_eip);
1211#endif /* FREEBSD */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001212}
1213
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001214
1215/*
1216 * These #if's are huge, please indent them correctly.
1217 * It's easy to get confused otherwise.
1218 */
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001219#ifndef USE_PROCFS
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001220
Denys Vlasenkoe7c90242011-06-22 00:09:25 +02001221# ifdef LINUX
Roland McGrathd81f1d92003-01-09 06:53:34 +00001222
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001223# include "syscall.h"
Roland McGrath3291ef22008-05-20 00:34:34 +00001224
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001225# include <sys/syscall.h>
1226# ifndef CLONE_PTRACE
1227# define CLONE_PTRACE 0x00002000
1228# endif
1229# ifndef CLONE_VFORK
1230# define CLONE_VFORK 0x00004000
1231# endif
1232# ifndef CLONE_VM
1233# define CLONE_VM 0x00000100
1234# endif
1235# ifndef CLONE_STOPPED
1236# define CLONE_STOPPED 0x02000000
1237# endif
Roland McGrathd81f1d92003-01-09 06:53:34 +00001238
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001239# ifdef IA64
Roland McGrathd81f1d92003-01-09 06:53:34 +00001240
Roland McGrath08267b82004-02-20 22:56:43 +00001241/* We don't have fork()/vfork() syscalls on ia64 itself, but the ia32
1242 subsystem has them for x86... */
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001243# define SYS_fork 2
1244# define SYS_vfork 190
Roland McGrath08267b82004-02-20 22:56:43 +00001245
Roland McGrathd81f1d92003-01-09 06:53:34 +00001246typedef unsigned long *arg_setup_state;
1247
1248static int
1249arg_setup(struct tcb *tcp, arg_setup_state *state)
1250{
Jan Kratochvil1f942712008-08-06 21:38:52 +00001251 unsigned long cfm, sof, sol;
1252 long bsp;
Roland McGrathd81f1d92003-01-09 06:53:34 +00001253
Jan Kratochvil1f942712008-08-06 21:38:52 +00001254 if (ia32) {
1255 /* Satisfy a false GCC warning. */
1256 *state = NULL;
Roland McGrath08267b82004-02-20 22:56:43 +00001257 return 0;
Jan Kratochvil1f942712008-08-06 21:38:52 +00001258 }
Roland McGrath08267b82004-02-20 22:56:43 +00001259
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001260 if (upeek(tcp, PT_AR_BSP, &bsp) < 0)
Roland McGrathd81f1d92003-01-09 06:53:34 +00001261 return -1;
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001262 if (upeek(tcp, PT_CFM, (long *) &cfm) < 0)
Roland McGrathd81f1d92003-01-09 06:53:34 +00001263 return -1;
1264
1265 sof = (cfm >> 0) & 0x7f;
1266 sol = (cfm >> 7) & 0x7f;
Jan Kratochvil1f942712008-08-06 21:38:52 +00001267 bsp = (long) ia64_rse_skip_regs((unsigned long *) bsp, -sof + sol);
Roland McGrathd81f1d92003-01-09 06:53:34 +00001268
Jan Kratochvil1f942712008-08-06 21:38:52 +00001269 *state = (unsigned long *) bsp;
Roland McGrathd81f1d92003-01-09 06:53:34 +00001270 return 0;
1271}
1272
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001273# define arg_finish_change(tcp, state) 0
Roland McGrathd81f1d92003-01-09 06:53:34 +00001274
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001275# ifdef SYS_fork
Roland McGrathd81f1d92003-01-09 06:53:34 +00001276static int
Denys Vlasenko12014262011-05-30 14:00:14 +02001277get_arg0(struct tcb *tcp, arg_setup_state *state, long *valp)
Roland McGrathd81f1d92003-01-09 06:53:34 +00001278{
Roland McGrath08267b82004-02-20 22:56:43 +00001279 int ret;
1280
1281 if (ia32)
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001282 ret = upeek(tcp, PT_R11, valp);
Roland McGrath08267b82004-02-20 22:56:43 +00001283 else
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001284 ret = umoven(tcp,
Roland McGrath08267b82004-02-20 22:56:43 +00001285 (unsigned long) ia64_rse_skip_regs(*state, 0),
1286 sizeof(long), (void *) valp);
1287 return ret;
Roland McGrathd81f1d92003-01-09 06:53:34 +00001288}
1289
1290static int
Denys Vlasenko12014262011-05-30 14:00:14 +02001291get_arg1(struct tcb *tcp, arg_setup_state *state, long *valp)
Roland McGrathd81f1d92003-01-09 06:53:34 +00001292{
Roland McGrath08267b82004-02-20 22:56:43 +00001293 int ret;
1294
1295 if (ia32)
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001296 ret = upeek(tcp, PT_R9, valp);
Roland McGrath08267b82004-02-20 22:56:43 +00001297 else
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001298 ret = umoven(tcp,
Roland McGrath08267b82004-02-20 22:56:43 +00001299 (unsigned long) ia64_rse_skip_regs(*state, 1),
1300 sizeof(long), (void *) valp);
1301 return ret;
Roland McGrathd81f1d92003-01-09 06:53:34 +00001302}
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001303# endif
Roland McGrathd81f1d92003-01-09 06:53:34 +00001304
1305static int
Denys Vlasenko12014262011-05-30 14:00:14 +02001306set_arg0(struct tcb *tcp, arg_setup_state *state, long val)
Roland McGrathd81f1d92003-01-09 06:53:34 +00001307{
Roland McGrath08267b82004-02-20 22:56:43 +00001308 int req = PTRACE_POKEDATA;
1309 void *ap;
1310
1311 if (ia32) {
1312 ap = (void *) (intptr_t) PT_R11; /* r11 == EBX */
1313 req = PTRACE_POKEUSER;
1314 } else
1315 ap = ia64_rse_skip_regs(*state, 0);
Roland McGratheb9e2e82009-06-02 16:49:22 -07001316 errno = 0;
1317 ptrace(req, tcp->pid, ap, val);
1318 return errno ? -1 : 0;
Roland McGrathd81f1d92003-01-09 06:53:34 +00001319}
1320
1321static int
Denys Vlasenko12014262011-05-30 14:00:14 +02001322set_arg1(struct tcb *tcp, arg_setup_state *state, long val)
Roland McGrathd81f1d92003-01-09 06:53:34 +00001323{
Roland McGrath08267b82004-02-20 22:56:43 +00001324 int req = PTRACE_POKEDATA;
1325 void *ap;
1326
1327 if (ia32) {
1328 ap = (void *) (intptr_t) PT_R9; /* r9 == ECX */
1329 req = PTRACE_POKEUSER;
1330 } else
1331 ap = ia64_rse_skip_regs(*state, 1);
Roland McGratheb9e2e82009-06-02 16:49:22 -07001332 errno = 0;
1333 ptrace(req, tcp->pid, ap, val);
1334 return errno ? -1 : 0;
Roland McGrathd81f1d92003-01-09 06:53:34 +00001335}
1336
Roland McGrathb659f872008-07-18 01:19:36 +00001337/* ia64 does not return the input arguments from functions (and syscalls)
1338 according to ia64 RSE (Register Stack Engine) behavior. */
1339
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001340# define restore_arg0(tcp, state, val) ((void) (state), 0)
1341# define restore_arg1(tcp, state, val) ((void) (state), 0)
Roland McGrathb659f872008-07-18 01:19:36 +00001342
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001343# elif defined (SPARC) || defined (SPARC64)
Roland McGrathd81f1d92003-01-09 06:53:34 +00001344
Mike Frysinger8566c502009-10-12 11:05:14 -04001345typedef struct pt_regs arg_setup_state;
Roland McGrathd81f1d92003-01-09 06:53:34 +00001346
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001347# define arg_setup(tcp, state) \
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001348 (ptrace(PTRACE_GETREGS, tcp->pid, (char *) (state), 0))
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001349# define arg_finish_change(tcp, state) \
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001350 (ptrace(PTRACE_SETREGS, tcp->pid, (char *) (state), 0))
Roland McGrathd81f1d92003-01-09 06:53:34 +00001351
Mike Frysinger8566c502009-10-12 11:05:14 -04001352# define get_arg0(tcp, state, valp) (*(valp) = (state)->u_regs[U_REG_O0], 0)
1353# define get_arg1(tcp, state, valp) (*(valp) = (state)->u_regs[U_REG_O1], 0)
1354# define set_arg0(tcp, state, val) ((state)->u_regs[U_REG_O0] = (val), 0)
1355# define set_arg1(tcp, state, val) ((state)->u_regs[U_REG_O1] = (val), 0)
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001356# define restore_arg0(tcp, state, val) 0
Roland McGrathd81f1d92003-01-09 06:53:34 +00001357
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001358# else /* other architectures */
Roland McGrathd81f1d92003-01-09 06:53:34 +00001359
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001360# if defined S390 || defined S390X
Roland McGrath7b308222003-01-20 09:04:36 +00001361/* Note: this is only true for the `clone' system call, which handles
1362 arguments specially. We could as well say that its first two arguments
1363 are swapped relative to other architectures, but that would just be
1364 another #ifdef in the calls. */
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001365# define arg0_offset PT_GPR3
1366# define arg1_offset PT_ORIGGPR2
1367# define restore_arg0(tcp, state, val) ((void) (state), 0)
1368# define restore_arg1(tcp, state, val) ((void) (state), 0)
1369# define arg0_index 1
1370# define arg1_index 0
1371# elif defined (ALPHA) || defined (MIPS)
1372# define arg0_offset REG_A0
1373# define arg1_offset (REG_A0+1)
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00001374# elif defined (AVR32)
1375# define arg0_offset (REG_R12)
1376# define arg1_offset (REG_R11)
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001377# elif defined (POWERPC)
1378# define arg0_offset (sizeof(unsigned long)*PT_R3)
1379# define arg1_offset (sizeof(unsigned long)*PT_R4)
1380# define restore_arg0(tcp, state, val) ((void) (state), 0)
1381# elif defined (HPPA)
1382# define arg0_offset PT_GR26
1383# define arg1_offset (PT_GR26-4)
1384# elif defined (X86_64)
1385# define arg0_offset ((long)(8*(current_personality ? RBX : RDI)))
1386# define arg1_offset ((long)(8*(current_personality ? RCX : RSI)))
1387# elif defined (SH)
1388# define arg0_offset (4*(REG_REG0+4))
1389# define arg1_offset (4*(REG_REG0+5))
1390# elif defined (SH64)
1391 /* ABI defines arg0 & 1 in r2 & r3 */
1392# define arg0_offset (REG_OFFSET+16)
1393# define arg1_offset (REG_OFFSET+24)
1394# define restore_arg0(tcp, state, val) 0
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001395# elif defined CRISV10 || defined CRISV32
1396# define arg0_offset (4*PT_R11)
1397# define arg1_offset (4*PT_ORIG_R10)
1398# define restore_arg0(tcp, state, val) 0
1399# define restore_arg1(tcp, state, val) 0
1400# define arg0_index 1
1401# define arg1_index 0
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001402# else
1403# define arg0_offset 0
1404# define arg1_offset 4
1405# if defined ARM
1406# define restore_arg0(tcp, state, val) 0
1407# endif
1408# endif
Roland McGrathd81f1d92003-01-09 06:53:34 +00001409
1410typedef int arg_setup_state;
1411
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001412# define arg_setup(tcp, state) (0)
1413# define arg_finish_change(tcp, state) 0
1414# define get_arg0(tcp, cookie, valp) \
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001415 (upeek((tcp), arg0_offset, (valp)))
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001416# define get_arg1(tcp, cookie, valp) \
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001417 (upeek((tcp), arg1_offset, (valp)))
Roland McGrathd81f1d92003-01-09 06:53:34 +00001418
1419static int
Denys Vlasenko12014262011-05-30 14:00:14 +02001420set_arg0(struct tcb *tcp, void *cookie, long val)
Roland McGrathd81f1d92003-01-09 06:53:34 +00001421{
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001422 return ptrace(PTRACE_POKEUSER, tcp->pid, (char*)arg0_offset, val);
Roland McGrathd81f1d92003-01-09 06:53:34 +00001423}
1424
1425static int
Denys Vlasenko12014262011-05-30 14:00:14 +02001426set_arg1(struct tcb *tcp, void *cookie, long val)
Roland McGrathd81f1d92003-01-09 06:53:34 +00001427{
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001428 return ptrace(PTRACE_POKEUSER, tcp->pid, (char*)arg1_offset, val);
Roland McGrathd81f1d92003-01-09 06:53:34 +00001429}
1430
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001431# endif /* architectures */
Roland McGrathd81f1d92003-01-09 06:53:34 +00001432
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001433# ifndef restore_arg0
1434# define restore_arg0(tcp, state, val) set_arg0((tcp), (state), (val))
1435# endif
1436# ifndef restore_arg1
1437# define restore_arg1(tcp, state, val) set_arg1((tcp), (state), (val))
1438# endif
Roland McGrathd81f1d92003-01-09 06:53:34 +00001439
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001440# ifndef arg0_index
1441# define arg0_index 0
1442# define arg1_index 1
1443# endif
Roland McGrath90d0afd2004-03-01 21:05:16 +00001444
Roland McGrathd81f1d92003-01-09 06:53:34 +00001445int
Denys Vlasenko418d66a2009-01-17 01:52:54 +00001446setbpt(struct tcb *tcp)
Roland McGrathd81f1d92003-01-09 06:53:34 +00001447{
Roland McGrath3291ef22008-05-20 00:34:34 +00001448 static int clone_scno[SUPPORTED_PERSONALITIES] = { SYS_clone };
Roland McGrathd81f1d92003-01-09 06:53:34 +00001449 arg_setup_state state;
1450
1451 if (tcp->flags & TCB_BPTSET) {
1452 fprintf(stderr, "PANIC: TCB already set in pid %u\n", tcp->pid);
1453 return -1;
1454 }
1455
Roland McGrath3291ef22008-05-20 00:34:34 +00001456 /*
1457 * It's a silly kludge to initialize this with a search at runtime.
1458 * But it's better than maintaining another magic thing in the
1459 * godforsaken tables.
1460 */
1461 if (clone_scno[current_personality] == 0) {
1462 int i;
1463 for (i = 0; i < nsyscalls; ++i)
1464 if (sysent[i].sys_func == sys_clone) {
1465 clone_scno[current_personality] = i;
1466 break;
1467 }
1468 }
1469
Roland McGrath76989d72005-06-07 23:21:31 +00001470 switch (known_scno(tcp)) {
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001471# ifdef SYS_vfork
Roland McGrath9383c6c2003-01-18 00:19:31 +00001472 case SYS_vfork:
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001473# endif
1474# ifdef SYS_fork
Roland McGrathd81f1d92003-01-09 06:53:34 +00001475 case SYS_fork:
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001476# endif
1477# if defined SYS_fork || defined SYS_vfork
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001478 if (arg_setup(tcp, &state) < 0
1479 || get_arg0(tcp, &state, &tcp->inst[0]) < 0
1480 || get_arg1(tcp, &state, &tcp->inst[1]) < 0
Roland McGrath3291ef22008-05-20 00:34:34 +00001481 || change_syscall(tcp, clone_scno[current_personality]) < 0
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001482 || set_arg0(tcp, &state, CLONE_PTRACE|SIGCHLD) < 0
1483 || set_arg1(tcp, &state, 0) < 0
1484 || arg_finish_change(tcp, &state) < 0)
Roland McGrathd81f1d92003-01-09 06:53:34 +00001485 return -1;
Roland McGrathc9dc3c12004-03-01 20:57:09 +00001486 tcp->u_arg[arg0_index] = CLONE_PTRACE|SIGCHLD;
1487 tcp->u_arg[arg1_index] = 0;
Roland McGrathd81f1d92003-01-09 06:53:34 +00001488 tcp->flags |= TCB_BPTSET;
1489 return 0;
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001490# endif
Roland McGrathd81f1d92003-01-09 06:53:34 +00001491
Denys Vlasenkoc133bf02011-06-23 21:57:54 +02001492 case SYS_clone: ;
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001493# ifdef SYS_clone2
Denys Vlasenkoc133bf02011-06-23 21:57:54 +02001494 case SYS_clone2: ;
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001495# endif
Jan Kratochvil8fc95752008-08-06 21:43:35 +00001496 /* ia64 calls directly `clone (CLONE_VFORK | CLONE_VM)'
1497 contrary to x86 SYS_vfork above. Even on x86 we turn the
1498 vfork semantics into plain fork - each application must not
1499 depend on the vfork specifics according to POSIX. We would
1500 hang waiting for the parent resume otherwise. We need to
1501 clear also CLONE_VM but only in the CLONE_VFORK case as
1502 otherwise we would break pthread_create. */
1503
Denys Vlasenkoc133bf02011-06-23 21:57:54 +02001504 long new_arg0 = (tcp->u_arg[arg0_index] | CLONE_PTRACE);
1505 if (new_arg0 & CLONE_VFORK)
1506 new_arg0 &= ~(unsigned long)(CLONE_VFORK | CLONE_VM);
1507 if (arg_setup(tcp, &state) < 0
1508 || set_arg0(tcp, &state, new_arg0) < 0
1509 || arg_finish_change(tcp, &state) < 0)
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00001510 return -1;
Roland McGrathd81f1d92003-01-09 06:53:34 +00001511 tcp->flags |= TCB_BPTSET;
Roland McGrathc9dc3c12004-03-01 20:57:09 +00001512 tcp->inst[0] = tcp->u_arg[arg0_index];
1513 tcp->inst[1] = tcp->u_arg[arg1_index];
Roland McGrathd81f1d92003-01-09 06:53:34 +00001514 return 0;
1515
1516 default:
1517 fprintf(stderr, "PANIC: setbpt for syscall %ld on %u???\n",
1518 tcp->scno, tcp->pid);
1519 break;
1520 }
1521
1522 return -1;
1523}
1524
1525int
Denys Vlasenko12014262011-05-30 14:00:14 +02001526clearbpt(struct tcb *tcp)
Roland McGrathd81f1d92003-01-09 06:53:34 +00001527{
1528 arg_setup_state state;
Denys Vlasenkob63256e2011-06-07 12:13:24 +02001529 if (arg_setup(tcp, &state) < 0
1530 || restore_arg0(tcp, &state, tcp->inst[0]) < 0
1531 || restore_arg1(tcp, &state, tcp->inst[1]) < 0
1532 || arg_finish_change(tcp, &state))
Denys Vlasenkoc133bf02011-06-23 21:57:54 +02001533 if (errno != ESRCH)
1534 return -1;
Roland McGrathd81f1d92003-01-09 06:53:34 +00001535 tcp->flags &= ~TCB_BPTSET;
1536 return 0;
1537}
1538
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001539# else /* !defined LINUX */
Roland McGrathd81f1d92003-01-09 06:53:34 +00001540
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001541int
Denys Vlasenko12014262011-05-30 14:00:14 +02001542setbpt(struct tcb *tcp)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001543{
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001544# ifdef SUNOS4
1545# ifdef SPARC /* This code is slightly sparc specific */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001546
Wichert Akkermane6f876c1999-06-22 15:28:30 +00001547 struct regs regs;
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001548# define BPT 0x91d02001 /* ta 1 */
1549# define LOOP 0x10800000 /* ba 0 */
1550# define LOOPA 0x30800000 /* ba,a 0 */
1551# define NOP 0x01000000
1552# if LOOPA
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001553 static int loopdeloop[1] = {LOOPA};
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001554# else
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001555 static int loopdeloop[2] = {LOOP, NOP};
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001556# endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001557
1558 if (tcp->flags & TCB_BPTSET) {
1559 fprintf(stderr, "PANIC: TCB already set in pid %u\n", tcp->pid);
1560 return -1;
1561 }
Roland McGratheb9e2e82009-06-02 16:49:22 -07001562 if (ptrace(PTRACE_GETREGS, tcp->pid, (char *)&regs, 0) < 0) {
1563 perror("setbpt: ptrace(PTRACE_GETREGS, ...)");
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001564 return -1;
1565 }
1566 tcp->baddr = regs.r_o7 + 8;
Roland McGratheb9e2e82009-06-02 16:49:22 -07001567 if (ptrace(PTRACE_READTEXT, tcp->pid, (char *)tcp->baddr,
1568 sizeof tcp->inst, (char *)tcp->inst) < 0) {
1569 perror("setbpt: ptrace(PTRACE_READTEXT, ...)");
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001570 return -1;
1571 }
1572
1573 /*
1574 * XXX - BRUTAL MODE ON
1575 * We cannot set a real BPT in the child, since it will not be
1576 * traced at the moment it will reach the trap and would probably
1577 * die with a core dump.
1578 * Thus, we are force our way in by taking out two instructions
1579 * and insert an eternal loop in stead, in expectance of the SIGSTOP
1580 * generated by out PTRACE_ATTACH.
1581 * Of cause, if we evaporate ourselves in the middle of all this...
1582 */
Roland McGratheb9e2e82009-06-02 16:49:22 -07001583 if (ptrace(PTRACE_WRITETEXT, tcp->pid, (char *) tcp->baddr,
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001584 sizeof loopdeloop, (char *) loopdeloop) < 0) {
Roland McGratheb9e2e82009-06-02 16:49:22 -07001585 perror("setbpt: ptrace(PTRACE_WRITETEXT, ...)");
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001586 return -1;
1587 }
1588 tcp->flags |= TCB_BPTSET;
1589
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001590# endif /* SPARC */
1591# endif /* SUNOS4 */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001592
1593 return 0;
1594}
1595
1596int
Denys Vlasenko12014262011-05-30 14:00:14 +02001597clearbpt(struct tcb *tcp)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001598{
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001599# ifdef SUNOS4
1600# ifdef SPARC
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001601
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001602# if !LOOPA
Wichert Akkermane6f876c1999-06-22 15:28:30 +00001603 struct regs regs;
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001604# endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001605
1606 if (!(tcp->flags & TCB_BPTSET)) {
1607 fprintf(stderr, "PANIC: TCB not set in pid %u\n", tcp->pid);
1608 return -1;
1609 }
Roland McGratheb9e2e82009-06-02 16:49:22 -07001610 if (ptrace(PTRACE_WRITETEXT, tcp->pid, (char *) tcp->baddr,
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001611 sizeof tcp->inst, (char *) tcp->inst) < 0) {
Roland McGratheb9e2e82009-06-02 16:49:22 -07001612 perror("clearbtp: ptrace(PTRACE_WRITETEXT, ...)");
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001613 return -1;
1614 }
1615 tcp->flags &= ~TCB_BPTSET;
1616
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001617# if !LOOPA
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001618 /*
1619 * Since we don't have a single instruction breakpoint, we may have
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001620 * to adjust the program counter after removing our `breakpoint'.
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001621 */
Roland McGratheb9e2e82009-06-02 16:49:22 -07001622 if (ptrace(PTRACE_GETREGS, tcp->pid, (char *)&regs, 0) < 0) {
1623 perror("clearbpt: ptrace(PTRACE_GETREGS, ...)");
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001624 return -1;
1625 }
Roland McGratheb9e2e82009-06-02 16:49:22 -07001626 if ((regs.r_pc < tcp->baddr) ||
1627 (regs.r_pc > tcp->baddr + 4)) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001628 /* The breakpoint has not been reached yet */
1629 if (debug)
1630 fprintf(stderr,
1631 "NOTE: PC not at bpt (pc %#x baddr %#x)\n",
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001632 regs.r_pc, tcp->baddr);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001633 return 0;
1634 }
1635 if (regs.r_pc != tcp->baddr)
1636 if (debug)
1637 fprintf(stderr, "NOTE: PC adjusted (%#x -> %#x\n",
1638 regs.r_pc, tcp->baddr);
1639
1640 regs.r_pc = tcp->baddr;
Roland McGratheb9e2e82009-06-02 16:49:22 -07001641 if (ptrace(PTRACE_SETREGS, tcp->pid, (char *)&regs, 0) < 0) {
1642 perror("clearbpt: ptrace(PTRACE_SETREGS, ...)");
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001643 return -1;
1644 }
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001645# endif /* LOOPA */
1646# endif /* SPARC */
1647# endif /* SUNOS4 */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001648
1649 return 0;
1650}
1651
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001652# endif /* !defined LINUX */
Roland McGrathd81f1d92003-01-09 06:53:34 +00001653
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001654#endif /* !USE_PROCFS */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001655
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001656
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001657#ifdef SUNOS4
1658
1659static int
Denys Vlasenko12014262011-05-30 14:00:14 +02001660getex(struct tcb *tcp, struct exec *hdr)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001661{
1662 int n;
1663
1664 for (n = 0; n < sizeof *hdr; n += 4) {
1665 long res;
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001666 if (upeek(tcp, uoff(u_exdata) + n, &res) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001667 return -1;
1668 memcpy(((char *) hdr) + n, &res, 4);
1669 }
1670 if (debug) {
1671 fprintf(stderr, "[struct exec: magic: %o version %u Mach %o\n",
1672 hdr->a_magic, hdr->a_toolversion, hdr->a_machtype);
1673 fprintf(stderr, "Text %lu Data %lu Bss %lu Syms %lu Entry %#lx]\n",
1674 hdr->a_text, hdr->a_data, hdr->a_bss, hdr->a_syms, hdr->a_entry);
1675 }
1676 return 0;
1677}
1678
1679int
Denys Vlasenko12014262011-05-30 14:00:14 +02001680fixvfork(struct tcb *tcp)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001681{
1682 int pid = tcp->pid;
1683 /*
1684 * Change `vfork' in a freshly exec'ed dynamically linked
1685 * executable's (internal) symbol table to plain old `fork'
1686 */
1687
1688 struct exec hdr;
1689 struct link_dynamic dyn;
1690 struct link_dynamic_2 ld;
1691 char *strtab, *cp;
1692
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001693 if (getex(tcp, &hdr) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001694 return -1;
1695 if (!hdr.a_dynamic)
1696 return -1;
1697
1698 if (umove(tcp, (int) N_DATADDR(hdr), &dyn) < 0) {
1699 fprintf(stderr, "Cannot read DYNAMIC\n");
1700 return -1;
1701 }
1702 if (umove(tcp, (int) dyn.ld_un.ld_2, &ld) < 0) {
1703 fprintf(stderr, "Cannot read link_dynamic_2\n");
1704 return -1;
1705 }
1706 if ((strtab = malloc((unsigned)ld.ld_symb_size)) == NULL) {
Roland McGrath46100d02005-06-01 18:55:42 +00001707 fprintf(stderr, "out of memory\n");
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001708 return -1;
1709 }
Roland McGratheb9e2e82009-06-02 16:49:22 -07001710 if (umoven(tcp, (int)ld.ld_symbols+(int)N_TXTADDR(hdr),
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001711 (int)ld.ld_symb_size, strtab) < 0)
1712 goto err;
1713
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001714 for (cp = strtab; cp < strtab + ld.ld_symb_size; ) {
1715 if (strcmp(cp, "_vfork") == 0) {
1716 if (debug)
1717 fprintf(stderr, "fixvfork: FOUND _vfork\n");
1718 strcpy(cp, "_fork");
1719 break;
1720 }
1721 cp += strlen(cp)+1;
1722 }
1723 if (cp < strtab + ld.ld_symb_size)
1724 /*
1725 * Write entire symbol table back to avoid
1726 * memory alignment bugs in ptrace
1727 */
Roland McGratheb9e2e82009-06-02 16:49:22 -07001728 if (tload(pid, (int)ld.ld_symbols+(int)N_TXTADDR(hdr),
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001729 (int)ld.ld_symb_size, strtab) < 0)
1730 goto err;
1731
1732 free(strtab);
1733 return 0;
1734
1735err:
1736 free(strtab);
1737 return -1;
1738}
1739
1740#endif /* SUNOS4 */