blob: d9de3543d8bb0c0aba0bfce86762e1d6ac3a2c5e [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
Roland McGrath6d1a65c2004-07-12 07:44:08 +000081#if defined(LINUXSPARC)
Wichert Akkerman9ce1a631999-08-29 23:15:07 +000082
Roland McGrath4db26242003-01-30 20:15:19 +000083# define fpq kernel_fpq
84# define fq kernel_fq
85# define fpu kernel_fpu
86# include <asm/reg.h>
87# undef fpq
88# undef fq
89# undef fpu
Wichert Akkerman9ce1a631999-08-29 23:15:07 +000090
Roland McGrath6d1a65c2004-07-12 07:44:08 +000091#if defined (SPARC64)
92# define r_pc r_tpc
93# undef PTRACE_GETREGS
94# define PTRACE_GETREGS PTRACE_GETREGS64
95# undef PTRACE_SETREGS
96# define PTRACE_SETREGS PTRACE_SETREGS64
97#endif /* SPARC64 */
98
Wichert Akkerman9ce1a631999-08-29 23:15:07 +000099#if !defined(__GLIBC__)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000100
101#include <linux/unistd.h>
102
103#define _hack_syscall5(type,name,type1,arg1,type2,arg2,type3,arg3,type4,arg4,\
104 type5,arg5,syscall) \
105type name (type1 arg1,type2 arg2,type3 arg3,type4 arg4,type5 arg5) \
106{ \
107 long __res; \
108\
109__asm__ volatile ("or %%g0, %1, %%o0\n\t" \
110 "or %%g0, %2, %%o1\n\t" \
111 "or %%g0, %3, %%o2\n\t" \
112 "or %%g0, %4, %%o3\n\t" \
113 "or %%g0, %5, %%o4\n\t" \
114 "or %%g0, %6, %%g1\n\t" \
Roland McGrath6d1a65c2004-07-12 07:44:08 +0000115#if defined (SPARC64)
116 "t 0x6d\n\t" \
117#else
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000118 "t 0x10\n\t" \
Roland McGrath6d1a65c2004-07-12 07:44:08 +0000119#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000120 "bcc 1f\n\t" \
121 "or %%g0, %%o0, %0\n\t" \
122 "sub %%g0, %%o0, %0\n\t" \
123 "1:\n\t" \
124 : "=r" (__res) \
125 : "0" ((long)(arg1)),"1" ((long)(arg2)), \
126 "2" ((long)(arg3)),"3" ((long)(arg4)),"4" ((long)(arg5)), \
127 "i" (__NR_##syscall) \
128 : "g1", "o0", "o1", "o2", "o3", "o4"); \
129if (__res>=0) \
Denys Vlasenkoadedb512008-12-30 18:47:55 +0000130 return (type) __res; \
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000131errno = -__res; \
132return -1; \
133}
134
135static _hack_syscall5(int,_ptrace,int,__request,int,__pid,int,__addr,int,__data,int,__addr2,ptrace)
136
137#define _ptrace
138
139#endif
140
Wichert Akkerman9ce1a631999-08-29 23:15:07 +0000141#endif
142
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000143/* macros */
144#ifndef MAX
145#define MAX(a,b) (((a) > (b)) ? (a) : (b))
146#endif
147#ifndef MIN
148#define MIN(a,b) (((a) < (b)) ? (a) : (b))
149#endif
150
Roland McGratha4d48532005-06-08 20:45:28 +0000151#if 0
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000152void
153tv_tv(tv, a, b)
154struct timeval *tv;
155int a;
156int b;
157{
158 tv->tv_sec = a;
159 tv->tv_usec = b;
160}
Roland McGratha4d48532005-06-08 20:45:28 +0000161#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000162
163int
164tv_nz(a)
165struct timeval *a;
166{
167 return a->tv_sec || a->tv_usec;
168}
169
170int
171tv_cmp(a, b)
172struct timeval *a, *b;
173{
174 if (a->tv_sec < b->tv_sec
175 || (a->tv_sec == b->tv_sec && a->tv_usec < b->tv_usec))
176 return -1;
177 if (a->tv_sec > b->tv_sec
178 || (a->tv_sec == b->tv_sec && a->tv_usec > b->tv_usec))
179 return 1;
180 return 0;
181}
182
183double
184tv_float(tv)
185struct timeval *tv;
186{
187 return tv->tv_sec + tv->tv_usec/1000000.0;
188}
189
190void
191tv_add(tv, a, b)
192struct timeval *tv, *a, *b;
193{
194 tv->tv_sec = a->tv_sec + b->tv_sec;
195 tv->tv_usec = a->tv_usec + b->tv_usec;
Roland McGrath58372f52007-07-24 01:38:22 +0000196 if (tv->tv_usec >= 1000000) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000197 tv->tv_sec++;
198 tv->tv_usec -= 1000000;
199 }
200}
201
202void
203tv_sub(tv, a, b)
204struct timeval *tv, *a, *b;
205{
206 tv->tv_sec = a->tv_sec - b->tv_sec;
207 tv->tv_usec = a->tv_usec - b->tv_usec;
208 if (((long) tv->tv_usec) < 0) {
209 tv->tv_sec--;
210 tv->tv_usec += 1000000;
211 }
212}
213
214void
215tv_div(tv, a, n)
216struct timeval *tv, *a;
217int n;
218{
219 tv->tv_usec = (a->tv_sec % n * 1000000 + a->tv_usec + n / 2) / n;
220 tv->tv_sec = a->tv_sec / n + tv->tv_usec / 1000000;
221 tv->tv_usec %= 1000000;
222}
223
224void
225tv_mul(tv, a, n)
226struct timeval *tv, *a;
227int n;
228{
229 tv->tv_usec = a->tv_usec * n;
Dmitry V. Levinfefdd972007-06-29 21:25:56 +0000230 tv->tv_sec = a->tv_sec * n + tv->tv_usec / 1000000;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000231 tv->tv_usec %= 1000000;
232}
233
Dmitry V. Levinab9008b2007-01-11 22:05:04 +0000234const char *
235xlookup(const struct xlat *xlat, int val)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000236{
237 for (; xlat->str != NULL; xlat++)
238 if (xlat->val == val)
239 return xlat->str;
240 return NULL;
241}
242
243/*
Denys Vlasenko4dedd562009-02-24 15:17:53 +0000244 * Generic ptrace wrapper which tracks ptrace errors
245 * by setting tcp->ptrace_errno.
Denys Vlasenko732d1bf2008-12-17 19:21:59 +0000246 *
247 * We assume that ESRCH indicates likely process death (SIGKILL?),
248 * modulo bugs where process somehow ended up not stopped.
249 * Unfortunately kernel uses ESRCH for that case too. Oh well.
Denys Vlasenko732d1bf2008-12-17 19:21:59 +0000250 */
Denys Vlasenko4dedd562009-02-24 15:17:53 +0000251static const char *
252str_PTRACE_xxx(int request)
Denys Vlasenko732d1bf2008-12-17 19:21:59 +0000253{
Denys Vlasenko4dedd562009-02-24 15:17:53 +0000254 const char *s;
255 static char msg[sizeof(int) * 3 + sizeof("PTRACE_<%d>")];
256
257 s = xlookup(ptrace_cmds, request);
258 if (s)
259 return s;
260 sprintf(msg, "PTRACE_<%d>", request);
261 return msg;
262}
263
264long
265do_ptrace(int request, struct tcb *tcp, void *addr, long data)
266{
267 int err;
Denys Vlasenko732d1bf2008-12-17 19:21:59 +0000268 long l;
269
270 errno = 0;
271 l = ptrace(request, tcp->pid, addr, data);
Denys Vlasenko4dedd562009-02-24 15:17:53 +0000272 err = errno;
273 if (err) {
274 tcp->ptrace_errno = err;
275 if (err != ESRCH) {
276 fprintf(stderr, "strace: ptrace(%s,%u,%p,%lu): %s\n",
277 str_PTRACE_xxx(request),
278 (int) tcp->pid, addr, data, strerror(err));
279 errno = err; /* fprintf can clobber it, restore */
280 }
281 return -1;
282 }
Denys Vlasenko732d1bf2008-12-17 19:21:59 +0000283 return l;
284}
285
Denys Vlasenko4dedd562009-02-24 15:17:53 +0000286static long
287do_ptrace_peekdata(struct tcb *tcp, void *addr, int started)
288{
289 int err;
290 long l;
291
292 errno = 0;
293 l = ptrace(PTRACE_PEEKDATA, tcp->pid, addr, 0);
294 err = errno;
295 if (err) {
296 if (started && (err == EPERM || err == EIO)) {
297 /* Ran into 'end of memory' - not an error.
298 * NB: errno is nonzero, caller uses this to detect
299 * "end of string" condition.
300 */
301 return 0;
302 }
303 /* If error happens at first call, we have a bogus address. */
304 if (addr != NULL && err != EIO) {
305 if (err != ESRCH) {
306 fprintf(stderr, "strace: ptrace(PTRACE_PEEKDATA,%u,%p,0): %s\n",
307 (int) tcp->pid, addr, strerror(err));
308 errno = err; /* fprintf can clobber it, restore */
309 }
310 tcp->ptrace_errno = err;
311 return -1;
312 }
313 }
314 return l;
315}
316
317#ifdef SUNOS4
318static long
319do_ptrace5(int request, struct tcb *tcp, void *addr, long data, char *data2)
320{
321 int err;
322 long l;
323
324 errno = 0;
325 l = ptrace(request, tcp->pid, addr, data, data2);
326 err = errno;
327 if (err) {
328 tcp->ptrace_errno = err;
329 if (err != ESRCH) {
330 fprintf(stderr, "strace: ptrace(%s,%u,%p,%lu,%p): %s\n",
331 str_PTRACE_xxx(request),
332 (int) tcp->pid, addr, data, data2, strerror(err));
333 errno = err; /* fprintf can clobber it, restore */
334 }
335 return -1;
336 }
337 return l;
338}
339#endif
340
Denys Vlasenko732d1bf2008-12-17 19:21:59 +0000341/*
342 * Used when we want to unblock stopped traced process.
343 * Should be only used with PTRACE_CONT, PTRACE_DETACH and PTRACE_SYSCALL.
344 * Returns 0 on success or if error was ESRCH
345 * (presumably process was killed while we talk to it).
346 * Otherwise prints error message and returns -1.
347 */
348int
Denys Vlasenko4dedd562009-02-24 15:17:53 +0000349ptrace_restart(int request, struct tcb *tcp, int sig)
Denys Vlasenko732d1bf2008-12-17 19:21:59 +0000350{
351 int err;
Denys Vlasenko732d1bf2008-12-17 19:21:59 +0000352
353 errno = 0;
Denys Vlasenko4dedd562009-02-24 15:17:53 +0000354 ptrace(request, tcp->pid, (void *) 1, (long) sig);
Denys Vlasenko732d1bf2008-12-17 19:21:59 +0000355 err = errno;
356 if (!err || err == ESRCH)
357 return 0;
358
359 tcp->ptrace_errno = err;
Denys Vlasenko4dedd562009-02-24 15:17:53 +0000360 fprintf(stderr, "strace: ptrace(%s,%u,1,%d): %s\n",
361 str_PTRACE_xxx(request),
362 (int)tcp->pid, sig, strerror(err));
363 errno = err; /* fprintf can clobber it, restore */
Denys Vlasenko732d1bf2008-12-17 19:21:59 +0000364 return -1;
365}
366
367/*
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000368 * Print entry in struct xlat table, if there.
369 */
370void
Dmitry V. Levinab9008b2007-01-11 22:05:04 +0000371printxval(const struct xlat *xlat, int val, const char *dflt)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000372{
Dmitry V. Levinab9008b2007-01-11 22:05:04 +0000373 const char *str = xlookup(xlat, val);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000374
375 if (str)
376 tprintf("%s", str);
377 else
378 tprintf("%#x /* %s */", val, dflt);
379}
380
381/*
382 * Interpret `xlat' as an array of flags
383 * print the entries whose bits are on in `flags'
384 * return # of flags printed.
385 */
386int
387addflags(xlat, flags)
Roland McGrathd9f816f2004-09-04 03:39:20 +0000388const struct xlat *xlat;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000389int flags;
390{
391 int n;
392
393 for (n = 0; xlat->str; xlat++) {
394 if (xlat->val && (flags & xlat->val) == xlat->val) {
395 tprintf("|%s", xlat->str);
396 flags &= ~xlat->val;
397 n++;
398 }
399 }
400 if (flags) {
401 tprintf("|%#x", flags);
402 n++;
403 }
404 return n;
405}
406
Roland McGratha6c0d8c2007-11-01 21:46:22 +0000407/*
408 * Interpret `xlat' as an array of flags/
409 * Print to static string the entries whose bits are on in `flags'
410 * Return static string.
411 */
412const char *
413sprintflags(const char *prefix, const struct xlat *xlat, int flags)
414{
415 static char outstr[1024];
416 int found = 0;
417
418 strcpy(outstr, prefix);
419
420 for (; xlat->str; xlat++) {
421 if ((flags & xlat->val) == xlat->val) {
422 if (found)
423 strcat(outstr, "|");
424 strcat(outstr, xlat->str);
425 flags &= ~xlat->val;
426 found = 1;
427 }
428 }
429 if (flags) {
430 if (found)
431 strcat(outstr, "|");
432 sprintf(outstr + strlen(outstr), "%#x", flags);
433 }
434
435 return outstr;
436}
437
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000438int
Roland McGrathb2dee132005-06-01 19:02:36 +0000439printflags(xlat, flags, dflt)
Roland McGrathd9f816f2004-09-04 03:39:20 +0000440const struct xlat *xlat;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000441int flags;
Roland McGrathb2dee132005-06-01 19:02:36 +0000442const char *dflt;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000443{
444 int n;
445 char *sep;
446
447 if (flags == 0 && xlat->val == 0) {
448 tprintf("%s", xlat->str);
449 return 1;
450 }
451
452 sep = "";
453 for (n = 0; xlat->str; xlat++) {
454 if (xlat->val && (flags & xlat->val) == xlat->val) {
455 tprintf("%s%s", sep, xlat->str);
456 flags &= ~xlat->val;
457 sep = "|";
458 n++;
459 }
460 }
Roland McGrathb2dee132005-06-01 19:02:36 +0000461
462 if (n) {
463 if (flags) {
464 tprintf("%s%#x", sep, flags);
465 n++;
466 }
467 } else {
468 if (flags) {
469 tprintf("%#x", flags);
470 if (dflt)
471 tprintf(" /* %s */", dflt);
472 } else {
473 if (dflt)
474 tprintf("0");
475 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000476 }
Roland McGrathb2dee132005-06-01 19:02:36 +0000477
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000478 return n;
479}
480
481void
482printnum(tcp, addr, fmt)
483struct tcb *tcp;
484long addr;
485char *fmt;
486{
Roland McGratheb285352003-01-14 09:59:00 +0000487 long num;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000488
489 if (!addr) {
490 tprintf("NULL");
491 return;
492 }
493 if (umove(tcp, addr, &num) < 0) {
494 tprintf("%#lx", addr);
495 return;
496 }
497 tprintf("[");
498 tprintf(fmt, num);
499 tprintf("]");
500}
501
Roland McGrath6bc12202003-11-13 22:32:27 +0000502void
Roland McGrath9814a942005-07-04 23:28:10 +0000503printnum_int(tcp, addr, fmt)
504struct tcb *tcp;
505long addr;
506char *fmt;
507{
508 int num;
509
510 if (!addr) {
511 tprintf("NULL");
512 return;
513 }
514 if (umove(tcp, addr, &num) < 0) {
515 tprintf("%#lx", addr);
516 return;
517 }
518 tprintf("[");
519 tprintf(fmt, num);
520 tprintf("]");
521}
522
523void
Roland McGrath6bc12202003-11-13 22:32:27 +0000524printuid(text, uid)
525const char *text;
526unsigned long uid;
527{
528 tprintf("%s", text);
529 tprintf((uid == -1) ? "%ld" : "%lu", uid);
530}
531
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000532static char path[MAXPATHLEN + 1];
533
Dmitry V. Levina501f142008-11-10 23:19:13 +0000534/*
535 * Quote string `instr' of length `size'
536 * Write up to (3 + `size' * 4) bytes to `outstr' buffer.
537 * If `len' < 0, treat `instr' as a NUL-terminated string
538 * and quote at most (`size' - 1) bytes.
539 */
Roland McGrath6d970322007-11-01 23:53:59 +0000540static int
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000541string_quote(const char *instr, char *outstr, int len, int size)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000542{
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000543 const unsigned char *ustr = (const unsigned char *) instr;
544 char *s = outstr;
545 int usehex = 0, c, i;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000546
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000547 if (xflag > 1)
548 usehex = 1;
549 else if (xflag) {
Dmitry V. Levina501f142008-11-10 23:19:13 +0000550 /* Check for presence of symbol which require
551 to hex-quote the whole string. */
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000552 for (i = 0; i < size; ++i) {
553 c = ustr[i];
Dmitry V. Levina501f142008-11-10 23:19:13 +0000554 /* Check for NUL-terminated string. */
555 if (len < 0) {
556 if (c == '\0')
557 break;
558 /* Quote at most size - 1 bytes. */
559 if (i == size - 1)
560 continue;
561 }
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000562 if (!isprint(c) && !isspace(c)) {
563 usehex = 1;
564 break;
565 }
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000566 }
567 }
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000568
569 *s++ = '\"';
570
571 if (usehex) {
Dmitry V. Levina501f142008-11-10 23:19:13 +0000572 /* Hex-quote the whole string. */
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000573 for (i = 0; i < size; ++i) {
574 c = ustr[i];
Dmitry V. Levina501f142008-11-10 23:19:13 +0000575 /* Check for NUL-terminated string. */
576 if (len < 0) {
577 if (c == '\0')
578 break;
579 /* Quote at most size - 1 bytes. */
580 if (i == size - 1)
581 continue;
582 }
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000583 sprintf(s, "\\x%02x", c);
584 s += 4;
585 }
586 } else {
587 for (i = 0; i < size; ++i) {
588 c = ustr[i];
Dmitry V. Levina501f142008-11-10 23:19:13 +0000589 /* Check for NUL-terminated string. */
590 if (len < 0) {
591 if (c == '\0')
592 break;
593 /* Quote at most size - 1 bytes. */
594 if (i == size - 1)
595 continue;
596 }
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000597 switch (c) {
598 case '\"': case '\\':
599 *s++ = '\\';
600 *s++ = c;
601 break;
602 case '\f':
603 *s++ = '\\';
604 *s++ = 'f';
605 break;
606 case '\n':
607 *s++ = '\\';
608 *s++ = 'n';
609 break;
610 case '\r':
611 *s++ = '\\';
612 *s++ = 'r';
613 break;
614 case '\t':
615 *s++ = '\\';
616 *s++ = 't';
617 break;
618 case '\v':
619 *s++ = '\\';
620 *s++ = 'v';
621 break;
622 default:
623 if (isprint(c))
624 *s++ = c;
625 else if (i + 1 < size
626 && isdigit(ustr[i + 1])) {
627 sprintf(s, "\\%03o", c);
628 s += 4;
629 } else {
630 sprintf(s, "\\%o", c);
631 s += strlen(s);
632 }
633 break;
634 }
635 }
636 }
637
638 *s++ = '\"';
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000639 *s = '\0';
Roland McGrath6d970322007-11-01 23:53:59 +0000640
641 /* Return nonzero if the string was unterminated. */
642 return i == size;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000643}
644
Dmitry V. Levina501f142008-11-10 23:19:13 +0000645/*
646 * Print path string specified by address `addr' and length `n'.
647 * If path length exceeds `n', append `...' to the output.
648 */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000649void
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000650printpathn(struct tcb *tcp, long addr, int n)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000651{
Dmitry V. Levina501f142008-11-10 23:19:13 +0000652 if (!addr) {
Roland McGrath371ed8f2005-02-06 01:55:07 +0000653 tprintf("NULL");
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000654 return;
655 }
656
Dmitry V. Levina501f142008-11-10 23:19:13 +0000657 /* Cap path length to the path buffer size,
658 and NUL-terminate the buffer. */
659 if (n > sizeof path - 1)
660 n = sizeof path - 1;
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000661 path[n] = '\0';
Dmitry V. Levina501f142008-11-10 23:19:13 +0000662
663 /* Fetch one byte more to find out whether path length > n. */
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000664 if (umovestr(tcp, addr, n + 1, path) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000665 tprintf("%#lx", addr);
666 else {
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000667 static char outstr[4*(sizeof path - 1) + sizeof "\"...\""];
668 int trunc = (path[n] != '\0');
669
670 if (trunc)
671 path[n] = '\0';
Dmitry V. Levina501f142008-11-10 23:19:13 +0000672 (void) string_quote(path, outstr, -1, n + 1);
673 if (trunc)
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000674 strcat(outstr, "...");
675 tprintf("%s", outstr);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000676 }
677}
678
679void
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000680printpath(struct tcb *tcp, long addr)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000681{
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000682 printpathn(tcp, addr, sizeof path - 1);
683}
684
Dmitry V. Levina501f142008-11-10 23:19:13 +0000685/*
686 * Print string specified by address `addr' and length `len'.
687 * If `len' < 0, treat the string as a NUL-terminated string.
688 * If string length exceeds `max_strlen', append `...' to the output.
689 */
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000690void
691printstr(struct tcb *tcp, long addr, int len)
692{
693 static char *str = NULL;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000694 static char *outstr;
Roland McGrath6d970322007-11-01 23:53:59 +0000695 int size;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000696
697 if (!addr) {
698 tprintf("NULL");
699 return;
700 }
Dmitry V. Levina501f142008-11-10 23:19:13 +0000701 /* Allocate static buffers if they are not allocated yet. */
702 if (!str)
703 str = malloc(max_strlen + 1);
704 if (!outstr)
705 outstr = malloc(4 * max_strlen + sizeof "\"...\"");
706 if (!str || !outstr) {
707 fprintf(stderr, "out of memory\n");
708 tprintf("%#lx", addr);
709 return;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000710 }
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000711
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000712 if (len < 0) {
Dmitry V. Levina501f142008-11-10 23:19:13 +0000713 /*
714 * Treat as a NUL-terminated string: fetch one byte more
715 * because string_quote() quotes one byte less.
716 */
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000717 size = max_strlen + 1;
Dmitry V. Levina501f142008-11-10 23:19:13 +0000718 str[max_strlen] = '\0';
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000719 if (umovestr(tcp, addr, size, str) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000720 tprintf("%#lx", addr);
721 return;
722 }
723 }
724 else {
Dmitry V. Levina501f142008-11-10 23:19:13 +0000725 size = MIN(len, max_strlen);
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000726 if (umoven(tcp, addr, size, str) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000727 tprintf("%#lx", addr);
728 return;
729 }
730 }
731
Dmitry V. Levina501f142008-11-10 23:19:13 +0000732 if (string_quote(str, outstr, len, size) &&
733 (len < 0 || len > max_strlen))
Dmitry V. Levinbea02032007-10-08 21:48:01 +0000734 strcat(outstr, "...");
Roland McGratha503dcf2007-08-02 02:06:26 +0000735
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000736 tprintf("%s", outstr);
737}
738
John Hughes1d08dcf2001-07-10 13:48:44 +0000739#if HAVE_SYS_UIO_H
740void
741dumpiov(tcp, len, addr)
742struct tcb * tcp;
743int len;
744long addr;
745{
Dmitry V. Levin4ebb4e32006-12-13 17:08:08 +0000746#if defined(LINUX) && SUPPORTED_PERSONALITIES > 1
747 union {
748 struct { u_int32_t base; u_int32_t len; } *iov32;
749 struct { u_int64_t base; u_int64_t len; } *iov64;
750 } iovu;
751#define iov iovu.iov64
752#define sizeof_iov \
753 (personality_wordsize[current_personality] == 4 \
754 ? sizeof(*iovu.iov32) : sizeof(*iovu.iov64))
755#define iov_iov_base(i) \
756 (personality_wordsize[current_personality] == 4 \
757 ? (u_int64_t) iovu.iov32[i].base : iovu.iov64[i].base)
758#define iov_iov_len(i) \
759 (personality_wordsize[current_personality] == 4 \
760 ? (u_int64_t) iovu.iov32[i].len : iovu.iov64[i].len)
761#else
John Hughes1d08dcf2001-07-10 13:48:44 +0000762 struct iovec *iov;
Dmitry V. Levin4ebb4e32006-12-13 17:08:08 +0000763#define sizeof_iov sizeof(*iov)
764#define iov_iov_base(i) iov[i].iov_base
765#define iov_iov_len(i) iov[i].iov_len
766#endif
John Hughes1d08dcf2001-07-10 13:48:44 +0000767 int i;
Roland McGrathaa524c82005-06-01 19:22:06 +0000768 unsigned long size;
John Hughes1d08dcf2001-07-10 13:48:44 +0000769
Dmitry V. Levin4ebb4e32006-12-13 17:08:08 +0000770 size = sizeof_iov * (unsigned long) len;
771 if (size / sizeof_iov != len
772 || (iov = malloc(size)) == NULL) {
Roland McGrathaa524c82005-06-01 19:22:06 +0000773 fprintf(stderr, "out of memory\n");
John Hughes1d08dcf2001-07-10 13:48:44 +0000774 return;
775 }
Roland McGrathaa524c82005-06-01 19:22:06 +0000776 if (umoven(tcp, addr, size, (char *) iov) >= 0) {
John Hughes1d08dcf2001-07-10 13:48:44 +0000777 for (i = 0; i < len; i++) {
Denys Vlasenkoadedb512008-12-30 18:47:55 +0000778 /* include the buffer number to make it easy to
779 * match up the trace with the source */
780 tprintf(" * %lu bytes in buffer %d\n",
781 (unsigned long)iov_iov_len(i), i);
782 dumpstr(tcp, (long) iov_iov_base(i),
783 iov_iov_len(i));
784 }
John Hughes1d08dcf2001-07-10 13:48:44 +0000785 }
786 free((char *) iov);
Dmitry V. Levin4ebb4e32006-12-13 17:08:08 +0000787#undef sizeof_iov
788#undef iov_iov_base
789#undef iov_iov_len
790#undef iov
John Hughes1d08dcf2001-07-10 13:48:44 +0000791}
792#endif
793
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000794void
795dumpstr(tcp, addr, len)
796struct tcb *tcp;
797long addr;
798int len;
799{
800 static int strsize = -1;
801 static unsigned char *str;
802 static char outstr[80];
803 char *s;
804 int i, j;
805
806 if (strsize < len) {
807 if (str)
808 free(str);
809 if ((str = malloc(len)) == NULL) {
Roland McGrath46100d02005-06-01 18:55:42 +0000810 fprintf(stderr, "out of memory\n");
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000811 return;
812 }
813 strsize = len;
814 }
815
816 if (umoven(tcp, addr, len, (char *) str) < 0)
817 return;
818
819 for (i = 0; i < len; i += 16) {
820 s = outstr;
821 sprintf(s, " | %05x ", i);
822 s += 9;
823 for (j = 0; j < 16; j++) {
824 if (j == 8)
825 *s++ = ' ';
826 if (i + j < len) {
827 sprintf(s, " %02x", str[i + j]);
828 s += 3;
829 }
830 else {
831 *s++ = ' '; *s++ = ' '; *s++ = ' ';
832 }
833 }
834 *s++ = ' '; *s++ = ' ';
835 for (j = 0; j < 16; j++) {
836 if (j == 8)
837 *s++ = ' ';
838 if (i + j < len) {
839 if (isprint(str[i + j]))
840 *s++ = str[i + j];
841 else
842 *s++ = '.';
843 }
844 else
845 *s++ = ' ';
846 }
847 tprintf("%s |\n", outstr);
848 }
849}
850
851#define PAGMASK (~(PAGSIZ - 1))
852/*
853 * move `len' bytes of data from process `pid'
854 * at address `addr' to our space at `laddr'
855 */
856int
Denys Vlasenkoef2fbf82009-01-06 21:45:06 +0000857umoven(struct tcb *tcp, long addr, int len, char *laddr)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000858{
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000859#ifdef LINUX
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000860 int n, m;
Wichert Akkerman5daa0281999-03-15 19:49:42 +0000861 int started = 0;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000862 union {
863 long val;
864 char x[sizeof(long)];
865 } u;
866
867 if (addr & (sizeof(long) - 1)) {
868 /* addr not a multiple of sizeof(long) */
869 n = addr - (addr & -sizeof(long)); /* residue */
870 addr &= -sizeof(long); /* residue */
Denys Vlasenko4dedd562009-02-24 15:17:53 +0000871 u.val = do_ptrace_peekdata(tcp, (char *) addr, started);
872 if (errno)
873 return u.val; /* 0 or -1 */
Wichert Akkerman5daa0281999-03-15 19:49:42 +0000874 started = 1;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000875 memcpy(laddr, &u.x[n], m = MIN(sizeof(long) - n, len));
876 addr += sizeof(long), laddr += m, len -= m;
877 }
878 while (len) {
Denys Vlasenko4dedd562009-02-24 15:17:53 +0000879 u.val = do_ptrace_peekdata(tcp, (char *) addr, started);
880 if (errno)
881 return u.val; /* 0 or -1 */
Wichert Akkerman5daa0281999-03-15 19:49:42 +0000882 started = 1;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000883 memcpy(laddr, u.x, m = MIN(sizeof(long), len));
884 addr += sizeof(long), laddr += m, len -= m;
885 }
886#endif /* LINUX */
887
888#ifdef SUNOS4
889 int pid = tcp->pid;
890#if 0
891 int n, m;
892 union {
893 long val;
894 char x[sizeof(long)];
895 } u;
896
897 if (addr & (sizeof(long) - 1)) {
898 /* addr not a multiple of sizeof(long) */
899 n = addr - (addr & -sizeof(long)); /* residue */
900 addr &= -sizeof(long); /* residue */
Denys Vlasenko4dedd562009-02-24 15:17:53 +0000901 u.val = do_ptrace(PTRACE_PEEKDATA, tcp, (char *) addr, 0);
902 if (errno)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000903 return -1;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000904 memcpy(laddr, &u.x[n], m = MIN(sizeof(long) - n, len));
905 addr += sizeof(long), laddr += m, len -= m;
906 }
907 while (len) {
Denys Vlasenko4dedd562009-02-24 15:17:53 +0000908 u.val = do_ptrace(PTRACE_PEEKDATA, tcp, (char *) addr, 0);
909 if (errno)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000910 return -1;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000911 memcpy(laddr, u.x, m = MIN(sizeof(long), len));
912 addr += sizeof(long), laddr += m, len -= m;
913 }
914#else /* !oldway */
915 int n;
916
917 while (len) {
918 n = MIN(len, PAGSIZ);
919 n = MIN(n, ((addr + PAGSIZ) & PAGMASK) - addr);
Denys Vlasenko4dedd562009-02-24 15:17:53 +0000920 if (do_ptrace5(PTRACE_READDATA, tcp, (char *) addr, len, laddr) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000921 return -1;
922 }
923 len -= n;
924 addr += n;
925 laddr += n;
926 }
927#endif /* !oldway */
928#endif /* SUNOS4 */
929
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000930#ifdef USE_PROCFS
Wichert Akkermanea78f0f1999-11-29 15:34:02 +0000931#ifdef HAVE_MP_PROCFS
John Hughesaa09c6b2001-05-15 14:53:43 +0000932 int fd = tcp->pfd_as;
Wichert Akkerman9ce1a631999-08-29 23:15:07 +0000933#else
John Hughesaa09c6b2001-05-15 14:53:43 +0000934 int fd = tcp->pfd;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000935#endif
John Hughesaa09c6b2001-05-15 14:53:43 +0000936 lseek(fd, addr, SEEK_SET);
937 if (read(fd, laddr, len) == -1)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000938 return -1;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000939#endif /* USE_PROCFS */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000940
941 return 0;
942}
943
944/*
945 * like `umove' but make the additional effort of looking
946 * for a terminating zero byte.
947 */
948int
Denys Vlasenkoef2fbf82009-01-06 21:45:06 +0000949umovestr(struct tcb *tcp, long addr, int len, char *laddr)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000950{
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000951#ifdef USE_PROCFS
John Hughesaa09c6b2001-05-15 14:53:43 +0000952#ifdef HAVE_MP_PROCFS
953 int fd = tcp->pfd_as;
954#else
955 int fd = tcp->pfd;
956#endif
957 /* Some systems (e.g. FreeBSD) can be upset if we read off the
958 end of valid memory, avoid this by trying to read up
959 to page boundaries. But we don't know what a page is (and
960 getpagesize(2) (if it exists) doesn't necessarily return
961 hardware page size). Assume all pages >= 1024 (a-historical
962 I know) */
963
964 int page = 1024; /* How to find this? */
965 int move = page - (addr & (page - 1));
966 int left = len;
967
968 lseek(fd, addr, SEEK_SET);
969
970 while (left) {
971 if (move > left) move = left;
John Hughes9cecf7f2001-10-16 10:20:22 +0000972 if ((move = read(fd, laddr, move)) <= 0)
John Hughesaa09c6b2001-05-15 14:53:43 +0000973 return left != len ? 0 : -1;
974 if (memchr (laddr, 0, move)) break;
975 left -= move;
976 laddr += move;
977 addr += move;
978 move = page;
979 }
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000980#else /* !USE_PROCFS */
Wichert Akkerman5daa0281999-03-15 19:49:42 +0000981 int started = 0;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000982 int i, n, m;
983 union {
984 long val;
985 char x[sizeof(long)];
986 } u;
987
988 if (addr & (sizeof(long) - 1)) {
989 /* addr not a multiple of sizeof(long) */
990 n = addr - (addr & -sizeof(long)); /* residue */
991 addr &= -sizeof(long); /* residue */
Denys Vlasenko4dedd562009-02-24 15:17:53 +0000992 u.val = do_ptrace_peekdata(tcp, (char *)addr, started);
993 if (errno)
994 return u.val; /* 0 or -1 */
Wichert Akkerman5daa0281999-03-15 19:49:42 +0000995 started = 1;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000996 memcpy(laddr, &u.x[n], m = MIN(sizeof(long)-n,len));
997 while (n & (sizeof(long) - 1))
998 if (u.x[n++] == '\0')
999 return 0;
1000 addr += sizeof(long), laddr += m, len -= m;
1001 }
1002 while (len) {
Denys Vlasenko4dedd562009-02-24 15:17:53 +00001003 u.val = do_ptrace_peekdata(tcp, (char *)addr, started);
1004 if (errno)
1005 return u.val; /* 0 or -1 */
Wichert Akkerman5daa0281999-03-15 19:49:42 +00001006 started = 1;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001007 memcpy(laddr, u.x, m = MIN(sizeof(long), len));
1008 for (i = 0; i < sizeof(long); i++)
1009 if (u.x[i] == '\0')
1010 return 0;
1011
1012 addr += sizeof(long), laddr += m, len -= m;
1013 }
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001014#endif /* !USE_PROCFS */
John Hughesaa09c6b2001-05-15 14:53:43 +00001015 return 0;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001016}
1017
1018#ifdef LINUX
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001019# if !defined (SPARC) && !defined(SPARC64)
1020# define PTRACE_WRITETEXT 101
1021# define PTRACE_WRITEDATA 102
1022# endif /* !SPARC && !SPARC64 */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001023#endif /* LINUX */
1024
1025#ifdef SUNOS4
1026
1027static int
Denys Vlasenko4dedd562009-02-24 15:17:53 +00001028uload(int cmd, struct tcb *tcp, long addr, int len, char *laddr)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001029{
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001030# if 0
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001031 int n;
1032
1033 while (len) {
1034 n = MIN(len, PAGSIZ);
1035 n = MIN(n, ((addr + PAGSIZ) & PAGMASK) - addr);
Denys Vlasenko4dedd562009-02-24 15:17:53 +00001036 if (do_ptrace5(cmd, tcp, (char *)addr, n, laddr) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001037 return -1;
1038 }
1039 len -= n;
1040 addr += n;
1041 laddr += n;
1042 }
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001043# else
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001044 int peek, poke;
1045 int n, m;
1046 union {
1047 long val;
1048 char x[sizeof(long)];
1049 } u;
1050
1051 if (cmd == PTRACE_WRITETEXT) {
1052 peek = PTRACE_PEEKTEXT;
1053 poke = PTRACE_POKETEXT;
1054 }
1055 else {
1056 peek = PTRACE_PEEKDATA;
1057 poke = PTRACE_POKEDATA;
1058 }
1059 if (addr & (sizeof(long) - 1)) {
1060 /* addr not a multiple of sizeof(long) */
1061 n = addr - (addr & -sizeof(long)); /* residue */
1062 addr &= -sizeof(long);
Denys Vlasenko4dedd562009-02-24 15:17:53 +00001063 u.val = do_ptrace(peek, tcp, (char *) addr, 0);
1064 if (errno)
1065 return -1;
1066 m = MIN(sizeof(long) - n;
1067 memcpy(&u.x[n], laddr, m, len));
1068 if (do_ptrace(poke, tcp, (char *)addr, u.val) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001069 return -1;
1070 }
Denys Vlasenko4dedd562009-02-24 15:17:53 +00001071 addr += sizeof(long);
1072 laddr += m;
1073 len -= m;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001074 }
Denys Vlasenko4dedd562009-02-24 15:17:53 +00001075 errno = 0;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001076 while (len) {
1077 if (len < sizeof(long))
Denys Vlasenko4dedd562009-02-24 15:17:53 +00001078 u.val = do_ptrace(peek, tcp, (char *) addr, 0);
1079 m = MIN(sizeof(long), len);
1080 memcpy(u.x, laddr, m);
1081 if (errno || do_ptrace(poke, tcp, (char *) addr, u.val) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001082 return -1;
1083 }
Denys Vlasenko4dedd562009-02-24 15:17:53 +00001084 addr += sizeof(long);
1085 laddr += m;
1086 len -= m;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001087 }
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001088# endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001089 return 0;
1090}
1091
Denys Vlasenko4dedd562009-02-24 15:17:53 +00001092static int
1093tload(struct tcb *tcp, int addr, int len, char *laddr)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001094{
Denys Vlasenko4dedd562009-02-24 15:17:53 +00001095 return uload(PTRACE_WRITETEXT, tcp, addr, len, laddr);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001096}
1097
1098#endif /* SUNOS4 */
1099
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001100#ifndef USE_PROCFS
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001101
1102int
Denys Vlasenko4dedd562009-02-24 15:17:53 +00001103upeek(struct tcb *tcp, long off, long *res)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001104{
1105 long val;
1106
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001107# ifdef SUNOS4_KERNEL_ARCH_KLUDGE
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001108 {
1109 static int is_sun4m = -1;
1110 struct utsname name;
1111
1112 /* Round up the usual suspects. */
1113 if (is_sun4m == -1) {
1114 if (uname(&name) < 0) {
1115 perror("upeek: uname?");
1116 exit(1);
1117 }
1118 is_sun4m = strcmp(name.machine, "sun4m") == 0;
1119 if (is_sun4m) {
Roland McGrathd9f816f2004-09-04 03:39:20 +00001120 const struct xlat *x;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001121
1122 for (x = struct_user_offsets; x->str; x++)
1123 x->val += 1024;
1124 }
1125 }
1126 if (is_sun4m)
1127 off += 1024;
1128 }
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001129# endif /* SUNOS4_KERNEL_ARCH_KLUDGE */
Denys Vlasenko732d1bf2008-12-17 19:21:59 +00001130 val = do_ptrace(PTRACE_PEEKUSER, tcp, (char *) off, 0);
Denys Vlasenko4dedd562009-02-24 15:17:53 +00001131 if (errno)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001132 return -1;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001133 *res = val;
1134 return 0;
1135}
1136
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001137#endif /* !USE_PROCFS */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001138
Roland McGratha4d48532005-06-08 20:45:28 +00001139#if 0
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001140long
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00001141getpc(struct tcb *tcp)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001142{
1143
1144#ifdef LINUX
1145 long pc;
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001146# if defined(I386)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001147 if (upeek(tcp, 4*EIP, &pc) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001148 return -1;
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001149# elif defined(X86_64)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001150 if (upeek(tcp, 8*RIP, &pc) < 0)
Michal Ludvig0e035502002-09-23 15:41:01 +00001151 return -1;
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001152# elif defined(IA64)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001153 if (upeek(tcp, PT_B0, &pc) < 0)
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00001154 return -1;
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001155# elif defined(ARM)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001156 if (upeek(tcp, 4*15, &pc) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001157 return -1;
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00001158# elif defined(AVR32)
1159 if (upeek(tcp, REG_PC, &pc) < 0)
1160 return -1;
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001161# elif defined(BFIN)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001162 if (upeek(tcp, REG_PC, &pc) < 0)
Dmitry V. Levin87ea1f42008-11-10 22:21:41 +00001163 return -1;
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001164# elif defined(POWERPC)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001165 if (upeek(tcp, sizeof(unsigned long)*PT_NIP, &pc) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001166 return -1;
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001167# elif defined(M68K)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001168 if (upeek(tcp, 4*PT_PC, &pc) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001169 return -1;
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001170# elif defined(ALPHA)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001171 if (upeek(tcp, REG_PC, &pc) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001172 return -1;
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001173# elif defined(MIPS)
1174 if (upeek(tcp, REG_EPC, &pc) < 0)
1175 return -1;
1176# elif defined(SPARC) || defined(SPARC64)
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001177 struct regs regs;
Denys Vlasenko4dedd562009-02-24 15:17:53 +00001178 if (do_ptrace(PTRACE_GETREGS, tcp, (char *) &regs, 0) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001179 return -1;
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001180 pc = regs.r_pc;
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001181# elif defined(S390) || defined(S390X)
Denys Vlasenko4dedd562009-02-24 15:17:53 +00001182 if (upeek(tcp, PT_PSWADDR, &pc) < 0)
Michal Ludvig10a88d02002-10-07 14:31:00 +00001183 return -1;
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001184# elif defined(HPPA)
Denys Vlasenko4dedd562009-02-24 15:17:53 +00001185 if (upeek(tcp, PT_IAOQ0, &pc) < 0)
Wichert Akkermanc1652e22001-03-27 12:17:16 +00001186 return -1;
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001187# elif defined(SH)
Denys Vlasenko4dedd562009-02-24 15:17:53 +00001188 if (upeek(tcp, 4*REG_PC, &pc) < 0)
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001189 return -1;
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001190# elif defined(SH64)
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001191 if (upeek(tcp, REG_PC ,&pc) < 0)
1192 return -1;
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001193# endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001194 return pc;
1195#endif /* LINUX */
1196
1197#ifdef SUNOS4
1198 /*
1199 * Return current program counter for `pid'
1200 * Assumes PC is never 0xffffffff
1201 */
1202 struct regs regs;
1203
Denys Vlasenko4dedd562009-02-24 15:17:53 +00001204 if (do_ptrace(PTRACE_GETREGS, tcp, (char *) &regs, 0) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001205 return -1;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001206 return regs.r_pc;
1207#endif /* SUNOS4 */
1208
1209#ifdef SVR4
1210 /* XXX */
1211 return 0;
1212#endif /* SVR4 */
1213
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001214#ifdef FREEBSD
1215 struct reg regs;
1216 pread(tcp->pfd_reg, &regs, sizeof(regs), 0);
1217 return regs.r_eip;
1218#endif /* FREEBSD */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001219}
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001220#endif /* 0 */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001221
1222void
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001223printcall(struct tcb *tcp)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001224{
Roland McGrath7a918832005-02-02 20:55:23 +00001225#define PRINTBADPC tprintf(sizeof(long) == 4 ? "[????????] " : \
1226 sizeof(long) == 8 ? "[????????????????] " : \
1227 NULL /* crash */)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001228
1229#ifdef LINUX
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001230# ifdef I386
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001231 long eip;
1232
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001233 if (upeek(tcp, 4*EIP, &eip) < 0) {
Roland McGrath7a918832005-02-02 20:55:23 +00001234 PRINTBADPC;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001235 return;
1236 }
1237 tprintf("[%08lx] ", eip);
Roland McGratheac26fc2005-02-02 02:48:53 +00001238
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001239# elif defined(S390) || defined(S390X)
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001240 long psw;
Denys Vlasenko4dedd562009-02-24 15:17:53 +00001241 if (upeek(tcp, PT_PSWADDR, &psw) < 0) {
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001242 PRINTBADPC;
1243 return;
1244 }
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001245# ifdef S390
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001246 tprintf("[%08lx] ", psw);
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001247# elif S390X
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001248 tprintf("[%16lx] ", psw);
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001249# endif
Roland McGratheac26fc2005-02-02 02:48:53 +00001250
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001251# elif defined(X86_64)
Michal Ludvig0e035502002-09-23 15:41:01 +00001252 long rip;
1253
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001254 if (upeek(tcp, 8*RIP, &rip) < 0) {
Roland McGrath7a918832005-02-02 20:55:23 +00001255 PRINTBADPC;
Michal Ludvig0e035502002-09-23 15:41:01 +00001256 return;
1257 }
1258 tprintf("[%16lx] ", rip);
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001259# elif defined(IA64)
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00001260 long ip;
1261
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001262 if (upeek(tcp, PT_B0, &ip) < 0) {
Roland McGrath7a918832005-02-02 20:55:23 +00001263 PRINTBADPC;
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00001264 return;
1265 }
1266 tprintf("[%08lx] ", ip);
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001267# elif defined(POWERPC)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001268 long pc;
1269
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001270 if (upeek(tcp, sizeof(unsigned long)*PT_NIP, &pc) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001271 tprintf ("[????????] ");
1272 return;
1273 }
1274 tprintf("[%08lx] ", pc);
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001275# elif defined(M68K)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001276 long pc;
1277
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001278 if (upeek(tcp, 4*PT_PC, &pc) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001279 tprintf ("[????????] ");
1280 return;
1281 }
1282 tprintf("[%08lx] ", pc);
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001283# elif defined(ALPHA)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001284 long pc;
1285
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001286 if (upeek(tcp, REG_PC, &pc) < 0) {
Roland McGrath7a918832005-02-02 20:55:23 +00001287 tprintf ("[????????????????] ");
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001288 return;
1289 }
1290 tprintf("[%08lx] ", pc);
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001291# elif defined(SPARC) || defined(SPARC64)
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001292 struct regs regs;
Denys Vlasenko4dedd562009-02-24 15:17:53 +00001293 if (do_ptrace(PTRACE_GETREGS, tcp, (char *) &regs, 0) < 0) {
Roland McGrath7a918832005-02-02 20:55:23 +00001294 PRINTBADPC;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001295 return;
1296 }
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001297 tprintf("[%08lx] ", regs.r_pc);
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001298# elif defined(HPPA)
Wichert Akkermanc1652e22001-03-27 12:17:16 +00001299 long pc;
1300
Denys Vlasenko4dedd562009-02-24 15:17:53 +00001301 if (upeek(tcp, PT_IAOQ0, &pc) < 0) {
Wichert Akkermanc1652e22001-03-27 12:17:16 +00001302 tprintf ("[????????] ");
1303 return;
1304 }
1305 tprintf("[%08lx] ", pc);
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001306# elif defined(MIPS)
Wichert Akkerman75c422b2001-04-10 10:22:50 +00001307 long pc;
1308
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001309 if (upeek(tcp, REG_EPC, &pc) < 0) {
Wichert Akkerman75c422b2001-04-10 10:22:50 +00001310 tprintf ("[????????] ");
1311 return;
1312 }
1313 tprintf("[%08lx] ", pc);
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001314# elif defined(SH)
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001315 long pc;
Wichert Akkermanccef6372002-05-01 16:39:22 +00001316
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001317 if (upeek(tcp, 4*REG_PC, &pc) < 0) {
1318 tprintf ("[????????] ");
1319 return;
1320 }
1321 tprintf("[%08lx] ", pc);
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001322# elif defined(SH64)
Roland McGrathe1e584b2003-06-02 19:18:58 +00001323 long pc;
1324
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001325 if (upeek(tcp, REG_PC, &pc) < 0) {
Roland McGrath7a918832005-02-02 20:55:23 +00001326 tprintf ("[????????????????] ");
Roland McGrathe1e584b2003-06-02 19:18:58 +00001327 return;
1328 }
1329 tprintf("[%08lx] ", pc);
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001330# elif defined(ARM)
Roland McGrathef388682003-06-03 23:28:59 +00001331 long pc;
Roland McGrathe1e584b2003-06-02 19:18:58 +00001332
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001333 if (upeek(tcp, 4*15, &pc) < 0) {
Roland McGrath7a918832005-02-02 20:55:23 +00001334 PRINTBADPC;
Roland McGrathef388682003-06-03 23:28:59 +00001335 return;
1336 }
1337 tprintf("[%08lx] ", pc);
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00001338# elif defined(AVR32)
1339 long pc;
1340
1341 if (upeek(tcp, REG_PC, &pc) < 0) {
1342 tprintf("[????????] ");
1343 return;
1344 }
1345 tprintf("[%08lx] ", pc);
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001346# elif defined(BFIN)
Dmitry V. Levin87ea1f42008-11-10 22:21:41 +00001347 long pc;
1348
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001349 if (upeek(tcp, PT_PC, &pc) < 0) {
Dmitry V. Levin87ea1f42008-11-10 22:21:41 +00001350 PRINTBADPC;
1351 return;
1352 }
1353 tprintf("[%08lx] ", pc);
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001354#elif defined(CRISV10)
1355 long pc;
1356
1357 if (upeek(tcp->pid, 4*PT_IRP, &pc) < 0) {
1358 PRINTBADPC;
1359 return;
1360 }
1361 tprintf("[%08lx] ", pc);
1362#elif defined(CRISV32)
1363 long pc;
1364
1365 if (upeek(tcp->pid, 4*PT_ERP, &pc) < 0) {
1366 PRINTBADPC;
1367 return;
1368 }
1369 tprintf("[%08lx] ", pc);
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001370# endif /* architecture */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001371#endif /* LINUX */
1372
1373#ifdef SUNOS4
1374 struct regs regs;
1375
Denys Vlasenko4dedd562009-02-24 15:17:53 +00001376 if (do_ptrace(PTRACE_GETREGS, tcp, (char *) &regs, 0) < 0) {
Roland McGrath7a918832005-02-02 20:55:23 +00001377 PRINTBADPC;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001378 return;
1379 }
1380 tprintf("[%08x] ", regs.r_o7);
1381#endif /* SUNOS4 */
1382
1383#ifdef SVR4
1384 /* XXX */
Roland McGrath7a918832005-02-02 20:55:23 +00001385 PRINTBADPC;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001386#endif
1387
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001388#ifdef FREEBSD
1389 struct reg regs;
1390 pread(tcp->pfd_reg, &regs, sizeof(regs), 0);
1391 tprintf("[%08x] ", regs.r_eip);
1392#endif /* FREEBSD */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001393}
1394
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001395
1396/*
1397 * These #if's are huge, please indent them correctly.
1398 * It's easy to get confused otherwise.
1399 */
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001400#ifndef USE_PROCFS
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001401
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001402# if defined LINUX
Roland McGrathd81f1d92003-01-09 06:53:34 +00001403
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001404# include "syscall.h"
Roland McGrath3291ef22008-05-20 00:34:34 +00001405
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001406# include <sys/syscall.h>
1407# ifndef CLONE_PTRACE
1408# define CLONE_PTRACE 0x00002000
1409# endif
1410# ifndef CLONE_VFORK
1411# define CLONE_VFORK 0x00004000
1412# endif
1413# ifndef CLONE_VM
1414# define CLONE_VM 0x00000100
1415# endif
1416# ifndef CLONE_STOPPED
1417# define CLONE_STOPPED 0x02000000
1418# endif
Roland McGrathd81f1d92003-01-09 06:53:34 +00001419
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001420# ifdef IA64
Roland McGrathd81f1d92003-01-09 06:53:34 +00001421
Roland McGrath08267b82004-02-20 22:56:43 +00001422/* We don't have fork()/vfork() syscalls on ia64 itself, but the ia32
1423 subsystem has them for x86... */
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001424# define SYS_fork 2
1425# define SYS_vfork 190
Roland McGrath08267b82004-02-20 22:56:43 +00001426
Roland McGrathd81f1d92003-01-09 06:53:34 +00001427typedef unsigned long *arg_setup_state;
1428
1429static int
1430arg_setup(struct tcb *tcp, arg_setup_state *state)
1431{
Jan Kratochvil1f942712008-08-06 21:38:52 +00001432 unsigned long cfm, sof, sol;
1433 long bsp;
Roland McGrathd81f1d92003-01-09 06:53:34 +00001434
Jan Kratochvil1f942712008-08-06 21:38:52 +00001435 if (ia32) {
1436 /* Satisfy a false GCC warning. */
1437 *state = NULL;
Roland McGrath08267b82004-02-20 22:56:43 +00001438 return 0;
Jan Kratochvil1f942712008-08-06 21:38:52 +00001439 }
Roland McGrath08267b82004-02-20 22:56:43 +00001440
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001441 if (upeek(tcp, PT_AR_BSP, &bsp) < 0)
Roland McGrathd81f1d92003-01-09 06:53:34 +00001442 return -1;
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001443 if (upeek(tcp, PT_CFM, (long *) &cfm) < 0)
Roland McGrathd81f1d92003-01-09 06:53:34 +00001444 return -1;
1445
1446 sof = (cfm >> 0) & 0x7f;
1447 sol = (cfm >> 7) & 0x7f;
Jan Kratochvil1f942712008-08-06 21:38:52 +00001448 bsp = (long) ia64_rse_skip_regs((unsigned long *) bsp, -sof + sol);
Roland McGrathd81f1d92003-01-09 06:53:34 +00001449
Jan Kratochvil1f942712008-08-06 21:38:52 +00001450 *state = (unsigned long *) bsp;
Roland McGrathd81f1d92003-01-09 06:53:34 +00001451 return 0;
1452}
1453
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001454# define arg_finish_change(tcp, state) 0
Roland McGrathd81f1d92003-01-09 06:53:34 +00001455
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001456# ifdef SYS_fork
Roland McGrathd81f1d92003-01-09 06:53:34 +00001457static int
1458get_arg0 (struct tcb *tcp, arg_setup_state *state, long *valp)
1459{
Roland McGrath08267b82004-02-20 22:56:43 +00001460 int ret;
1461
1462 if (ia32)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001463 ret = upeek (tcp, PT_R11, valp);
Roland McGrath08267b82004-02-20 22:56:43 +00001464 else
1465 ret = umoven (tcp,
1466 (unsigned long) ia64_rse_skip_regs(*state, 0),
1467 sizeof(long), (void *) valp);
1468 return ret;
Roland McGrathd81f1d92003-01-09 06:53:34 +00001469}
1470
1471static int
1472get_arg1 (struct tcb *tcp, arg_setup_state *state, long *valp)
1473{
Roland McGrath08267b82004-02-20 22:56:43 +00001474 int ret;
1475
1476 if (ia32)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001477 ret = upeek (tcp, PT_R9, valp);
Roland McGrath08267b82004-02-20 22:56:43 +00001478 else
1479 ret = umoven (tcp,
1480 (unsigned long) ia64_rse_skip_regs(*state, 1),
1481 sizeof(long), (void *) valp);
1482 return ret;
Roland McGrathd81f1d92003-01-09 06:53:34 +00001483}
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001484# endif
Roland McGrathd81f1d92003-01-09 06:53:34 +00001485
1486static int
1487set_arg0 (struct tcb *tcp, arg_setup_state *state, long val)
1488{
Roland McGrath08267b82004-02-20 22:56:43 +00001489 int req = PTRACE_POKEDATA;
1490 void *ap;
1491
1492 if (ia32) {
1493 ap = (void *) (intptr_t) PT_R11; /* r11 == EBX */
1494 req = PTRACE_POKEUSER;
1495 } else
1496 ap = ia64_rse_skip_regs(*state, 0);
Denys Vlasenko4dedd562009-02-24 15:17:53 +00001497 if (do_ptrace(req, tcp, ap, val) < 0)
1498 return -1;
1499 return 0;
Roland McGrathd81f1d92003-01-09 06:53:34 +00001500}
1501
1502static int
1503set_arg1 (struct tcb *tcp, arg_setup_state *state, long val)
1504{
Roland McGrath08267b82004-02-20 22:56:43 +00001505 int req = PTRACE_POKEDATA;
1506 void *ap;
1507
1508 if (ia32) {
1509 ap = (void *) (intptr_t) PT_R9; /* r9 == ECX */
1510 req = PTRACE_POKEUSER;
1511 } else
1512 ap = ia64_rse_skip_regs(*state, 1);
Denys Vlasenko4dedd562009-02-24 15:17:53 +00001513 if (do_ptrace(req, tcp, ap, val) < 0)
1514 return -1;
1515 return 0;
Roland McGrathd81f1d92003-01-09 06:53:34 +00001516}
1517
Roland McGrathb659f872008-07-18 01:19:36 +00001518/* ia64 does not return the input arguments from functions (and syscalls)
1519 according to ia64 RSE (Register Stack Engine) behavior. */
1520
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001521# define restore_arg0(tcp, state, val) ((void) (state), 0)
1522# define restore_arg1(tcp, state, val) ((void) (state), 0)
Roland McGrathb659f872008-07-18 01:19:36 +00001523
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001524# elif defined (SPARC) || defined (SPARC64)
Roland McGrathd81f1d92003-01-09 06:53:34 +00001525
1526typedef struct regs arg_setup_state;
1527
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001528# define arg_setup(tcp, state) \
Denys Vlasenko4dedd562009-02-24 15:17:53 +00001529 (do_ptrace(PTRACE_GETREGS, tcp, (char *) (state), 0))
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001530# define arg_finish_change(tcp, state) \
Denys Vlasenko4dedd562009-02-24 15:17:53 +00001531 (do_ptrace(PTRACE_SETREGS, tcp, (char *) (state), 0))
Roland McGrathd81f1d92003-01-09 06:53:34 +00001532
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001533# define get_arg0(tcp, state, valp) (*(valp) = (state)->r_o0, 0)
1534# define get_arg1(tcp, state, valp) (*(valp) = (state)->r_o1, 0)
1535# define set_arg0(tcp, state, val) ((state)->r_o0 = (val), 0)
1536# define set_arg1(tcp, state, val) ((state)->r_o1 = (val), 0)
1537# define restore_arg0(tcp, state, val) 0
Roland McGrathd81f1d92003-01-09 06:53:34 +00001538
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001539# else /* other architectures */
Roland McGrathd81f1d92003-01-09 06:53:34 +00001540
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001541# if defined S390 || defined S390X
Roland McGrath7b308222003-01-20 09:04:36 +00001542/* Note: this is only true for the `clone' system call, which handles
1543 arguments specially. We could as well say that its first two arguments
1544 are swapped relative to other architectures, but that would just be
1545 another #ifdef in the calls. */
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001546# define arg0_offset PT_GPR3
1547# define arg1_offset PT_ORIGGPR2
1548# define restore_arg0(tcp, state, val) ((void) (state), 0)
1549# define restore_arg1(tcp, state, val) ((void) (state), 0)
1550# define arg0_index 1
1551# define arg1_index 0
1552# elif defined (ALPHA) || defined (MIPS)
1553# define arg0_offset REG_A0
1554# define arg1_offset (REG_A0+1)
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00001555# elif defined (AVR32)
1556# define arg0_offset (REG_R12)
1557# define arg1_offset (REG_R11)
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001558# elif defined (POWERPC)
1559# define arg0_offset (sizeof(unsigned long)*PT_R3)
1560# define arg1_offset (sizeof(unsigned long)*PT_R4)
1561# define restore_arg0(tcp, state, val) ((void) (state), 0)
1562# elif defined (HPPA)
1563# define arg0_offset PT_GR26
1564# define arg1_offset (PT_GR26-4)
1565# elif defined (X86_64)
1566# define arg0_offset ((long)(8*(current_personality ? RBX : RDI)))
1567# define arg1_offset ((long)(8*(current_personality ? RCX : RSI)))
1568# elif defined (SH)
1569# define arg0_offset (4*(REG_REG0+4))
1570# define arg1_offset (4*(REG_REG0+5))
1571# elif defined (SH64)
1572 /* ABI defines arg0 & 1 in r2 & r3 */
1573# define arg0_offset (REG_OFFSET+16)
1574# define arg1_offset (REG_OFFSET+24)
1575# define restore_arg0(tcp, state, val) 0
Denys Vlasenkoea0e6e82009-02-25 17:08:40 +00001576# elif defined CRISV10 || defined CRISV32
1577# define arg0_offset (4*PT_R11)
1578# define arg1_offset (4*PT_ORIG_R10)
1579# define restore_arg0(tcp, state, val) 0
1580# define restore_arg1(tcp, state, val) 0
1581# define arg0_index 1
1582# define arg1_index 0
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001583# else
1584# define arg0_offset 0
1585# define arg1_offset 4
1586# if defined ARM
1587# define restore_arg0(tcp, state, val) 0
1588# endif
1589# endif
Roland McGrathd81f1d92003-01-09 06:53:34 +00001590
1591typedef int arg_setup_state;
1592
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001593# define arg_setup(tcp, state) (0)
1594# define arg_finish_change(tcp, state) 0
1595# define get_arg0(tcp, cookie, valp) \
1596 (upeek ((tcp), arg0_offset, (valp)))
1597# define get_arg1(tcp, cookie, valp) \
1598 (upeek ((tcp), arg1_offset, (valp)))
Roland McGrathd81f1d92003-01-09 06:53:34 +00001599
1600static int
Denys Vlasenko4dedd562009-02-24 15:17:53 +00001601set_arg0(struct tcb *tcp, void *cookie, long val)
Roland McGrathd81f1d92003-01-09 06:53:34 +00001602{
Denys Vlasenko4dedd562009-02-24 15:17:53 +00001603 return do_ptrace(PTRACE_POKEUSER, tcp, (char*)arg0_offset, val);
Roland McGrathd81f1d92003-01-09 06:53:34 +00001604}
1605
1606static int
Denys Vlasenko4dedd562009-02-24 15:17:53 +00001607set_arg1(struct tcb *tcp, void *cookie, long val)
Roland McGrathd81f1d92003-01-09 06:53:34 +00001608{
Denys Vlasenko4dedd562009-02-24 15:17:53 +00001609 return do_ptrace(PTRACE_POKEUSER, tcp, (char*)arg1_offset, val);
Roland McGrathd81f1d92003-01-09 06:53:34 +00001610}
1611
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001612# endif /* architectures */
Roland McGrathd81f1d92003-01-09 06:53:34 +00001613
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001614# ifndef restore_arg0
1615# define restore_arg0(tcp, state, val) set_arg0((tcp), (state), (val))
1616# endif
1617# ifndef restore_arg1
1618# define restore_arg1(tcp, state, val) set_arg1((tcp), (state), (val))
1619# endif
Roland McGrathd81f1d92003-01-09 06:53:34 +00001620
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001621# ifndef arg0_index
1622# define arg0_index 0
1623# define arg1_index 1
1624# endif
Roland McGrath90d0afd2004-03-01 21:05:16 +00001625
Roland McGrathd81f1d92003-01-09 06:53:34 +00001626int
Denys Vlasenko418d66a2009-01-17 01:52:54 +00001627setbpt(struct tcb *tcp)
Roland McGrathd81f1d92003-01-09 06:53:34 +00001628{
Roland McGrath3291ef22008-05-20 00:34:34 +00001629 static int clone_scno[SUPPORTED_PERSONALITIES] = { SYS_clone };
Roland McGrathd81f1d92003-01-09 06:53:34 +00001630 arg_setup_state state;
1631
1632 if (tcp->flags & TCB_BPTSET) {
1633 fprintf(stderr, "PANIC: TCB already set in pid %u\n", tcp->pid);
1634 return -1;
1635 }
1636
Roland McGrath3291ef22008-05-20 00:34:34 +00001637 /*
1638 * It's a silly kludge to initialize this with a search at runtime.
1639 * But it's better than maintaining another magic thing in the
1640 * godforsaken tables.
1641 */
1642 if (clone_scno[current_personality] == 0) {
1643 int i;
1644 for (i = 0; i < nsyscalls; ++i)
1645 if (sysent[i].sys_func == sys_clone) {
1646 clone_scno[current_personality] = i;
1647 break;
1648 }
1649 }
1650
Roland McGrath76989d72005-06-07 23:21:31 +00001651 switch (known_scno(tcp)) {
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001652# ifdef SYS_vfork
Roland McGrath9383c6c2003-01-18 00:19:31 +00001653 case SYS_vfork:
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001654# endif
1655# ifdef SYS_fork
Roland McGrathd81f1d92003-01-09 06:53:34 +00001656 case SYS_fork:
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001657# endif
1658# if defined SYS_fork || defined SYS_vfork
Roland McGrathd81f1d92003-01-09 06:53:34 +00001659 if (arg_setup (tcp, &state) < 0
1660 || get_arg0 (tcp, &state, &tcp->inst[0]) < 0
1661 || get_arg1 (tcp, &state, &tcp->inst[1]) < 0
Roland McGrath3291ef22008-05-20 00:34:34 +00001662 || change_syscall(tcp, clone_scno[current_personality]) < 0
Roland McGrathd81f1d92003-01-09 06:53:34 +00001663 || set_arg0 (tcp, &state, CLONE_PTRACE|SIGCHLD) < 0
1664 || set_arg1 (tcp, &state, 0) < 0
1665 || arg_finish_change (tcp, &state) < 0)
1666 return -1;
Roland McGrathc9dc3c12004-03-01 20:57:09 +00001667 tcp->u_arg[arg0_index] = CLONE_PTRACE|SIGCHLD;
1668 tcp->u_arg[arg1_index] = 0;
Roland McGrathd81f1d92003-01-09 06:53:34 +00001669 tcp->flags |= TCB_BPTSET;
1670 return 0;
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001671# endif
Roland McGrathd81f1d92003-01-09 06:53:34 +00001672
1673 case SYS_clone:
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001674# ifdef SYS_clone2
Roland McGrathd81f1d92003-01-09 06:53:34 +00001675 case SYS_clone2:
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001676# endif
Jan Kratochvil8fc95752008-08-06 21:43:35 +00001677 /* ia64 calls directly `clone (CLONE_VFORK | CLONE_VM)'
1678 contrary to x86 SYS_vfork above. Even on x86 we turn the
1679 vfork semantics into plain fork - each application must not
1680 depend on the vfork specifics according to POSIX. We would
1681 hang waiting for the parent resume otherwise. We need to
1682 clear also CLONE_VM but only in the CLONE_VFORK case as
1683 otherwise we would break pthread_create. */
1684
Roland McGrathd6ff0d52008-07-18 01:09:44 +00001685 if ((arg_setup (tcp, &state) < 0
1686 || set_arg0 (tcp, &state,
1687 (tcp->u_arg[arg0_index] | CLONE_PTRACE)
Jan Kratochvil8fc95752008-08-06 21:43:35 +00001688 & ~(tcp->u_arg[arg0_index] & CLONE_VFORK
1689 ? CLONE_VFORK | CLONE_VM : 0)) < 0
Roland McGrathd6ff0d52008-07-18 01:09:44 +00001690 || arg_finish_change (tcp, &state) < 0))
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00001691 return -1;
Roland McGrathd81f1d92003-01-09 06:53:34 +00001692 tcp->flags |= TCB_BPTSET;
Roland McGrathc9dc3c12004-03-01 20:57:09 +00001693 tcp->inst[0] = tcp->u_arg[arg0_index];
1694 tcp->inst[1] = tcp->u_arg[arg1_index];
Roland McGrathd81f1d92003-01-09 06:53:34 +00001695 return 0;
1696
1697 default:
1698 fprintf(stderr, "PANIC: setbpt for syscall %ld on %u???\n",
1699 tcp->scno, tcp->pid);
1700 break;
1701 }
1702
1703 return -1;
1704}
1705
1706int
1707clearbpt(tcp)
1708struct tcb *tcp;
1709{
1710 arg_setup_state state;
1711 if (arg_setup (tcp, &state) < 0
Roland McGrathe1df47f2003-01-14 09:46:15 +00001712 || restore_arg0 (tcp, &state, tcp->inst[0]) < 0
1713 || restore_arg1 (tcp, &state, tcp->inst[1]) < 0
Roland McGrathd81f1d92003-01-09 06:53:34 +00001714 || arg_finish_change (tcp, &state))
1715 return -1;
1716 tcp->flags &= ~TCB_BPTSET;
1717 return 0;
1718}
1719
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001720# else /* !defined LINUX */
Roland McGrathd81f1d92003-01-09 06:53:34 +00001721
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001722int
1723setbpt(tcp)
1724struct tcb *tcp;
1725{
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001726# ifdef LINUX
1727 DEAD CODE HERE? WE ARE IN 'else !defined LINUX'
1728# if defined (SPARC) || defined (SPARC64)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001729 /* We simply use the SunOS breakpoint code. */
1730
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001731 struct regs regs;
Roland McGrath6d1a65c2004-07-12 07:44:08 +00001732 unsigned long inst;
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001733# define LOOPA 0x30800000 /* ba,a 0 */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001734
1735 if (tcp->flags & TCB_BPTSET) {
1736 fprintf(stderr, "PANIC: TCB already set in pid %u\n", tcp->pid);
1737 return -1;
1738 }
Denys Vlasenko4dedd562009-02-24 15:17:53 +00001739 if (do_ptrace(PTRACE_GETREGS, tcp, (char *)&regs, 0) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001740 return -1;
1741 }
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001742 tcp->baddr = regs.r_o7 + 8;
Denys Vlasenko4dedd562009-02-24 15:17:53 +00001743 tcp->inst[0] = do_ptrace(PTRACE_PEEKTEXT, tcp, (char *)tcp->baddr, 0);
1744 if (errno)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001745 return -1;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001746
1747 /*
1748 * XXX - BRUTAL MODE ON
1749 * We cannot set a real BPT in the child, since it will not be
1750 * traced at the moment it will reach the trap and would probably
1751 * die with a core dump.
1752 * Thus, we are force our way in by taking out two instructions
1753 * and insert an eternal loop instead, in expectance of the SIGSTOP
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001754 * generated by our PTRACE_ATTACH.
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001755 * Of cause, if we evaporate ourselves in the middle of all this...
1756 */
1757 errno = 0;
Roland McGrath6d1a65c2004-07-12 07:44:08 +00001758 inst = LOOPA;
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001759# if defined (SPARC64)
Roland McGrath6d1a65c2004-07-12 07:44:08 +00001760 inst <<= 32;
1761 inst |= (tcp->inst[0] & 0xffffffffUL);
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001762# endif
Denys Vlasenko4dedd562009-02-24 15:17:53 +00001763 if (do_ptrace(PTRACE_POKETEXT, tcp, (char *) tcp->baddr, inst) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001764 return -1;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001765 tcp->flags |= TCB_BPTSET;
1766
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001767# else /* !SPARC && !SPARC64 */
1768# ifdef IA64
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00001769 if (ia32) {
1770# define LOOP 0x0000feeb
1771 if (tcp->flags & TCB_BPTSET) {
1772 fprintf(stderr, "PANIC: bpt already set in pid %u\n",
1773 tcp->pid);
1774 return -1;
1775 }
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001776 if (upeek(tcp, PT_CR_IIP, &tcp->baddr) < 0)
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00001777 return -1;
1778 if (debug)
1779 fprintf(stderr, "[%d] setting bpt at %lx\n",
1780 tcp->pid, tcp->baddr);
Denys Vlasenko4dedd562009-02-24 15:17:53 +00001781 tcp->inst[0] = do_ptrace(PTRACE_PEEKTEXT, tcp, (char *) tcp->baddr, 0);
1782 if (errno)
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00001783 return -1;
Denys Vlasenko4dedd562009-02-24 15:17:53 +00001784 if (do_ptrace(PTRACE_POKETEXT, tcp, (char *) tcp->baddr, LOOP) < 0)
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00001785 return -1;
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00001786 tcp->flags |= TCB_BPTSET;
1787 } else {
1788 /*
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00001789 * Our strategy here is to replace the bundle that
1790 * contained the clone() syscall with a bundle of the
1791 * form:
1792 *
1793 * { 1: br 1b; br 1b; br 1b }
1794 *
1795 * This ensures that the newly forked child will loop
1796 * endlessly until we've got a chance to attach to it.
1797 */
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001798# define LOOP0 0x0000100000000017
1799# define LOOP1 0x4000000000200000
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00001800 unsigned long addr, ipsr;
1801 pid_t pid;
1802
1803 pid = tcp->pid;
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001804 if (upeek(tcp, PT_CR_IPSR, &ipsr) < 0)
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00001805 return -1;
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001806 if (upeek(tcp, PT_CR_IIP, &addr) < 0)
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00001807 return -1;
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00001808 /* store "ri" in low two bits */
1809 tcp->baddr = addr | ((ipsr >> 41) & 0x3);
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00001810
Denys Vlasenko4dedd562009-02-24 15:17:53 +00001811 tcp->inst[0] = do_ptrace(PTRACE_PEEKTEXT, tcp, (char *) addr + 0, 0);
1812 if (!errno)
1813 tcp->inst[1] = do_ptrace(PTRACE_PEEKTEXT, tcp, (char *) addr + 8, 0);
1814 if (errno)
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00001815 return -1;
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00001816
Denys Vlasenko4dedd562009-02-24 15:17:53 +00001817 if (do_ptrace(PTRACE_POKETEXT, tcp, (char *) addr + 0, LOOP0) < 0
1818 || do_ptrace(PTRACE_POKETEXT, tcp, (char *) addr + 8, LOOP1) < 0
1819 ) {
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00001820 return -1;
1821 }
1822 tcp->flags |= TCB_BPTSET;
1823 }
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001824# else /* !IA64 */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001825
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001826# if defined (I386) || defined(X86_64)
1827# define LOOP 0x0000feeb
1828# elif defined (M68K)
1829# define LOOP 0x60fe0000
1830# elif defined (ALPHA)
1831# define LOOP 0xc3ffffff
1832# elif defined (POWERPC)
1833# define LOOP 0x48000000
1834# elif defined(ARM)
1835# define LOOP 0xEAFFFFFE
1836# elif defined(MIPS)
1837# define LOOP 0x1000ffff
1838# elif defined(S390)
1839# define LOOP 0xa7f40000 /* BRC 15,0 */
1840# elif defined(S390X)
1841# define LOOP 0xa7f4000000000000UL /* BRC 15,0 */
1842# elif defined(HPPA)
1843# define LOOP 0xe81f1ff7 /* b,l,n <loc>,r0 */
1844# elif defined(SH)
1845# ifdef __LITTLE_ENDIAN__
1846# define LOOP 0x0000affe
1847# else
1848# define LOOP 0xfeaf0000
1849# endif
1850# else
1851# error unknown architecture
1852# endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001853
1854 if (tcp->flags & TCB_BPTSET) {
1855 fprintf(stderr, "PANIC: bpt already set in pid %u\n", tcp->pid);
1856 return -1;
1857 }
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001858# if defined (I386)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001859 if (upeek(tcp, 4*EIP, &tcp->baddr) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001860 return -1;
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001861# elif defined (X86_64)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001862 if (upeek(tcp, 8*RIP, &tcp->baddr) < 0)
Michal Ludvig0e035502002-09-23 15:41:01 +00001863 return -1;
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001864# elif defined (M68K)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001865 if (upeek(tcp, 4*PT_PC, &tcp->baddr) < 0)
Denys Vlasenko5ae2b7c2009-02-27 20:32:52 +00001866 return -1;
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001867# elif defined (ALPHA)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001868 return -1;
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001869# elif defined (ARM)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001870 return -1;
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001871# elif defined (MIPS)
Wichert Akkermanf90da011999-10-31 21:15:38 +00001872 return -1; /* FIXME: I do not know what i do - Flo */
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001873# elif defined (POWERPC)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001874 if (upeek(tcp, sizeof(unsigned long)*PT_NIP, &tcp->baddr) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001875 return -1;
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001876# elif defined(S390) || defined(S390X)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001877 if (upeek(tcp,PT_PSWADDR, &tcp->baddr) < 0)
Wichert Akkerman4dc8a2a1999-12-23 14:20:14 +00001878 return -1;
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001879# elif defined(HPPA)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001880 if (upeek(tcp, PT_IAOQ0, &tcp->baddr) < 0)
Wichert Akkermanc1652e22001-03-27 12:17:16 +00001881 return -1;
1882 tcp->baddr &= ~0x03;
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001883# elif defined(SH)
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001884 if (upeek(tcp, 4*REG_PC, &tcp->baddr) < 0)
1885 return -1;
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001886# else
1887# error unknown architecture
1888# endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001889 if (debug)
1890 fprintf(stderr, "[%d] setting bpt at %lx\n", tcp->pid, tcp->baddr);
Denys Vlasenko4dedd562009-02-24 15:17:53 +00001891 tcp->inst[0] = do_ptrace(PTRACE_PEEKTEXT, tcp, (char *) tcp->baddr, 0);
1892 if (errno)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001893 return -1;
Denys Vlasenko4dedd562009-02-24 15:17:53 +00001894 if (do_ptrace(PTRACE_POKETEXT, tcp, (char *) tcp->baddr, LOOP) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001895 return -1;
1896 }
1897 tcp->flags |= TCB_BPTSET;
1898
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001899# endif /* !IA64 */
1900# endif /* !SPARC && !SPARC64 */
1901# endif /* LINUX */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001902
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001903# ifdef SUNOS4
1904# ifdef SPARC /* This code is slightly sparc specific */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001905
Wichert Akkermane6f876c1999-06-22 15:28:30 +00001906 struct regs regs;
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001907# define BPT 0x91d02001 /* ta 1 */
1908# define LOOP 0x10800000 /* ba 0 */
1909# define LOOPA 0x30800000 /* ba,a 0 */
1910# define NOP 0x01000000
1911# if LOOPA
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001912 static int loopdeloop[1] = {LOOPA};
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001913# else
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001914 static int loopdeloop[2] = {LOOP, NOP};
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001915# endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001916
1917 if (tcp->flags & TCB_BPTSET) {
1918 fprintf(stderr, "PANIC: TCB already set in pid %u\n", tcp->pid);
1919 return -1;
1920 }
Denys Vlasenko4dedd562009-02-24 15:17:53 +00001921 if (do_ptrace(PTRACE_GETREGS, tcp, (char *)&regs, 0) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001922 return -1;
1923 }
1924 tcp->baddr = regs.r_o7 + 8;
Denys Vlasenko4dedd562009-02-24 15:17:53 +00001925 if (do_ptrace5(PTRACE_READTEXT, tcp, (char *)tcp->baddr,
1926 sizeof tcp->inst, (char *)tcp->inst, "READTEXT") < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001927 return -1;
1928 }
1929
1930 /*
1931 * XXX - BRUTAL MODE ON
1932 * We cannot set a real BPT in the child, since it will not be
1933 * traced at the moment it will reach the trap and would probably
1934 * die with a core dump.
1935 * Thus, we are force our way in by taking out two instructions
1936 * and insert an eternal loop in stead, in expectance of the SIGSTOP
1937 * generated by out PTRACE_ATTACH.
1938 * Of cause, if we evaporate ourselves in the middle of all this...
1939 */
Denys Vlasenko4dedd562009-02-24 15:17:53 +00001940 if (do_ptrace5(PTRACE_WRITETEXT, tcp, (char *) tcp->baddr,
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001941 sizeof loopdeloop, (char *) loopdeloop) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001942 return -1;
1943 }
1944 tcp->flags |= TCB_BPTSET;
1945
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001946# endif /* SPARC */
1947# endif /* SUNOS4 */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001948
1949 return 0;
1950}
1951
1952int
1953clearbpt(tcp)
1954struct tcb *tcp;
1955{
1956
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001957# ifdef LINUX
1958 DEAD CODE HERE? WE ARE IN 'else !defined LINUX'
1959# if defined(I386) || defined(X86_64)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001960 long eip;
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001961# elif defined(POWERPC)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001962 long pc;
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001963# elif defined(M68K)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001964 long pc;
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001965# elif defined(ALPHA)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001966 long pc;
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001967# elif defined(HPPA)
Wichert Akkermanc1652e22001-03-27 12:17:16 +00001968 long iaoq;
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001969# elif defined(SH)
Denys Vlasenkoadedb512008-12-30 18:47:55 +00001970 long pc;
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001971# endif /* architecture */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001972
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001973# if defined (SPARC) || defined (SPARC64)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001974 /* Again, we borrow the SunOS breakpoint code. */
1975 if (!(tcp->flags & TCB_BPTSET)) {
1976 fprintf(stderr, "PANIC: TCB not set in pid %u\n", tcp->pid);
1977 return -1;
1978 }
Denys Vlasenko4dedd562009-02-24 15:17:53 +00001979 if (do_ptrace(PTRACE_POKETEXT, tcp, (char *) tcp->baddr, tcp->inst[0]) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001980 return -1;
1981 }
1982 tcp->flags &= ~TCB_BPTSET;
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00001983# elif defined(IA64)
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00001984 if (ia32) {
1985 unsigned long addr;
1986
1987 if (debug)
1988 fprintf(stderr, "[%d] clearing bpt\n", tcp->pid);
1989 if (!(tcp->flags & TCB_BPTSET)) {
1990 fprintf(stderr, "PANIC: TCB not set in pid %u\n", tcp->pid);
1991 return -1;
1992 }
Denys Vlasenko4dedd562009-02-24 15:17:53 +00001993 if (do_ptrace(PTRACE_POKETEXT, tcp, (char *) tcp->baddr, tcp->inst[0]) < 0) {
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00001994 return -1;
1995 }
1996 tcp->flags &= ~TCB_BPTSET;
1997
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00001998 if (upeek(tcp, PT_CR_IIP, &addr) < 0)
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00001999 return -1;
2000 if (addr != tcp->baddr) {
2001 /* The breakpoint has not been reached yet. */
2002 if (debug)
2003 fprintf(stderr,
2004 "NOTE: PC not at bpt (pc %#lx baddr %#lx)\n",
2005 addr, tcp->baddr);
2006 return 0;
2007 }
2008 } else {
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00002009 unsigned long addr, ipsr;
2010 pid_t pid;
2011
2012 pid = tcp->pid;
2013
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00002014 if (upeek(tcp, PT_CR_IPSR, &ipsr) < 0)
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00002015 return -1;
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00002016 if (upeek(tcp, PT_CR_IIP, &addr) < 0)
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00002017 return -1;
2018
2019 /* restore original bundle: */
Denys Vlasenko4dedd562009-02-24 15:17:53 +00002020 if (do_ptrace(PTRACE_POKETEXT, tcp, (char *) addr + 0, tcp->inst[0]) < 0
2021 || do_ptrace(PTRACE_POKETEXT, tcp, (char *) addr + 8, tcp->inst[1]) < 0
2022 ) {
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00002023 return -1;
2024 }
2025
2026 /* restore original "ri" in ipsr: */
2027 ipsr = (ipsr & ~(0x3ul << 41)) | ((tcp->baddr & 0x3) << 41);
Denys Vlasenko4dedd562009-02-24 15:17:53 +00002028 if (do_ptrace(PTRACE_POKEUSER, tcp, (char *) PT_CR_IPSR, ipsr) < 0) {
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00002029 return -1;
2030 }
2031
2032 tcp->flags &= ~TCB_BPTSET;
2033
2034 if (addr != (tcp->baddr & ~0x3)) {
2035 /* the breakpoint has not been reached yet. */
2036 if (debug)
2037 fprintf(stderr, "NOTE: PC not at bpt (pc %#lx baddr %#lx)\n",
2038 addr, tcp->baddr);
2039 return 0;
2040 }
2041 }
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00002042# else /* !IA64 && !SPARC && !SPARC64 */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002043
2044 if (debug)
2045 fprintf(stderr, "[%d] clearing bpt\n", tcp->pid);
2046 if (!(tcp->flags & TCB_BPTSET)) {
2047 fprintf(stderr, "PANIC: TCB not set in pid %u\n", tcp->pid);
2048 return -1;
2049 }
Denys Vlasenko4dedd562009-02-24 15:17:53 +00002050 if (do_ptrace(PTRACE_POKETEXT, tcp, (char *) tcp->baddr, tcp->inst[0]) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002051 return -1;
2052 }
2053 tcp->flags &= ~TCB_BPTSET;
2054
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00002055# ifdef I386
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00002056 if (upeek(tcp, 4*EIP, &eip) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002057 return -1;
2058 if (eip != tcp->baddr) {
2059 /* The breakpoint has not been reached yet. */
2060 if (debug)
2061 fprintf(stderr,
2062 "NOTE: PC not at bpt (pc %#lx baddr %#lx)\n",
2063 eip, tcp->baddr);
2064 return 0;
2065 }
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00002066# elif defined(X86_64)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00002067 if (upeek(tcp, 8*RIP, &eip) < 0)
Michal Ludvig0e035502002-09-23 15:41:01 +00002068 return -1;
2069 if (eip != tcp->baddr) {
2070 /* The breakpoint has not been reached yet. */
2071 if (debug)
2072 fprintf(stderr,
2073 "NOTE: PC not at bpt (pc %#lx baddr %#lx)\n",
2074 eip, tcp->baddr);
2075 return 0;
2076 }
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00002077# elif defined(POWERPC)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00002078 if (upeek(tcp, sizeof(unsigned long)*PT_NIP, &pc) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002079 return -1;
2080 if (pc != tcp->baddr) {
2081 /* The breakpoint has not been reached yet. */
2082 if (debug)
2083 fprintf(stderr, "NOTE: PC not at bpt (pc %#lx baddr %#lx)\n",
2084 pc, tcp->baddr);
2085 return 0;
2086 }
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00002087# elif defined(M68K)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00002088 if (upeek(tcp, 4*PT_PC, &pc) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002089 return -1;
2090 if (pc != tcp->baddr) {
2091 /* The breakpoint has not been reached yet. */
2092 if (debug)
2093 fprintf(stderr, "NOTE: PC not at bpt (pc %#lx baddr %#lx)\n",
2094 pc, tcp->baddr);
2095 return 0;
2096 }
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00002097# elif defined(ALPHA)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00002098 if (upeek(tcp, REG_PC, &pc) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002099 return -1;
2100 if (pc != tcp->baddr) {
2101 /* The breakpoint has not been reached yet. */
2102 if (debug)
2103 fprintf(stderr, "NOTE: PC not at bpt (pc %#lx baddr %#lx)\n",
2104 pc, tcp->baddr);
2105 return 0;
2106 }
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00002107# elif defined(HPPA)
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00002108 if (upeek(tcp, PT_IAOQ0, &iaoq) < 0)
Wichert Akkermanc1652e22001-03-27 12:17:16 +00002109 return -1;
2110 iaoq &= ~0x03;
2111 if (iaoq != tcp->baddr && iaoq != tcp->baddr + 4) {
2112 /* The breakpoint has not been reached yet. */
2113 if (debug)
2114 fprintf(stderr, "NOTE: PC not at bpt (iaoq %#lx baddr %#lx)\n",
2115 iaoq, tcp->baddr);
2116 return 0;
2117 }
2118 iaoq = tcp->baddr | 3;
2119 /* We should be pointing at a 'ldi -1000,r1' in glibc, so it is
2120 * safe to set both IAOQ0 and IAOQ1 to that so the PSW N bit
2121 * has no significant effect.
2122 */
Denys Vlasenko4dedd562009-02-24 15:17:53 +00002123 if (do_ptrace(PTRACE_POKEUSER, tcp, (void *)PT_IAOQ0, iaoq) < 0
2124 || do_ptrace(PTRACE_POKEUSER, tcp, (void *)PT_IAOQ1, iaoq) < 0
2125 ) {
2126 return -1;
2127 }
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00002128# elif defined(SH)
Denys Vlasenkoadedb512008-12-30 18:47:55 +00002129 if (upeek(tcp, 4*REG_PC, &pc) < 0)
2130 return -1;
2131 if (pc != tcp->baddr) {
2132 /* The breakpoint has not been reached yet. */
2133 if (debug)
2134 fprintf(stderr, "NOTE: PC not at bpt (pc %#lx baddr %#lx)\n",
2135 pc, tcp->baddr);
2136 return 0;
2137 }
Wichert Akkermanccef6372002-05-01 16:39:22 +00002138
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00002139# endif /* arch */
2140# endif /* !SPARC && !SPARC64 && !IA64 */
2141# endif /* LINUX */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002142
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00002143# ifdef SUNOS4
2144# ifdef SPARC
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002145
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00002146# if !LOOPA
Wichert Akkermane6f876c1999-06-22 15:28:30 +00002147 struct regs regs;
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00002148# endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002149
2150 if (!(tcp->flags & TCB_BPTSET)) {
2151 fprintf(stderr, "PANIC: TCB not set in pid %u\n", tcp->pid);
2152 return -1;
2153 }
Denys Vlasenko4dedd562009-02-24 15:17:53 +00002154 if (do_ptrace5(PTRACE_WRITETEXT, tcp, (char *) tcp->baddr,
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002155 sizeof tcp->inst, (char *) tcp->inst) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002156 return -1;
2157 }
2158 tcp->flags &= ~TCB_BPTSET;
2159
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00002160# if !LOOPA
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002161 /*
2162 * Since we don't have a single instruction breakpoint, we may have
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00002163 * to adjust the program counter after removing our `breakpoint'.
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002164 */
Denys Vlasenko4dedd562009-02-24 15:17:53 +00002165 if (do_ptrace(PTRACE_GETREGS, tcp, (char *)&regs, 0) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002166 return -1;
2167 }
Denys Vlasenko4dedd562009-02-24 15:17:53 +00002168 if ((regs.r_pc < tcp->baddr) || (regs.r_pc > tcp->baddr + 4)) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002169 /* The breakpoint has not been reached yet */
2170 if (debug)
2171 fprintf(stderr,
2172 "NOTE: PC not at bpt (pc %#x baddr %#x)\n",
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00002173 regs.r_pc, tcp->baddr);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002174 return 0;
2175 }
2176 if (regs.r_pc != tcp->baddr)
2177 if (debug)
2178 fprintf(stderr, "NOTE: PC adjusted (%#x -> %#x\n",
2179 regs.r_pc, tcp->baddr);
2180
2181 regs.r_pc = tcp->baddr;
Denys Vlasenko4dedd562009-02-24 15:17:53 +00002182 if (do_ptrace(PTRACE_SETREGS, tcp, (char *)&regs, 0) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002183 return -1;
2184 }
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00002185# endif /* LOOPA */
2186# endif /* SPARC */
2187# endif /* SUNOS4 */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002188
2189 return 0;
2190}
2191
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00002192# endif /* !defined LINUX */
Roland McGrathd81f1d92003-01-09 06:53:34 +00002193
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00002194#endif /* !USE_PROCFS */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002195
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00002196
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002197#ifdef SUNOS4
2198
2199static int
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00002200getex(tcp, hdr)
2201struct tcb *tcp;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002202struct exec *hdr;
2203{
2204 int n;
2205
2206 for (n = 0; n < sizeof *hdr; n += 4) {
2207 long res;
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00002208 if (upeek(tcp, uoff(u_exdata) + n, &res) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002209 return -1;
2210 memcpy(((char *) hdr) + n, &res, 4);
2211 }
2212 if (debug) {
2213 fprintf(stderr, "[struct exec: magic: %o version %u Mach %o\n",
2214 hdr->a_magic, hdr->a_toolversion, hdr->a_machtype);
2215 fprintf(stderr, "Text %lu Data %lu Bss %lu Syms %lu Entry %#lx]\n",
2216 hdr->a_text, hdr->a_data, hdr->a_bss, hdr->a_syms, hdr->a_entry);
2217 }
2218 return 0;
2219}
2220
2221int
2222fixvfork(tcp)
2223struct tcb *tcp;
2224{
2225 int pid = tcp->pid;
2226 /*
2227 * Change `vfork' in a freshly exec'ed dynamically linked
2228 * executable's (internal) symbol table to plain old `fork'
2229 */
2230
2231 struct exec hdr;
2232 struct link_dynamic dyn;
2233 struct link_dynamic_2 ld;
2234 char *strtab, *cp;
2235
Denys Vlasenko932fc7d2008-12-16 18:18:40 +00002236 if (getex(tcp, &hdr) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002237 return -1;
2238 if (!hdr.a_dynamic)
2239 return -1;
2240
2241 if (umove(tcp, (int) N_DATADDR(hdr), &dyn) < 0) {
2242 fprintf(stderr, "Cannot read DYNAMIC\n");
2243 return -1;
2244 }
2245 if (umove(tcp, (int) dyn.ld_un.ld_2, &ld) < 0) {
2246 fprintf(stderr, "Cannot read link_dynamic_2\n");
2247 return -1;
2248 }
2249 if ((strtab = malloc((unsigned)ld.ld_symb_size)) == NULL) {
Roland McGrath46100d02005-06-01 18:55:42 +00002250 fprintf(stderr, "out of memory\n");
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002251 return -1;
2252 }
Denys Vlasenko4dedd562009-02-24 15:17:53 +00002253 if (umoven(tcp, (int)ld.ld_symbols + (int)N_TXTADDR(hdr),
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002254 (int)ld.ld_symb_size, strtab) < 0)
2255 goto err;
2256
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00002257# if 0
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002258 for (cp = strtab; cp < strtab + ld.ld_symb_size; ) {
2259 fprintf(stderr, "[symbol: %s]\n", cp);
2260 cp += strlen(cp)+1;
2261 }
2262 return 0;
Denys Vlasenko3bb7cd62009-02-09 18:55:59 +00002263# endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002264 for (cp = strtab; cp < strtab + ld.ld_symb_size; ) {
2265 if (strcmp(cp, "_vfork") == 0) {
2266 if (debug)
2267 fprintf(stderr, "fixvfork: FOUND _vfork\n");
2268 strcpy(cp, "_fork");
2269 break;
2270 }
2271 cp += strlen(cp)+1;
2272 }
2273 if (cp < strtab + ld.ld_symb_size)
2274 /*
2275 * Write entire symbol table back to avoid
2276 * memory alignment bugs in ptrace
2277 */
Denys Vlasenko4dedd562009-02-24 15:17:53 +00002278 if (tload(tcp, (int)ld.ld_symbols + (int)N_TXTADDR(hdr),
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00002279 (int)ld.ld_symb_size, strtab) < 0)
2280 goto err;
2281
2282 free(strtab);
2283 return 0;
2284
2285err:
2286 free(strtab);
2287 return -1;
2288}
2289
2290#endif /* SUNOS4 */