blob: 4663bc9c8435d3fc6aa7a40a49afc57a9f81fa37 [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
66#include <linux/ptrace.h>
Wichert Akkerman2e2553a1999-05-09 00:29:58 +000067#endif
68
Wichert Akkerman76baf7c1999-02-19 00:21:36 +000069#ifdef SUNOS4_KERNEL_ARCH_KLUDGE
70#include <sys/utsname.h>
71#endif /* SUNOS4_KERNEL_ARCH_KLUDGE */
72
Wichert Akkerman9ce1a631999-08-29 23:15:07 +000073#if defined(LINUX) && defined(SPARC)
74
Roland McGrath4db26242003-01-30 20:15:19 +000075# define fpq kernel_fpq
76# define fq kernel_fq
77# define fpu kernel_fpu
78# include <asm/reg.h>
79# undef fpq
80# undef fq
81# undef fpu
Wichert Akkerman9ce1a631999-08-29 23:15:07 +000082
83#if !defined(__GLIBC__)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +000084
85#include <linux/unistd.h>
86
87#define _hack_syscall5(type,name,type1,arg1,type2,arg2,type3,arg3,type4,arg4,\
88 type5,arg5,syscall) \
89type name (type1 arg1,type2 arg2,type3 arg3,type4 arg4,type5 arg5) \
90{ \
91 long __res; \
92\
93__asm__ volatile ("or %%g0, %1, %%o0\n\t" \
94 "or %%g0, %2, %%o1\n\t" \
95 "or %%g0, %3, %%o2\n\t" \
96 "or %%g0, %4, %%o3\n\t" \
97 "or %%g0, %5, %%o4\n\t" \
98 "or %%g0, %6, %%g1\n\t" \
99 "t 0x10\n\t" \
100 "bcc 1f\n\t" \
101 "or %%g0, %%o0, %0\n\t" \
102 "sub %%g0, %%o0, %0\n\t" \
103 "1:\n\t" \
104 : "=r" (__res) \
105 : "0" ((long)(arg1)),"1" ((long)(arg2)), \
106 "2" ((long)(arg3)),"3" ((long)(arg4)),"4" ((long)(arg5)), \
107 "i" (__NR_##syscall) \
108 : "g1", "o0", "o1", "o2", "o3", "o4"); \
109if (__res>=0) \
110 return (type) __res; \
111errno = -__res; \
112return -1; \
113}
114
115static _hack_syscall5(int,_ptrace,int,__request,int,__pid,int,__addr,int,__data,int,__addr2,ptrace)
116
117#define _ptrace
118
119#endif
120
Wichert Akkerman9ce1a631999-08-29 23:15:07 +0000121#endif
122
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000123/* macros */
124#ifndef MAX
125#define MAX(a,b) (((a) > (b)) ? (a) : (b))
126#endif
127#ifndef MIN
128#define MIN(a,b) (((a) < (b)) ? (a) : (b))
129#endif
130
131void
132tv_tv(tv, a, b)
133struct timeval *tv;
134int a;
135int b;
136{
137 tv->tv_sec = a;
138 tv->tv_usec = b;
139}
140
141int
142tv_nz(a)
143struct timeval *a;
144{
145 return a->tv_sec || a->tv_usec;
146}
147
148int
149tv_cmp(a, b)
150struct timeval *a, *b;
151{
152 if (a->tv_sec < b->tv_sec
153 || (a->tv_sec == b->tv_sec && a->tv_usec < b->tv_usec))
154 return -1;
155 if (a->tv_sec > b->tv_sec
156 || (a->tv_sec == b->tv_sec && a->tv_usec > b->tv_usec))
157 return 1;
158 return 0;
159}
160
161double
162tv_float(tv)
163struct timeval *tv;
164{
165 return tv->tv_sec + tv->tv_usec/1000000.0;
166}
167
168void
169tv_add(tv, a, b)
170struct timeval *tv, *a, *b;
171{
172 tv->tv_sec = a->tv_sec + b->tv_sec;
173 tv->tv_usec = a->tv_usec + b->tv_usec;
174 if (tv->tv_usec > 1000000) {
175 tv->tv_sec++;
176 tv->tv_usec -= 1000000;
177 }
178}
179
180void
181tv_sub(tv, a, b)
182struct timeval *tv, *a, *b;
183{
184 tv->tv_sec = a->tv_sec - b->tv_sec;
185 tv->tv_usec = a->tv_usec - b->tv_usec;
186 if (((long) tv->tv_usec) < 0) {
187 tv->tv_sec--;
188 tv->tv_usec += 1000000;
189 }
190}
191
192void
193tv_div(tv, a, n)
194struct timeval *tv, *a;
195int n;
196{
197 tv->tv_usec = (a->tv_sec % n * 1000000 + a->tv_usec + n / 2) / n;
198 tv->tv_sec = a->tv_sec / n + tv->tv_usec / 1000000;
199 tv->tv_usec %= 1000000;
200}
201
202void
203tv_mul(tv, a, n)
204struct timeval *tv, *a;
205int n;
206{
207 tv->tv_usec = a->tv_usec * n;
208 tv->tv_sec = a->tv_sec * n + a->tv_usec / 1000000;
209 tv->tv_usec %= 1000000;
210}
211
212char *
213xlookup(xlat, val)
214struct xlat *xlat;
215int val;
216{
217 for (; xlat->str != NULL; xlat++)
218 if (xlat->val == val)
219 return xlat->str;
220 return NULL;
221}
222
223/*
224 * Print entry in struct xlat table, if there.
225 */
226void
227printxval(xlat, val, dflt)
228struct xlat *xlat;
229int val;
230char *dflt;
231{
232 char *str = xlookup(xlat, val);
233
234 if (str)
235 tprintf("%s", str);
236 else
237 tprintf("%#x /* %s */", val, dflt);
238}
239
240/*
241 * Interpret `xlat' as an array of flags
242 * print the entries whose bits are on in `flags'
243 * return # of flags printed.
244 */
245int
246addflags(xlat, flags)
247struct xlat *xlat;
248int flags;
249{
250 int n;
251
252 for (n = 0; xlat->str; xlat++) {
253 if (xlat->val && (flags & xlat->val) == xlat->val) {
254 tprintf("|%s", xlat->str);
255 flags &= ~xlat->val;
256 n++;
257 }
258 }
259 if (flags) {
260 tprintf("|%#x", flags);
261 n++;
262 }
263 return n;
264}
265
266int
267printflags(xlat, flags)
268struct xlat *xlat;
269int flags;
270{
271 int n;
272 char *sep;
273
274 if (flags == 0 && xlat->val == 0) {
275 tprintf("%s", xlat->str);
276 return 1;
277 }
278
279 sep = "";
280 for (n = 0; xlat->str; xlat++) {
281 if (xlat->val && (flags & xlat->val) == xlat->val) {
282 tprintf("%s%s", sep, xlat->str);
283 flags &= ~xlat->val;
284 sep = "|";
285 n++;
286 }
287 }
288 if (flags) {
289 tprintf("%s%#x", sep, flags);
290 n++;
291 }
292 return n;
293}
294
295void
296printnum(tcp, addr, fmt)
297struct tcb *tcp;
298long addr;
299char *fmt;
300{
Roland McGratheb285352003-01-14 09:59:00 +0000301 long num;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000302
303 if (!addr) {
304 tprintf("NULL");
305 return;
306 }
307 if (umove(tcp, addr, &num) < 0) {
308 tprintf("%#lx", addr);
309 return;
310 }
311 tprintf("[");
312 tprintf(fmt, num);
313 tprintf("]");
314}
315
Roland McGrath6bc12202003-11-13 22:32:27 +0000316void
317printuid(text, uid)
318const char *text;
319unsigned long uid;
320{
321 tprintf("%s", text);
322 tprintf((uid == -1) ? "%ld" : "%lu", uid);
323}
324
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000325static char path[MAXPATHLEN + 1];
326
327void
328string_quote(str)
329char *str;
330{
331 char buf[2 * MAXPATHLEN + 1];
332 char *s;
333
334 if (!strpbrk(str, "\"\'\\")) {
335 tprintf("\"%s\"", str);
336 return;
337 }
338 for (s = buf; *str; str++) {
339 switch (*str) {
340 case '\"': case '\'': case '\\':
341 *s++ = '\\'; *s++ = *str; break;
342 default:
343 *s++ = *str; break;
344 }
345 }
346 *s = '\0';
347 tprintf("\"%s\"", buf);
348}
349
350void
351printpath(tcp, addr)
352struct tcb *tcp;
353long addr;
354{
355 if (umovestr(tcp, addr, MAXPATHLEN, path) < 0)
356 tprintf("%#lx", addr);
357 else
358 string_quote(path);
359 return;
360}
361
362void
363printpathn(tcp, addr, n)
364struct tcb *tcp;
365long addr;
366int n;
367{
368 if (umovestr(tcp, addr, n, path) < 0)
369 tprintf("%#lx", addr);
370 else {
371 path[n] = '\0';
372 string_quote(path);
373 }
374}
375
376void
377printstr(tcp, addr, len)
378struct tcb *tcp;
379long addr;
380int len;
381{
382 static unsigned char *str = NULL;
383 static char *outstr;
384 int i, n, c, usehex;
385 char *s, *outend;
386
387 if (!addr) {
388 tprintf("NULL");
389 return;
390 }
391 if (!str) {
392 if ((str = malloc(max_strlen)) == NULL
393 || (outstr = malloc(2*max_strlen)) == NULL) {
394 fprintf(stderr, "printstr: no memory\n");
395 tprintf("%#lx", addr);
396 return;
397 }
398 }
Wichert Akkerman2e2553a1999-05-09 00:29:58 +0000399 outend = outstr + max_strlen * 2 - 10;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000400 if (len < 0) {
401 n = max_strlen;
402 if (umovestr(tcp, addr, n, (char *) str) < 0) {
403 tprintf("%#lx", addr);
404 return;
405 }
406 }
407 else {
408 n = MIN(len, max_strlen);
409 if (umoven(tcp, addr, n, (char *) str) < 0) {
410 tprintf("%#lx", addr);
411 return;
412 }
413 }
414
415 usehex = 0;
416 if (xflag > 1)
417 usehex = 1;
418 else if (xflag) {
419 for (i = 0; i < n; i++) {
420 c = str[i];
421 if (len < 0 && c == '\0')
422 break;
423 if (!isprint(c) && !isspace(c)) {
424 usehex = 1;
425 break;
426 }
427 }
428 }
429
430 s = outstr;
431 *s++ = '\"';
432
433 if (usehex) {
434 for (i = 0; i < n; i++) {
435 c = str[i];
436 if (len < 0 && c == '\0')
437 break;
438 sprintf(s, "\\x%02x", c);
439 s += 4;
440 if (s > outend)
441 break;
442 }
443 }
444 else {
445 for (i = 0; i < n; i++) {
446 c = str[i];
447 if (len < 0 && c == '\0')
448 break;
449 switch (c) {
450 case '\"': case '\'': case '\\':
451 *s++ = '\\'; *s++ = c; break;
452 case '\f':
453 *s++ = '\\'; *s++ = 'f'; break;
454 case '\n':
455 *s++ = '\\'; *s++ = 'n'; break;
456 case '\r':
457 *s++ = '\\'; *s++ = 'r'; break;
458 case '\t':
459 *s++ = '\\'; *s++ = 't'; break;
460 case '\v':
461 *s++ = '\\'; *s++ = 'v'; break;
462 default:
463 if (isprint(c))
464 *s++ = c;
465 else if (i < n - 1 && isdigit(str[i + 1])) {
466 sprintf(s, "\\%03o", c);
467 s += 4;
468 }
469 else {
470 sprintf(s, "\\%o", c);
471 s += strlen(s);
472 }
473 break;
474 }
475 if (s > outend)
476 break;
477 }
478 }
479
480 *s++ = '\"';
481 if (i < len || (len < 0 && (i == n || s > outend))) {
482 *s++ = '.'; *s++ = '.'; *s++ = '.';
483 }
484 *s = '\0';
485 tprintf("%s", outstr);
486}
487
John Hughes1d08dcf2001-07-10 13:48:44 +0000488#if HAVE_SYS_UIO_H
489void
490dumpiov(tcp, len, addr)
491struct tcb * tcp;
492int len;
493long addr;
494{
495 struct iovec *iov;
496 int i;
497
Roland McGrath1e85cf92002-12-16 20:40:54 +0000498
John Hughes1d08dcf2001-07-10 13:48:44 +0000499 if ((iov = (struct iovec *) malloc(len * sizeof *iov)) == NULL) {
500 fprintf(stderr, "dump: No memory");
501 return;
502 }
503 if (umoven(tcp, addr,
504 len * sizeof *iov, (char *) iov) >= 0) {
Roland McGrath1e85cf92002-12-16 20:40:54 +0000505
John Hughes1d08dcf2001-07-10 13:48:44 +0000506 for (i = 0; i < len; i++) {
507 /* include the buffer number to make it easy to
508 * match up the trace with the source */
509 tprintf(" * %lu bytes in buffer %d\n",
510 (unsigned long)iov[i].iov_len, i);
511 dumpstr(tcp, (long) iov[i].iov_base,
512 iov[i].iov_len);
513 }
514 }
515 free((char *) iov);
Roland McGrath1e85cf92002-12-16 20:40:54 +0000516
John Hughes1d08dcf2001-07-10 13:48:44 +0000517}
518#endif
519
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000520void
521dumpstr(tcp, addr, len)
522struct tcb *tcp;
523long addr;
524int len;
525{
526 static int strsize = -1;
527 static unsigned char *str;
528 static char outstr[80];
529 char *s;
530 int i, j;
531
532 if (strsize < len) {
533 if (str)
534 free(str);
535 if ((str = malloc(len)) == NULL) {
536 fprintf(stderr, "dump: no memory\n");
537 return;
538 }
539 strsize = len;
540 }
541
542 if (umoven(tcp, addr, len, (char *) str) < 0)
543 return;
544
545 for (i = 0; i < len; i += 16) {
546 s = outstr;
547 sprintf(s, " | %05x ", i);
548 s += 9;
549 for (j = 0; j < 16; j++) {
550 if (j == 8)
551 *s++ = ' ';
552 if (i + j < len) {
553 sprintf(s, " %02x", str[i + j]);
554 s += 3;
555 }
556 else {
557 *s++ = ' '; *s++ = ' '; *s++ = ' ';
558 }
559 }
560 *s++ = ' '; *s++ = ' ';
561 for (j = 0; j < 16; j++) {
562 if (j == 8)
563 *s++ = ' ';
564 if (i + j < len) {
565 if (isprint(str[i + j]))
566 *s++ = str[i + j];
567 else
568 *s++ = '.';
569 }
570 else
571 *s++ = ' ';
572 }
573 tprintf("%s |\n", outstr);
574 }
575}
576
577#define PAGMASK (~(PAGSIZ - 1))
578/*
579 * move `len' bytes of data from process `pid'
580 * at address `addr' to our space at `laddr'
581 */
582int
583umoven(tcp, addr, len, laddr)
584struct tcb *tcp;
585long addr;
586int len;
587char *laddr;
588{
589
590#ifdef LINUX
591 int pid = tcp->pid;
592 int n, m;
Wichert Akkerman5daa0281999-03-15 19:49:42 +0000593 int started = 0;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000594 union {
595 long val;
596 char x[sizeof(long)];
597 } u;
598
599 if (addr & (sizeof(long) - 1)) {
600 /* addr not a multiple of sizeof(long) */
601 n = addr - (addr & -sizeof(long)); /* residue */
602 addr &= -sizeof(long); /* residue */
603 errno = 0;
604 u.val = ptrace(PTRACE_PEEKDATA, pid, (char *) addr, 0);
605 if (errno) {
Wichert Akkerman5daa0281999-03-15 19:49:42 +0000606 if (started && (errno==EPERM || errno==EIO)) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000607 /* Ran into 'end of memory' - stupid "printpath" */
608 return 0;
609 }
Wichert Akkerman5daa0281999-03-15 19:49:42 +0000610 /* But if not started, we had a bogus address. */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000611 perror("ptrace: umoven");
612 return -1;
613 }
Wichert Akkerman5daa0281999-03-15 19:49:42 +0000614 started = 1;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000615 memcpy(laddr, &u.x[n], m = MIN(sizeof(long) - n, len));
616 addr += sizeof(long), laddr += m, len -= m;
617 }
618 while (len) {
619 errno = 0;
620 u.val = ptrace(PTRACE_PEEKDATA, pid, (char *) addr, 0);
621 if (errno) {
Wichert Akkerman5daa0281999-03-15 19:49:42 +0000622 if (started && (errno==EPERM || errno==EIO)) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000623 /* Ran into 'end of memory' - stupid "printpath" */
624 return 0;
625 }
Roland McGrath4db26242003-01-30 20:15:19 +0000626 if (addr != 0)
627 perror("ptrace: umoven");
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000628 return -1;
629 }
Wichert Akkerman5daa0281999-03-15 19:49:42 +0000630 started = 1;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000631 memcpy(laddr, u.x, m = MIN(sizeof(long), len));
632 addr += sizeof(long), laddr += m, len -= m;
633 }
634#endif /* LINUX */
635
636#ifdef SUNOS4
637 int pid = tcp->pid;
638#if 0
639 int n, m;
640 union {
641 long val;
642 char x[sizeof(long)];
643 } u;
644
645 if (addr & (sizeof(long) - 1)) {
646 /* addr not a multiple of sizeof(long) */
647 n = addr - (addr & -sizeof(long)); /* residue */
648 addr &= -sizeof(long); /* residue */
649 errno = 0;
650 u.val = ptrace(PTRACE_PEEKDATA, pid, (char *) addr, 0);
651 if (errno) {
652 perror("umoven");
653 return -1;
654 }
655 memcpy(laddr, &u.x[n], m = MIN(sizeof(long) - n, len));
656 addr += sizeof(long), laddr += m, len -= m;
657 }
658 while (len) {
659 errno = 0;
660 u.val = ptrace(PTRACE_PEEKDATA, pid, (char *) addr, 0);
661 if (errno) {
662 perror("umoven");
663 return -1;
664 }
665 memcpy(laddr, u.x, m = MIN(sizeof(long), len));
666 addr += sizeof(long), laddr += m, len -= m;
667 }
668#else /* !oldway */
669 int n;
670
671 while (len) {
672 n = MIN(len, PAGSIZ);
673 n = MIN(n, ((addr + PAGSIZ) & PAGMASK) - addr);
674 if (ptrace(PTRACE_READDATA, pid,
675 (char *) addr, len, laddr) < 0) {
676 perror("umoven: ptrace(PTRACE_READDATA, ...)");
677 abort();
678 return -1;
679 }
680 len -= n;
681 addr += n;
682 laddr += n;
683 }
684#endif /* !oldway */
685#endif /* SUNOS4 */
686
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000687#ifdef USE_PROCFS
Wichert Akkermanea78f0f1999-11-29 15:34:02 +0000688#ifdef HAVE_MP_PROCFS
John Hughesaa09c6b2001-05-15 14:53:43 +0000689 int fd = tcp->pfd_as;
Wichert Akkerman9ce1a631999-08-29 23:15:07 +0000690#else
John Hughesaa09c6b2001-05-15 14:53:43 +0000691 int fd = tcp->pfd;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000692#endif
John Hughesaa09c6b2001-05-15 14:53:43 +0000693 lseek(fd, addr, SEEK_SET);
694 if (read(fd, laddr, len) == -1)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000695 return -1;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000696#endif /* USE_PROCFS */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000697
698 return 0;
699}
700
701/*
702 * like `umove' but make the additional effort of looking
703 * for a terminating zero byte.
704 */
705int
706umovestr(tcp, addr, len, laddr)
707struct tcb *tcp;
708long addr;
709int len;
710char *laddr;
711{
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000712#ifdef USE_PROCFS
John Hughesaa09c6b2001-05-15 14:53:43 +0000713#ifdef HAVE_MP_PROCFS
714 int fd = tcp->pfd_as;
715#else
716 int fd = tcp->pfd;
717#endif
718 /* Some systems (e.g. FreeBSD) can be upset if we read off the
719 end of valid memory, avoid this by trying to read up
720 to page boundaries. But we don't know what a page is (and
721 getpagesize(2) (if it exists) doesn't necessarily return
722 hardware page size). Assume all pages >= 1024 (a-historical
723 I know) */
724
725 int page = 1024; /* How to find this? */
726 int move = page - (addr & (page - 1));
727 int left = len;
728
729 lseek(fd, addr, SEEK_SET);
730
731 while (left) {
732 if (move > left) move = left;
John Hughes9cecf7f2001-10-16 10:20:22 +0000733 if ((move = read(fd, laddr, move)) <= 0)
John Hughesaa09c6b2001-05-15 14:53:43 +0000734 return left != len ? 0 : -1;
735 if (memchr (laddr, 0, move)) break;
736 left -= move;
737 laddr += move;
738 addr += move;
739 move = page;
740 }
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000741#else /* !USE_PROCFS */
Wichert Akkerman5daa0281999-03-15 19:49:42 +0000742 int started = 0;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000743 int pid = tcp->pid;
744 int i, n, m;
745 union {
746 long val;
747 char x[sizeof(long)];
748 } u;
749
750 if (addr & (sizeof(long) - 1)) {
751 /* addr not a multiple of sizeof(long) */
752 n = addr - (addr & -sizeof(long)); /* residue */
753 addr &= -sizeof(long); /* residue */
754 errno = 0;
755 u.val = ptrace(PTRACE_PEEKDATA, pid, (char *)addr, 0);
756 if (errno) {
Wichert Akkerman5daa0281999-03-15 19:49:42 +0000757 if (started && (errno==EPERM || errno==EIO)) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000758 /* Ran into 'end of memory' - stupid "printpath" */
759 return 0;
760 }
761 perror("umovestr");
762 return -1;
763 }
Wichert Akkerman5daa0281999-03-15 19:49:42 +0000764 started = 1;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000765 memcpy(laddr, &u.x[n], m = MIN(sizeof(long)-n,len));
766 while (n & (sizeof(long) - 1))
767 if (u.x[n++] == '\0')
768 return 0;
769 addr += sizeof(long), laddr += m, len -= m;
770 }
771 while (len) {
772 errno = 0;
773 u.val = ptrace(PTRACE_PEEKDATA, pid, (char *)addr, 0);
774 if (errno) {
Wichert Akkerman5daa0281999-03-15 19:49:42 +0000775 if (started && (errno==EPERM || errno==EIO)) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000776 /* Ran into 'end of memory' - stupid "printpath" */
777 return 0;
778 }
779 perror("umovestr");
780 return -1;
781 }
Wichert Akkerman5daa0281999-03-15 19:49:42 +0000782 started = 1;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000783 memcpy(laddr, u.x, m = MIN(sizeof(long), len));
784 for (i = 0; i < sizeof(long); i++)
785 if (u.x[i] == '\0')
786 return 0;
787
788 addr += sizeof(long), laddr += m, len -= m;
789 }
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000790#endif /* !USE_PROCFS */
John Hughesaa09c6b2001-05-15 14:53:43 +0000791 return 0;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000792}
793
794#ifdef LINUX
795#ifndef SPARC
796#define PTRACE_WRITETEXT 101
797#define PTRACE_WRITEDATA 102
798#endif /* !SPARC */
799#endif /* LINUX */
800
801#ifdef SUNOS4
802
803static int
804uload(cmd, pid, addr, len, laddr)
805int cmd;
806int pid;
807long addr;
808int len;
809char *laddr;
810{
811#if 0
812 int n;
813
814 while (len) {
815 n = MIN(len, PAGSIZ);
816 n = MIN(n, ((addr + PAGSIZ) & PAGMASK) - addr);
817 if (ptrace(cmd, pid, (char *)addr, n, laddr) < 0) {
818 perror("uload: ptrace(PTRACE_WRITE, ...)");
819 return -1;
820 }
821 len -= n;
822 addr += n;
823 laddr += n;
824 }
825#else
826 int peek, poke;
827 int n, m;
828 union {
829 long val;
830 char x[sizeof(long)];
831 } u;
832
833 if (cmd == PTRACE_WRITETEXT) {
834 peek = PTRACE_PEEKTEXT;
835 poke = PTRACE_POKETEXT;
836 }
837 else {
838 peek = PTRACE_PEEKDATA;
839 poke = PTRACE_POKEDATA;
840 }
841 if (addr & (sizeof(long) - 1)) {
842 /* addr not a multiple of sizeof(long) */
843 n = addr - (addr & -sizeof(long)); /* residue */
844 addr &= -sizeof(long);
845 errno = 0;
846 u.val = ptrace(peek, pid, (char *) addr, 0);
847 if (errno) {
848 perror("uload: POKE");
849 return -1;
850 }
851 memcpy(&u.x[n], laddr, m = MIN(sizeof(long) - n, len));
852 if (ptrace(poke, pid, (char *)addr, u.val) < 0) {
853 perror("uload: POKE");
854 return -1;
855 }
856 addr += sizeof(long), laddr += m, len -= m;
857 }
858 while (len) {
859 if (len < sizeof(long))
860 u.val = ptrace(peek, pid, (char *) addr, 0);
861 memcpy(u.x, laddr, m = MIN(sizeof(long), len));
862 if (ptrace(poke, pid, (char *) addr, u.val) < 0) {
863 perror("uload: POKE");
864 return -1;
865 }
866 addr += sizeof(long), laddr += m, len -= m;
867 }
868#endif
869 return 0;
870}
871
872int
873tload(pid, addr, len, laddr)
874int pid;
875int addr, len;
876char *laddr;
877{
878 return uload(PTRACE_WRITETEXT, pid, addr, len, laddr);
879}
880
881int
882dload(pid, addr, len, laddr)
883int pid;
884int addr;
885int len;
886char *laddr;
887{
888 return uload(PTRACE_WRITEDATA, pid, addr, len, laddr);
889}
890
891#endif /* SUNOS4 */
892
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000893#ifndef USE_PROCFS
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000894
895int
896upeek(pid, off, res)
897int pid;
898long off;
899long *res;
900{
901 long val;
902
903#ifdef SUNOS4_KERNEL_ARCH_KLUDGE
904 {
905 static int is_sun4m = -1;
906 struct utsname name;
907
908 /* Round up the usual suspects. */
909 if (is_sun4m == -1) {
910 if (uname(&name) < 0) {
911 perror("upeek: uname?");
912 exit(1);
913 }
914 is_sun4m = strcmp(name.machine, "sun4m") == 0;
915 if (is_sun4m) {
916 extern struct xlat struct_user_offsets[];
917 struct xlat *x;
918
919 for (x = struct_user_offsets; x->str; x++)
920 x->val += 1024;
921 }
922 }
923 if (is_sun4m)
924 off += 1024;
925 }
926#endif /* SUNOS4_KERNEL_ARCH_KLUDGE */
927 errno = 0;
928 val = ptrace(PTRACE_PEEKUSER, pid, (char *) off, 0);
929 if (val == -1 && errno) {
Roland McGrath1e85cf92002-12-16 20:40:54 +0000930 char buf[60];
Michal Ludvig0e035502002-09-23 15:41:01 +0000931 sprintf(buf,"upeek: ptrace(PTRACE_PEEKUSER,%d,%lu,0)",pid,off);
Roland McGrath1e85cf92002-12-16 20:40:54 +0000932 perror(buf);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000933 return -1;
934 }
935 *res = val;
936 return 0;
937}
938
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000939#endif /* !USE_PROCFS */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000940
941long
942getpc(tcp)
943struct tcb *tcp;
944{
945
946#ifdef LINUX
947 long pc;
Wichert Akkermanf90da011999-10-31 21:15:38 +0000948#if defined(I386)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000949 if (upeek(tcp->pid, 4*EIP, &pc) < 0)
950 return -1;
Michal Ludvig0e035502002-09-23 15:41:01 +0000951#elif defined(X86_64)
952 if (upeek(tcp->pid, 8*RIP, &pc) < 0)
953 return -1;
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +0000954#elif defined(IA64)
955 if (upeek(tcp->pid, PT_B0, &pc) < 0)
956 return -1;
Wichert Akkermanf90da011999-10-31 21:15:38 +0000957#elif defined(ARM)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000958 if (upeek(tcp->pid, 4*15, &pc) < 0)
959 return -1;
Wichert Akkermanf90da011999-10-31 21:15:38 +0000960#elif defined(POWERPC)
Roland McGratheb285352003-01-14 09:59:00 +0000961 if (upeek(tcp->pid, sizeof(unsigned long)*PT_NIP, &pc) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000962 return -1;
Wichert Akkermanf90da011999-10-31 21:15:38 +0000963#elif defined(M68k)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000964 if (upeek(tcp->pid, 4*PT_PC, &pc) < 0)
965 return -1;
Wichert Akkermanf90da011999-10-31 21:15:38 +0000966#elif defined(ALPHA)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000967 if (upeek(tcp->pid, REG_PC, &pc) < 0)
968 return -1;
Wichert Akkermanf90da011999-10-31 21:15:38 +0000969#elif defined(MIPS)
970 if (upeek(tcp->pid, REG_EPC, &pc) < 0)
971 return -1;
972#elif defined(SPARC)
Wichert Akkerman9ce1a631999-08-29 23:15:07 +0000973 struct regs regs;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000974 if (ptrace(PTRACE_GETREGS,tcp->pid,(char *)&regs,0) < 0)
975 return -1;
Wichert Akkerman9ce1a631999-08-29 23:15:07 +0000976 pc = regs.r_pc;
Michal Ludvig10a88d02002-10-07 14:31:00 +0000977#elif defined(S390) || defined(S390X)
Wichert Akkerman4dc8a2a1999-12-23 14:20:14 +0000978 if(upeek(tcp->pid,PT_PSWADDR,&pc) < 0)
Michal Ludvig10a88d02002-10-07 14:31:00 +0000979 return -1;
Wichert Akkermanc1652e22001-03-27 12:17:16 +0000980#elif defined(HPPA)
981 if(upeek(tcp->pid,PT_IAOQ0,&pc) < 0)
982 return -1;
Wichert Akkermanccef6372002-05-01 16:39:22 +0000983#elif defined(SH)
984 if (upeek(tcp->pid, 4*REG_PC ,&pc) < 0)
985 return -1;
Roland McGrathf5a47772003-06-26 22:40:42 +0000986#elif defined(SH64)
Roland McGrathe1e584b2003-06-02 19:18:58 +0000987 if (upeek(tcp->pid, REG_PC ,&pc) < 0)
988 return -1;
Wichert Akkerman7a0b6491999-12-23 15:08:17 +0000989#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000990 return pc;
991#endif /* LINUX */
992
993#ifdef SUNOS4
994 /*
995 * Return current program counter for `pid'
996 * Assumes PC is never 0xffffffff
997 */
998 struct regs regs;
999
1000 if (ptrace(PTRACE_GETREGS, tcp->pid, (char *) &regs, 0) < 0) {
1001 perror("getpc: ptrace(PTRACE_GETREGS, ...)");
1002 return -1;
1003 }
1004 return regs.r_pc;
1005#endif /* SUNOS4 */
1006
1007#ifdef SVR4
1008 /* XXX */
1009 return 0;
1010#endif /* SVR4 */
1011
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001012#ifdef FREEBSD
1013 struct reg regs;
1014 pread(tcp->pfd_reg, &regs, sizeof(regs), 0);
1015 return regs.r_eip;
1016#endif /* FREEBSD */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001017}
1018
1019void
1020printcall(tcp)
1021struct tcb *tcp;
1022{
1023
1024#ifdef LINUX
1025#ifdef I386
1026 long eip;
1027
1028 if (upeek(tcp->pid, 4*EIP, &eip) < 0) {
1029 tprintf("[????????] ");
1030 return;
1031 }
1032 tprintf("[%08lx] ", eip);
Michal Ludvig0e035502002-09-23 15:41:01 +00001033#elif defined(X86_64)
1034 long rip;
1035
1036 if (upeek(tcp->pid, 8*RIP, &rip) < 0) {
1037 tprintf("[????????] ");
1038 return;
1039 }
1040 tprintf("[%16lx] ", rip);
Roland McGrathef388682003-06-03 23:28:59 +00001041#elif defined(IA64)
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00001042 long ip;
1043
1044 if (upeek(tcp->pid, PT_B0, &ip) < 0) {
1045 tprintf("[????????] ");
1046 return;
1047 }
1048 tprintf("[%08lx] ", ip);
Wichert Akkermanfaf72222000-02-19 23:59:03 +00001049#elif defined(POWERPC)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001050 long pc;
1051
Roland McGratheb285352003-01-14 09:59:00 +00001052 if (upeek(tcp->pid, sizeof(unsigned long)*PT_NIP, &pc) < 0) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001053 tprintf ("[????????] ");
1054 return;
1055 }
1056 tprintf("[%08lx] ", pc);
Wichert Akkermanfaf72222000-02-19 23:59:03 +00001057#elif defined(M68k)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001058 long pc;
1059
1060 if (upeek(tcp->pid, 4*PT_PC, &pc) < 0) {
1061 tprintf ("[????????] ");
1062 return;
1063 }
1064 tprintf("[%08lx] ", pc);
Wichert Akkermanfaf72222000-02-19 23:59:03 +00001065#elif defined(ALPHA)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001066 long pc;
1067
1068 if (upeek(tcp->pid, REG_PC, &pc) < 0) {
1069 tprintf ("[????????] ");
1070 return;
1071 }
1072 tprintf("[%08lx] ", pc);
Wichert Akkermanfaf72222000-02-19 23:59:03 +00001073#elif defined(SPARC)
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001074 struct regs regs;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001075 if (ptrace(PTRACE_GETREGS,tcp->pid,(char *)&regs,0) < 0) {
1076 tprintf("[????????] ");
1077 return;
1078 }
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001079 tprintf("[%08lx] ", regs.r_pc);
Wichert Akkermanc1652e22001-03-27 12:17:16 +00001080#elif defined(HPPA)
1081 long pc;
1082
1083 if(upeek(tcp->pid,PT_IAOQ0,&pc) < 0) {
1084 tprintf ("[????????] ");
1085 return;
1086 }
1087 tprintf("[%08lx] ", pc);
Wichert Akkerman75c422b2001-04-10 10:22:50 +00001088#elif defined(MIPS)
1089 long pc;
1090
1091 if (upeek(tcp->pid, REG_EPC, &pc) < 0) {
1092 tprintf ("[????????] ");
1093 return;
1094 }
1095 tprintf("[%08lx] ", pc);
Wichert Akkermanccef6372002-05-01 16:39:22 +00001096#elif defined(SH)
1097 long pc;
1098
1099 if (upeek(tcp->pid, 4*REG_PC, &pc) < 0) {
1100 tprintf ("[????????] ");
1101 return;
1102 }
1103 tprintf("[%08lx] ", pc);
Roland McGrathf5a47772003-06-26 22:40:42 +00001104#elif defined(SH64)
Roland McGrathe1e584b2003-06-02 19:18:58 +00001105 long pc;
1106
1107 if (upeek(tcp->pid, REG_PC, &pc) < 0) {
1108 tprintf ("[????????] ");
1109 return;
1110 }
1111 tprintf("[%08lx] ", pc);
Roland McGrathef388682003-06-03 23:28:59 +00001112#elif defined(ARM)
1113 long pc;
Roland McGrathe1e584b2003-06-02 19:18:58 +00001114
Roland McGrathef388682003-06-03 23:28:59 +00001115 if (upeek(tcp->pid, 4*15, &pc) < 0) {
1116 tprintf("[????????] ");
1117 return;
1118 }
1119 tprintf("[%08lx] ", pc);
Wichert Akkermanfaf72222000-02-19 23:59:03 +00001120#endif /* !architecture */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001121#endif /* LINUX */
1122
1123#ifdef SUNOS4
1124 struct regs regs;
1125
1126 if (ptrace(PTRACE_GETREGS, tcp->pid, (char *) &regs, 0) < 0) {
1127 perror("printcall: ptrace(PTRACE_GETREGS, ...)");
1128 tprintf("[????????] ");
1129 return;
1130 }
1131 tprintf("[%08x] ", regs.r_o7);
1132#endif /* SUNOS4 */
1133
1134#ifdef SVR4
1135 /* XXX */
1136 tprintf("[????????] ");
1137#endif
1138
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001139#ifdef FREEBSD
1140 struct reg regs;
1141 pread(tcp->pfd_reg, &regs, sizeof(regs), 0);
1142 tprintf("[%08x] ", regs.r_eip);
1143#endif /* FREEBSD */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001144}
1145
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001146#ifndef USE_PROCFS
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001147
Roland McGrathd81f1d92003-01-09 06:53:34 +00001148#if defined LINUX
1149
1150#include <sys/syscall.h>
1151#ifndef CLONE_PTRACE
1152# define CLONE_PTRACE 0x00002000
1153#endif
1154
1155#ifdef IA64
1156
Roland McGrath08267b82004-02-20 22:56:43 +00001157/* We don't have fork()/vfork() syscalls on ia64 itself, but the ia32
1158 subsystem has them for x86... */
1159#define SYS_fork 2
1160#define SYS_vfork 190
1161
Roland McGrathd81f1d92003-01-09 06:53:34 +00001162typedef unsigned long *arg_setup_state;
1163
1164static int
1165arg_setup(struct tcb *tcp, arg_setup_state *state)
1166{
1167 unsigned long *bsp, cfm, sof, sol;
1168
Roland McGrath08267b82004-02-20 22:56:43 +00001169 if (ia32)
1170 return 0;
1171
Roland McGrathd81f1d92003-01-09 06:53:34 +00001172 if (upeek(tcp->pid, PT_AR_BSP, (long *) &bsp) < 0)
1173 return -1;
1174 if (upeek(tcp->pid, PT_CFM, (long *) &cfm) < 0)
1175 return -1;
1176
1177 sof = (cfm >> 0) & 0x7f;
1178 sol = (cfm >> 7) & 0x7f;
1179 bsp = ia64_rse_skip_regs(bsp, -sof + sol);
1180
1181 *state = bsp;
1182 return 0;
1183}
1184
1185# define arg_finish_change(tcp, state) 0
1186
1187#ifdef SYS_fork
1188static int
1189get_arg0 (struct tcb *tcp, arg_setup_state *state, long *valp)
1190{
Roland McGrath08267b82004-02-20 22:56:43 +00001191 int ret;
1192
1193 if (ia32)
1194 ret = upeek (tcp->pid, PT_R11, valp);
1195 else
1196 ret = umoven (tcp,
1197 (unsigned long) ia64_rse_skip_regs(*state, 0),
1198 sizeof(long), (void *) valp);
1199 return ret;
Roland McGrathd81f1d92003-01-09 06:53:34 +00001200}
1201
1202static int
1203get_arg1 (struct tcb *tcp, arg_setup_state *state, long *valp)
1204{
Roland McGrath08267b82004-02-20 22:56:43 +00001205 int ret;
1206
1207 if (ia32)
1208 ret = upeek (tcp->pid, PT_R9, valp);
1209 else
1210 ret = umoven (tcp,
1211 (unsigned long) ia64_rse_skip_regs(*state, 1),
1212 sizeof(long), (void *) valp);
1213 return ret;
Roland McGrathd81f1d92003-01-09 06:53:34 +00001214}
1215#endif
1216
1217static int
1218set_arg0 (struct tcb *tcp, arg_setup_state *state, long val)
1219{
Roland McGrath08267b82004-02-20 22:56:43 +00001220 int req = PTRACE_POKEDATA;
1221 void *ap;
1222
1223 if (ia32) {
1224 ap = (void *) (intptr_t) PT_R11; /* r11 == EBX */
1225 req = PTRACE_POKEUSER;
1226 } else
1227 ap = ia64_rse_skip_regs(*state, 0);
Roland McGrathd81f1d92003-01-09 06:53:34 +00001228 errno = 0;
Roland McGrath08267b82004-02-20 22:56:43 +00001229 ptrace(req, tcp->pid, ap, val);
Roland McGrathd81f1d92003-01-09 06:53:34 +00001230 return errno ? -1 : 0;
1231}
1232
1233static int
1234set_arg1 (struct tcb *tcp, arg_setup_state *state, long val)
1235{
Roland McGrath08267b82004-02-20 22:56:43 +00001236 int req = PTRACE_POKEDATA;
1237 void *ap;
1238
1239 if (ia32) {
1240 ap = (void *) (intptr_t) PT_R9; /* r9 == ECX */
1241 req = PTRACE_POKEUSER;
1242 } else
1243 ap = ia64_rse_skip_regs(*state, 1);
Roland McGrathd81f1d92003-01-09 06:53:34 +00001244 errno = 0;
Roland McGrath08267b82004-02-20 22:56:43 +00001245 ptrace(req, tcp->pid, ap, val);
Roland McGrathd81f1d92003-01-09 06:53:34 +00001246 return errno ? -1 : 0;
1247}
1248
1249#elif defined (SPARC)
1250
1251typedef struct regs arg_setup_state;
1252
1253# define arg_setup(tcp, state) \
1254 (ptrace (PTRACE_GETREGS, tcp->pid, (char *) (state), 0))
1255# define arg_finish_change(tcp, state) \
1256 (ptrace (PTRACE_SETREGS, tcp->pid, (char *) (state), 0))
1257
1258# define get_arg0(tcp, state, valp) (*(valp) = (state)->r_o0, 0)
1259# define get_arg1(tcp, state, valp) (*(valp) = (state)->r_o1, 0)
1260# define set_arg0(tcp, state, val) ((state)->r_o0 = (val), 0)
1261# define set_arg1(tcp, state, val) ((state)->r_o1 = (val), 0)
Roland McGrathe1df47f2003-01-14 09:46:15 +00001262# define restore_arg0(tcp, state, val) 0
Roland McGrathd81f1d92003-01-09 06:53:34 +00001263
1264#else
1265
1266# if defined S390 || defined S390X
Roland McGrath7b308222003-01-20 09:04:36 +00001267/* Note: this is only true for the `clone' system call, which handles
1268 arguments specially. We could as well say that its first two arguments
1269 are swapped relative to other architectures, but that would just be
1270 another #ifdef in the calls. */
1271# define arg0_offset PT_GPR3
1272# define arg1_offset PT_ORIGGPR2
1273# define restore_arg0(tcp, state, val) ((void) (state), 0)
1274# define restore_arg1(tcp, state, val) ((void) (state), 0)
Roland McGrathd81f1d92003-01-09 06:53:34 +00001275# elif defined (ALPHA) || defined (MIPS)
1276# define arg0_offset REG_A0
1277# define arg1_offset (REG_A0+1)
1278# elif defined (POWERPC)
Roland McGratheb285352003-01-14 09:59:00 +00001279# define arg0_offset (sizeof(unsigned long)*PT_R3)
1280# define arg1_offset (sizeof(unsigned long)*PT_R4)
Roland McGrath7b308222003-01-20 09:04:36 +00001281# define restore_arg0(tcp, state, val) ((void) (state), 0)
Roland McGrathd81f1d92003-01-09 06:53:34 +00001282# elif defined (HPPA)
1283# define arg0_offset PT_GR26
1284# define arg1_offset (PT_GR26-4)
Roland McGrath7f33cc32003-01-10 20:51:00 +00001285# elif defined (X86_64)
1286# define arg0_offset ((long)(8*(current_personality ? RBX : RDI)))
1287# define arg1_offset ((long)(8*(current_personality ? RCX : RSI)))
Roland McGrathac971c22003-03-31 01:03:33 +00001288# elif defined (SH)
1289# define arg0_offset (4*(REG_REG0+4))
1290# define arg1_offset (4*(REG_REG0+5))
Roland McGrathf5a47772003-06-26 22:40:42 +00001291# elif defined (SH64)
Roland McGrathe1e584b2003-06-02 19:18:58 +00001292 /* ABI defines arg0 & 1 in r2 & r3 */
1293# define arg0_offset (REG_OFFSET+16)
1294# define arg1_offset (REG_OFFSET+24)
1295# define restore_arg0(tcp, state, val) 0
Roland McGrathd81f1d92003-01-09 06:53:34 +00001296# else
1297# define arg0_offset 0
1298# define arg1_offset 4
Roland McGrathac971c22003-03-31 01:03:33 +00001299# if defined ARM
Roland McGrathe1df47f2003-01-14 09:46:15 +00001300# define restore_arg0(tcp, state, val) 0
1301# endif
Roland McGrathd81f1d92003-01-09 06:53:34 +00001302# endif
1303
1304typedef int arg_setup_state;
1305
1306# define arg_setup(tcp, state) (0)
1307# define arg_finish_change(tcp, state) 0
1308# define get_arg0(tcp, cookie, valp) \
1309 (upeek ((tcp)->pid, arg0_offset, (valp)))
1310# define get_arg1(tcp, cookie, valp) \
1311 (upeek ((tcp)->pid, arg1_offset, (valp)))
1312
1313static int
1314set_arg0 (struct tcb *tcp, void *cookie, long val)
1315{
1316 return ptrace (PTRACE_POKEUSER, tcp->pid, (char*)arg0_offset, val);
1317}
1318
1319static int
1320set_arg1 (struct tcb *tcp, void *cookie, long val)
1321{
1322 return ptrace (PTRACE_POKEUSER, tcp->pid, (char*)arg1_offset, val);
1323}
1324
1325#endif
1326
Roland McGrathe1df47f2003-01-14 09:46:15 +00001327#ifndef restore_arg0
1328# define restore_arg0(tcp, state, val) set_arg0((tcp), (state), (val))
1329#endif
1330#ifndef restore_arg1
1331# define restore_arg1(tcp, state, val) set_arg1((tcp), (state), (val))
1332#endif
Roland McGrathd81f1d92003-01-09 06:53:34 +00001333
1334int
1335setbpt(tcp)
1336struct tcb *tcp;
1337{
1338 extern int change_syscall(struct tcb *, int);
1339 arg_setup_state state;
1340
1341 if (tcp->flags & TCB_BPTSET) {
1342 fprintf(stderr, "PANIC: TCB already set in pid %u\n", tcp->pid);
1343 return -1;
1344 }
1345
1346 switch (tcp->scno) {
Roland McGrath9383c6c2003-01-18 00:19:31 +00001347#ifdef SYS_vfork
1348 case SYS_vfork:
1349#endif
Roland McGrathd81f1d92003-01-09 06:53:34 +00001350#ifdef SYS_fork
1351 case SYS_fork:
Roland McGrath9b0982b2003-01-18 00:21:51 +00001352#endif
1353#if defined SYS_fork || defined SYS_vfork
Roland McGrathd81f1d92003-01-09 06:53:34 +00001354 if (arg_setup (tcp, &state) < 0
1355 || get_arg0 (tcp, &state, &tcp->inst[0]) < 0
1356 || get_arg1 (tcp, &state, &tcp->inst[1]) < 0
1357 || change_syscall(tcp, SYS_clone) < 0
1358 || set_arg0 (tcp, &state, CLONE_PTRACE|SIGCHLD) < 0
1359 || set_arg1 (tcp, &state, 0) < 0
1360 || arg_finish_change (tcp, &state) < 0)
1361 return -1;
1362 tcp->u_arg[0] = CLONE_PTRACE|SIGCHLD;
1363 tcp->u_arg[1] = 0;
1364 tcp->flags |= TCB_BPTSET;
1365 return 0;
1366#endif
1367
1368 case SYS_clone:
1369#ifdef SYS_clone2
1370 case SYS_clone2:
1371#endif
1372 if ((tcp->u_arg[0] & CLONE_PTRACE) == 0
1373 && (arg_setup (tcp, &state) < 0
1374 || set_arg0 (tcp, &state, tcp->u_arg[0] | CLONE_PTRACE) < 0
1375 || arg_finish_change (tcp, &state) < 0))
1376 return -1;
1377 tcp->flags |= TCB_BPTSET;
1378 tcp->inst[0] = tcp->u_arg[0];
1379 tcp->inst[1] = tcp->u_arg[1];
1380 return 0;
1381
1382 default:
1383 fprintf(stderr, "PANIC: setbpt for syscall %ld on %u???\n",
1384 tcp->scno, tcp->pid);
1385 break;
1386 }
1387
1388 return -1;
1389}
1390
1391int
1392clearbpt(tcp)
1393struct tcb *tcp;
1394{
1395 arg_setup_state state;
1396 if (arg_setup (tcp, &state) < 0
Roland McGrathe1df47f2003-01-14 09:46:15 +00001397 || restore_arg0 (tcp, &state, tcp->inst[0]) < 0
1398 || restore_arg1 (tcp, &state, tcp->inst[1]) < 0
Roland McGrathd81f1d92003-01-09 06:53:34 +00001399 || arg_finish_change (tcp, &state))
1400 return -1;
1401 tcp->flags &= ~TCB_BPTSET;
1402 return 0;
1403}
1404
1405#else
1406
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001407int
1408setbpt(tcp)
1409struct tcb *tcp;
1410{
1411
1412#ifdef LINUX
1413#ifdef SPARC
1414 /* We simply use the SunOS breakpoint code. */
1415
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001416 struct regs regs;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001417#define LOOPA 0x30800000 /* ba,a 0 */
1418
1419 if (tcp->flags & TCB_BPTSET) {
1420 fprintf(stderr, "PANIC: TCB already set in pid %u\n", tcp->pid);
1421 return -1;
1422 }
1423 if (ptrace(PTRACE_GETREGS, tcp->pid, (char *)&regs, 0) < 0) {
1424 perror("setbpt: ptrace(PTRACE_GETREGS, ...)");
1425 return -1;
1426 }
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001427 tcp->baddr = regs.r_o7 + 8;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001428 errno = 0;
1429 tcp->inst[0] = ptrace(PTRACE_PEEKTEXT, tcp->pid, (char *)tcp->baddr, 0);
1430 if(errno) {
1431 perror("setbpt: ptrace(PTRACE_PEEKTEXT, ...)");
1432 return -1;
1433 }
1434
1435 /*
1436 * XXX - BRUTAL MODE ON
1437 * We cannot set a real BPT in the child, since it will not be
1438 * traced at the moment it will reach the trap and would probably
1439 * die with a core dump.
1440 * Thus, we are force our way in by taking out two instructions
1441 * and insert an eternal loop instead, in expectance of the SIGSTOP
1442 * generated by out PTRACE_ATTACH.
1443 * Of cause, if we evaporate ourselves in the middle of all this...
1444 */
1445 errno = 0;
1446 ptrace(PTRACE_POKETEXT, tcp->pid, (char *) tcp->baddr, LOOPA);
1447 if(errno) {
1448 perror("setbpt: ptrace(PTRACE_POKETEXT, ...)");
1449 return -1;
1450 }
1451 tcp->flags |= TCB_BPTSET;
1452
1453#else /* !SPARC */
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00001454#ifdef IA64
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00001455 if (ia32) {
1456# define LOOP 0x0000feeb
1457 if (tcp->flags & TCB_BPTSET) {
1458 fprintf(stderr, "PANIC: bpt already set in pid %u\n",
1459 tcp->pid);
1460 return -1;
1461 }
1462 if (upeek(tcp->pid, PT_CR_IIP, &tcp->baddr) < 0)
1463 return -1;
1464 if (debug)
1465 fprintf(stderr, "[%d] setting bpt at %lx\n",
1466 tcp->pid, tcp->baddr);
1467 tcp->inst[0] = ptrace(PTRACE_PEEKTEXT, tcp->pid,
1468 (char *) tcp->baddr, 0);
1469 if (errno) {
1470 perror("setbpt: ptrace(PTRACE_PEEKTEXT, ...)");
1471 return -1;
1472 }
1473 ptrace(PTRACE_POKETEXT, tcp->pid, (char *) tcp->baddr, LOOP);
1474 if (errno) {
1475 perror("setbpt: ptrace(PTRACE_POKETEXT, ...)");
1476 return -1;
1477 }
1478 tcp->flags |= TCB_BPTSET;
1479 } else {
1480 /*
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00001481 * Our strategy here is to replace the bundle that
1482 * contained the clone() syscall with a bundle of the
1483 * form:
1484 *
1485 * { 1: br 1b; br 1b; br 1b }
1486 *
1487 * This ensures that the newly forked child will loop
1488 * endlessly until we've got a chance to attach to it.
1489 */
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00001490# define LOOP0 0x0000100000000017
1491# define LOOP1 0x4000000000200000
1492 unsigned long addr, ipsr;
1493 pid_t pid;
1494
1495 pid = tcp->pid;
1496 if (upeek(pid, PT_CR_IPSR, &ipsr) < 0)
1497 return -1;
1498 if (upeek(pid, PT_CR_IIP, &addr) < 0)
1499 return -1;
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00001500 /* store "ri" in low two bits */
1501 tcp->baddr = addr | ((ipsr >> 41) & 0x3);
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00001502
1503 errno = 0;
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00001504 tcp->inst[0] = ptrace(PTRACE_PEEKTEXT, pid, (char *) addr + 0,
1505 0);
1506 tcp->inst[1] = ptrace(PTRACE_PEEKTEXT, pid, (char *) addr + 8,
1507 0);
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00001508 if (errno) {
1509 perror("setbpt: ptrace(PTRACE_PEEKTEXT, ...)");
1510 return -1;
1511 }
1512
1513 errno = 0;
1514 ptrace(PTRACE_POKETEXT, pid, (char *) addr + 0, LOOP0);
1515 ptrace(PTRACE_POKETEXT, pid, (char *) addr + 8, LOOP1);
1516 if (errno) {
1517 perror("setbpt: ptrace(PTRACE_POKETEXT, ...)");
1518 return -1;
1519 }
1520 tcp->flags |= TCB_BPTSET;
1521 }
1522#else /* !IA64 */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001523
Michal Ludvig0e035502002-09-23 15:41:01 +00001524#if defined (I386) || defined(X86_64)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001525#define LOOP 0x0000feeb
1526#elif defined (M68K)
1527#define LOOP 0x60fe0000
1528#elif defined (ALPHA)
Wichert Akkerman4dc8a2a1999-12-23 14:20:14 +00001529#define LOOP 0xc3ffffff
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001530#elif defined (POWERPC)
Roland McGrath1e85cf92002-12-16 20:40:54 +00001531#define LOOP 0x48000000
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001532#elif defined(ARM)
Wichert Akkerman9a8a37f1999-12-24 23:19:31 +00001533#define LOOP 0xEAFFFFFE
Wichert Akkermanf90da011999-10-31 21:15:38 +00001534#elif defined(MIPS)
Wichert Akkerman4dc8a2a1999-12-23 14:20:14 +00001535#define LOOP 0x1000ffff
1536#elif defined(S390)
1537#define LOOP 0xa7f40000 /* BRC 15,0 */
Michal Ludvig10a88d02002-10-07 14:31:00 +00001538#elif defined(S390X)
1539#define LOOP 0xa7f4000000000000UL /* BRC 15,0 */
Wichert Akkermanc1652e22001-03-27 12:17:16 +00001540#elif defined(HPPA)
1541#define LOOP 0xe81f1ff7 /* b,l,n <loc>,r0 */
Wichert Akkermanccef6372002-05-01 16:39:22 +00001542#elif defined(SH)
1543#ifdef __LITTLE_ENDIAN__
1544#define LOOP 0x0000affe
1545#else
1546#define LOOP 0xfeaf0000
1547#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001548#else
1549#error unknown architecture
1550#endif
1551
1552 if (tcp->flags & TCB_BPTSET) {
1553 fprintf(stderr, "PANIC: bpt already set in pid %u\n", tcp->pid);
1554 return -1;
1555 }
1556#if defined (I386)
1557 if (upeek(tcp->pid, 4*EIP, &tcp->baddr) < 0)
1558 return -1;
Michal Ludvig0e035502002-09-23 15:41:01 +00001559#elif defined (X86_64)
1560 if (upeek(tcp->pid, 8*RIP, &tcp->baddr) < 0)
1561 return -1;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001562#elif defined (M68K)
1563 if (upeek(tcp->pid, 4*PT_PC, &tcp->baddr) < 0)
1564 return -1;
1565#elif defined (ALPHA)
1566 return -1;
1567#elif defined (ARM)
1568 return -1;
Wichert Akkermanf90da011999-10-31 21:15:38 +00001569#elif defined (MIPS)
1570 return -1; /* FIXME: I do not know what i do - Flo */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001571#elif defined (POWERPC)
Roland McGratheb285352003-01-14 09:59:00 +00001572 if (upeek(tcp->pid, sizeof(unsigned long)*PT_NIP, &tcp->baddr) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001573 return -1;
Michal Ludvig10a88d02002-10-07 14:31:00 +00001574#elif defined(S390) || defined(S390X)
Wichert Akkerman4dc8a2a1999-12-23 14:20:14 +00001575 if (upeek(tcp->pid,PT_PSWADDR, &tcp->baddr) < 0)
1576 return -1;
Wichert Akkermanc1652e22001-03-27 12:17:16 +00001577#elif defined(HPPA)
1578 if (upeek(tcp->pid, PT_IAOQ0, &tcp->baddr) < 0)
1579 return -1;
1580 tcp->baddr &= ~0x03;
Wichert Akkermanccef6372002-05-01 16:39:22 +00001581#elif defined(SH)
1582 if (upeek(tcp->pid, 4*REG_PC, &tcp->baddr) < 0)
1583 return -1;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001584#else
1585#error unknown architecture
1586#endif
1587 if (debug)
1588 fprintf(stderr, "[%d] setting bpt at %lx\n", tcp->pid, tcp->baddr);
1589 tcp->inst[0] = ptrace(PTRACE_PEEKTEXT, tcp->pid, (char *) tcp->baddr, 0);
1590 if (errno) {
1591 perror("setbpt: ptrace(PTRACE_PEEKTEXT, ...)");
1592 return -1;
1593 }
1594 ptrace(PTRACE_POKETEXT, tcp->pid, (char *) tcp->baddr, LOOP);
1595 if (errno) {
1596 perror("setbpt: ptrace(PTRACE_POKETEXT, ...)");
1597 return -1;
1598 }
1599 tcp->flags |= TCB_BPTSET;
1600
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00001601#endif /* !IA64 */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001602#endif /* SPARC */
1603#endif /* LINUX */
1604
1605#ifdef SUNOS4
1606#ifdef SPARC /* This code is slightly sparc specific */
1607
Wichert Akkermane6f876c1999-06-22 15:28:30 +00001608 struct regs regs;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001609#define BPT 0x91d02001 /* ta 1 */
1610#define LOOP 0x10800000 /* ba 0 */
1611#define LOOPA 0x30800000 /* ba,a 0 */
1612#define NOP 0x01000000
1613#if LOOPA
1614 static int loopdeloop[1] = {LOOPA};
1615#else
1616 static int loopdeloop[2] = {LOOP, NOP};
1617#endif
1618
1619 if (tcp->flags & TCB_BPTSET) {
1620 fprintf(stderr, "PANIC: TCB already set in pid %u\n", tcp->pid);
1621 return -1;
1622 }
1623 if (ptrace(PTRACE_GETREGS, tcp->pid, (char *)&regs, 0) < 0) {
1624 perror("setbpt: ptrace(PTRACE_GETREGS, ...)");
1625 return -1;
1626 }
1627 tcp->baddr = regs.r_o7 + 8;
1628 if (ptrace(PTRACE_READTEXT, tcp->pid, (char *)tcp->baddr,
1629 sizeof tcp->inst, (char *)tcp->inst) < 0) {
1630 perror("setbpt: ptrace(PTRACE_READTEXT, ...)");
1631 return -1;
1632 }
1633
1634 /*
1635 * XXX - BRUTAL MODE ON
1636 * We cannot set a real BPT in the child, since it will not be
1637 * traced at the moment it will reach the trap and would probably
1638 * die with a core dump.
1639 * Thus, we are force our way in by taking out two instructions
1640 * and insert an eternal loop in stead, in expectance of the SIGSTOP
1641 * generated by out PTRACE_ATTACH.
1642 * Of cause, if we evaporate ourselves in the middle of all this...
1643 */
1644 if (ptrace(PTRACE_WRITETEXT, tcp->pid, (char *) tcp->baddr,
1645 sizeof loopdeloop, (char *) loopdeloop) < 0) {
1646 perror("setbpt: ptrace(PTRACE_WRITETEXT, ...)");
1647 return -1;
1648 }
1649 tcp->flags |= TCB_BPTSET;
1650
1651#endif /* SPARC */
1652#endif /* SUNOS4 */
1653
1654 return 0;
1655}
1656
1657int
1658clearbpt(tcp)
1659struct tcb *tcp;
1660{
1661
1662#ifdef LINUX
Michal Ludvig0e035502002-09-23 15:41:01 +00001663#if defined(I386) || defined(X86_64)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001664 long eip;
Wichert Akkermanfaf72222000-02-19 23:59:03 +00001665#elif defined(POWERPC)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001666 long pc;
Wichert Akkermanfaf72222000-02-19 23:59:03 +00001667#elif defined(M68K)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001668 long pc;
Wichert Akkermanfaf72222000-02-19 23:59:03 +00001669#elif defined(ALPHA)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001670 long pc;
Wichert Akkermanc1652e22001-03-27 12:17:16 +00001671#elif defined(HPPA)
1672 long iaoq;
Wichert Akkermanccef6372002-05-01 16:39:22 +00001673#elif defined(SH)
1674 long pc;
Wichert Akkermanfaf72222000-02-19 23:59:03 +00001675#endif /* architecture */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001676
1677#ifdef SPARC
1678 /* Again, we borrow the SunOS breakpoint code. */
1679 if (!(tcp->flags & TCB_BPTSET)) {
1680 fprintf(stderr, "PANIC: TCB not set in pid %u\n", tcp->pid);
1681 return -1;
1682 }
1683 errno = 0;
1684 ptrace(PTRACE_POKETEXT, tcp->pid, (char *) tcp->baddr, tcp->inst[0]);
1685 if(errno) {
1686 perror("clearbtp: ptrace(PTRACE_POKETEXT, ...)");
1687 return -1;
1688 }
1689 tcp->flags &= ~TCB_BPTSET;
Wichert Akkermanfaf72222000-02-19 23:59:03 +00001690#elif defined(IA64)
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00001691 if (ia32) {
1692 unsigned long addr;
1693
1694 if (debug)
1695 fprintf(stderr, "[%d] clearing bpt\n", tcp->pid);
1696 if (!(tcp->flags & TCB_BPTSET)) {
1697 fprintf(stderr, "PANIC: TCB not set in pid %u\n", tcp->pid);
1698 return -1;
1699 }
1700 errno = 0;
1701 ptrace(PTRACE_POKETEXT, tcp->pid, (char *) tcp->baddr, tcp->inst[0]);
1702 if (errno) {
1703 perror("clearbtp: ptrace(PTRACE_POKETEXT, ...)");
1704 return -1;
1705 }
1706 tcp->flags &= ~TCB_BPTSET;
1707
1708 if (upeek(tcp->pid, PT_CR_IIP, &addr) < 0)
1709 return -1;
1710 if (addr != tcp->baddr) {
1711 /* The breakpoint has not been reached yet. */
1712 if (debug)
1713 fprintf(stderr,
1714 "NOTE: PC not at bpt (pc %#lx baddr %#lx)\n",
1715 addr, tcp->baddr);
1716 return 0;
1717 }
1718 } else {
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00001719 unsigned long addr, ipsr;
1720 pid_t pid;
1721
1722 pid = tcp->pid;
1723
1724 if (upeek(pid, PT_CR_IPSR, &ipsr) < 0)
1725 return -1;
1726 if (upeek(pid, PT_CR_IIP, &addr) < 0)
1727 return -1;
1728
1729 /* restore original bundle: */
1730 errno = 0;
1731 ptrace(PTRACE_POKETEXT, pid, (char *) addr + 0, tcp->inst[0]);
1732 ptrace(PTRACE_POKETEXT, pid, (char *) addr + 8, tcp->inst[1]);
1733 if (errno) {
1734 perror("clearbpt: ptrace(PTRACE_POKETEXT, ...)");
1735 return -1;
1736 }
1737
1738 /* restore original "ri" in ipsr: */
1739 ipsr = (ipsr & ~(0x3ul << 41)) | ((tcp->baddr & 0x3) << 41);
1740 errno = 0;
1741 ptrace(PTRACE_POKEUSER, pid, (char *) PT_CR_IPSR, ipsr);
1742 if (errno) {
1743 perror("clrbpt: ptrace(PTRACE_POKEUSER, ...)");
1744 return -1;
1745 }
1746
1747 tcp->flags &= ~TCB_BPTSET;
1748
1749 if (addr != (tcp->baddr & ~0x3)) {
1750 /* the breakpoint has not been reached yet. */
1751 if (debug)
1752 fprintf(stderr, "NOTE: PC not at bpt (pc %#lx baddr %#lx)\n",
1753 addr, tcp->baddr);
1754 return 0;
1755 }
1756 }
Wichert Akkermanfaf72222000-02-19 23:59:03 +00001757#else /* !IA64 && ! SPARC */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001758
1759 if (debug)
1760 fprintf(stderr, "[%d] clearing bpt\n", tcp->pid);
1761 if (!(tcp->flags & TCB_BPTSET)) {
1762 fprintf(stderr, "PANIC: TCB not set in pid %u\n", tcp->pid);
1763 return -1;
1764 }
1765 errno = 0;
1766 ptrace(PTRACE_POKETEXT, tcp->pid, (char *) tcp->baddr, tcp->inst[0]);
1767 if (errno) {
1768 perror("clearbtp: ptrace(PTRACE_POKETEXT, ...)");
1769 return -1;
1770 }
1771 tcp->flags &= ~TCB_BPTSET;
1772
1773#ifdef I386
1774 if (upeek(tcp->pid, 4*EIP, &eip) < 0)
1775 return -1;
1776 if (eip != tcp->baddr) {
1777 /* The breakpoint has not been reached yet. */
1778 if (debug)
1779 fprintf(stderr,
1780 "NOTE: PC not at bpt (pc %#lx baddr %#lx)\n",
1781 eip, tcp->baddr);
1782 return 0;
1783 }
Michal Ludvig0e035502002-09-23 15:41:01 +00001784#elif defined(X86_64)
1785 if (upeek(tcp->pid, 8*RIP, &eip) < 0)
1786 return -1;
1787 if (eip != tcp->baddr) {
1788 /* The breakpoint has not been reached yet. */
1789 if (debug)
1790 fprintf(stderr,
1791 "NOTE: PC not at bpt (pc %#lx baddr %#lx)\n",
1792 eip, tcp->baddr);
1793 return 0;
1794 }
Wichert Akkermanc7926982000-04-10 22:22:31 +00001795#elif defined(POWERPC)
Roland McGratheb285352003-01-14 09:59:00 +00001796 if (upeek(tcp->pid, sizeof(unsigned long)*PT_NIP, &pc) < 0)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001797 return -1;
1798 if (pc != tcp->baddr) {
1799 /* The breakpoint has not been reached yet. */
1800 if (debug)
1801 fprintf(stderr, "NOTE: PC not at bpt (pc %#lx baddr %#lx)\n",
1802 pc, tcp->baddr);
1803 return 0;
1804 }
Wichert Akkermanfaf72222000-02-19 23:59:03 +00001805#elif defined(M68K)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001806 if (upeek(tcp->pid, 4*PT_PC, &pc) < 0)
1807 return -1;
1808 if (pc != tcp->baddr) {
1809 /* The breakpoint has not been reached yet. */
1810 if (debug)
1811 fprintf(stderr, "NOTE: PC not at bpt (pc %#lx baddr %#lx)\n",
1812 pc, tcp->baddr);
1813 return 0;
1814 }
Wichert Akkermanfaf72222000-02-19 23:59:03 +00001815#elif defined(ALPHA)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001816 if (upeek(tcp->pid, REG_PC, &pc) < 0)
1817 return -1;
1818 if (pc != tcp->baddr) {
1819 /* The breakpoint has not been reached yet. */
1820 if (debug)
1821 fprintf(stderr, "NOTE: PC not at bpt (pc %#lx baddr %#lx)\n",
1822 pc, tcp->baddr);
1823 return 0;
1824 }
Wichert Akkermanc1652e22001-03-27 12:17:16 +00001825#elif defined(HPPA)
1826 if (upeek(tcp->pid, PT_IAOQ0, &iaoq) < 0)
1827 return -1;
1828 iaoq &= ~0x03;
1829 if (iaoq != tcp->baddr && iaoq != tcp->baddr + 4) {
1830 /* The breakpoint has not been reached yet. */
1831 if (debug)
1832 fprintf(stderr, "NOTE: PC not at bpt (iaoq %#lx baddr %#lx)\n",
1833 iaoq, tcp->baddr);
1834 return 0;
1835 }
1836 iaoq = tcp->baddr | 3;
1837 /* We should be pointing at a 'ldi -1000,r1' in glibc, so it is
1838 * safe to set both IAOQ0 and IAOQ1 to that so the PSW N bit
1839 * has no significant effect.
1840 */
1841 ptrace(PTRACE_POKEUSER, tcp->pid, (void *)PT_IAOQ0, iaoq);
1842 ptrace(PTRACE_POKEUSER, tcp->pid, (void *)PT_IAOQ1, iaoq);
Wichert Akkermanccef6372002-05-01 16:39:22 +00001843#elif defined(SH)
1844 if (upeek(tcp->pid, 4*REG_PC, &pc) < 0)
1845 return -1;
1846 if (pc != tcp->baddr) {
1847 /* The breakpoint has not been reached yet. */
1848 if (debug)
1849 fprintf(stderr, "NOTE: PC not at bpt (pc %#lx baddr %#lx)\n",
1850 pc, tcp->baddr);
1851 return 0;
1852 }
1853
Wichert Akkermanfaf72222000-02-19 23:59:03 +00001854#endif /* arch */
1855#endif /* !SPARC && !IA64 */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001856#endif /* LINUX */
1857
1858#ifdef SUNOS4
1859#ifdef SPARC
1860
1861#if !LOOPA
Wichert Akkermane6f876c1999-06-22 15:28:30 +00001862 struct regs regs;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001863#endif
1864
1865 if (!(tcp->flags & TCB_BPTSET)) {
1866 fprintf(stderr, "PANIC: TCB not set in pid %u\n", tcp->pid);
1867 return -1;
1868 }
1869 if (ptrace(PTRACE_WRITETEXT, tcp->pid, (char *) tcp->baddr,
1870 sizeof tcp->inst, (char *) tcp->inst) < 0) {
1871 perror("clearbtp: ptrace(PTRACE_WRITETEXT, ...)");
1872 return -1;
1873 }
1874 tcp->flags &= ~TCB_BPTSET;
1875
1876#if !LOOPA
1877 /*
1878 * Since we don't have a single instruction breakpoint, we may have
1879 * to adjust the program counter after removing the our `breakpoint'.
1880 */
1881 if (ptrace(PTRACE_GETREGS, tcp->pid, (char *)&regs, 0) < 0) {
1882 perror("clearbpt: ptrace(PTRACE_GETREGS, ...)");
1883 return -1;
1884 }
1885 if ((regs.r_pc < tcp->baddr) ||
1886 (regs.r_pc > tcp->baddr + 4)) {
1887 /* The breakpoint has not been reached yet */
1888 if (debug)
1889 fprintf(stderr,
1890 "NOTE: PC not at bpt (pc %#x baddr %#x)\n",
1891 regs.r_pc, tcp->parent->baddr);
1892 return 0;
1893 }
1894 if (regs.r_pc != tcp->baddr)
1895 if (debug)
1896 fprintf(stderr, "NOTE: PC adjusted (%#x -> %#x\n",
1897 regs.r_pc, tcp->baddr);
1898
1899 regs.r_pc = tcp->baddr;
1900 if (ptrace(PTRACE_SETREGS, tcp->pid, (char *)&regs, 0) < 0) {
1901 perror("clearbpt: ptrace(PTRACE_SETREGS, ...)");
1902 return -1;
1903 }
1904#endif /* LOOPA */
1905#endif /* SPARC */
1906#endif /* SUNOS4 */
1907
1908 return 0;
1909}
1910
Roland McGrathd81f1d92003-01-09 06:53:34 +00001911#endif
1912
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001913#endif /* !USE_PROCFS */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001914
1915#ifdef SUNOS4
1916
1917static int
1918getex(pid, hdr)
1919int pid;
1920struct exec *hdr;
1921{
1922 int n;
1923
1924 for (n = 0; n < sizeof *hdr; n += 4) {
1925 long res;
1926 if (upeek(pid, uoff(u_exdata) + n, &res) < 0)
1927 return -1;
1928 memcpy(((char *) hdr) + n, &res, 4);
1929 }
1930 if (debug) {
1931 fprintf(stderr, "[struct exec: magic: %o version %u Mach %o\n",
1932 hdr->a_magic, hdr->a_toolversion, hdr->a_machtype);
1933 fprintf(stderr, "Text %lu Data %lu Bss %lu Syms %lu Entry %#lx]\n",
1934 hdr->a_text, hdr->a_data, hdr->a_bss, hdr->a_syms, hdr->a_entry);
1935 }
1936 return 0;
1937}
1938
1939int
1940fixvfork(tcp)
1941struct tcb *tcp;
1942{
1943 int pid = tcp->pid;
1944 /*
1945 * Change `vfork' in a freshly exec'ed dynamically linked
1946 * executable's (internal) symbol table to plain old `fork'
1947 */
1948
1949 struct exec hdr;
1950 struct link_dynamic dyn;
1951 struct link_dynamic_2 ld;
1952 char *strtab, *cp;
1953
1954 if (getex(pid, &hdr) < 0)
1955 return -1;
1956 if (!hdr.a_dynamic)
1957 return -1;
1958
1959 if (umove(tcp, (int) N_DATADDR(hdr), &dyn) < 0) {
1960 fprintf(stderr, "Cannot read DYNAMIC\n");
1961 return -1;
1962 }
1963 if (umove(tcp, (int) dyn.ld_un.ld_2, &ld) < 0) {
1964 fprintf(stderr, "Cannot read link_dynamic_2\n");
1965 return -1;
1966 }
1967 if ((strtab = malloc((unsigned)ld.ld_symb_size)) == NULL) {
1968 fprintf(stderr, "fixvfork: out of memory\n");
1969 return -1;
1970 }
1971 if (umoven(tcp, (int)ld.ld_symbols+(int)N_TXTADDR(hdr),
1972 (int)ld.ld_symb_size, strtab) < 0)
1973 goto err;
1974
1975#if 0
1976 for (cp = strtab; cp < strtab + ld.ld_symb_size; ) {
1977 fprintf(stderr, "[symbol: %s]\n", cp);
1978 cp += strlen(cp)+1;
1979 }
1980 return 0;
1981#endif
1982 for (cp = strtab; cp < strtab + ld.ld_symb_size; ) {
1983 if (strcmp(cp, "_vfork") == 0) {
1984 if (debug)
1985 fprintf(stderr, "fixvfork: FOUND _vfork\n");
1986 strcpy(cp, "_fork");
1987 break;
1988 }
1989 cp += strlen(cp)+1;
1990 }
1991 if (cp < strtab + ld.ld_symb_size)
1992 /*
1993 * Write entire symbol table back to avoid
1994 * memory alignment bugs in ptrace
1995 */
1996 if (tload(pid, (int)ld.ld_symbols+(int)N_TXTADDR(hdr),
1997 (int)ld.ld_symb_size, strtab) < 0)
1998 goto err;
1999
2000 free(strtab);
2001 return 0;
2002
2003err:
2004 free(strtab);
2005 return -1;
2006}
2007
2008#endif /* SUNOS4 */