blob: 529114241e5ca09a2c06cda4ad946b26b0ea9e39 [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
38#include <sys/user.h>
39#include <sys/param.h>
40#include <fcntl.h>
41#ifdef SUNOS4
42#include <machine/reg.h>
43#include <a.out.h>
44#include <link.h>
45#endif /* SUNOS4 */
Wichert Akkerman36915a11999-07-13 15:45:02 +000046
Wichert Akkerman43a74822000-06-27 17:33:32 +000047#if defined(linux) && (__GLIBC__ < 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ < 1))
Wichert Akkerman36915a11999-07-13 15:45:02 +000048#include <linux/ptrace.h>
49#endif
50
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +000051#if defined(LINUX) && defined(IA64)
52#include <asm/ptrace_offsets.h>
53#endif
54
Wichert Akkerman36915a11999-07-13 15:45:02 +000055#ifdef HAVE_SYS_REG_H
56#include <sys/reg.h>
Wichert Akkerman76baf7c1999-02-19 00:21:36 +000057# define PTRACE_PEEKUSR PTRACE_PEEKUSER
Wichert Akkermanfaf72222000-02-19 23:59:03 +000058#elif defined(HAVE_LINUX_PTRACE_H)
59#undef PTRACE_SYSCALL
60#include <linux/ptrace.h>
Wichert Akkerman2e2553a1999-05-09 00:29:58 +000061#endif
62
Wichert Akkerman76baf7c1999-02-19 00:21:36 +000063#ifdef SUNOS4_KERNEL_ARCH_KLUDGE
64#include <sys/utsname.h>
65#endif /* SUNOS4_KERNEL_ARCH_KLUDGE */
66
Wichert Akkerman9ce1a631999-08-29 23:15:07 +000067#if defined(LINUX) && defined(SPARC)
68
69#include <asm/reg.h>
70
71#if !defined(__GLIBC__)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +000072
73#include <linux/unistd.h>
74
75#define _hack_syscall5(type,name,type1,arg1,type2,arg2,type3,arg3,type4,arg4,\
76 type5,arg5,syscall) \
77type name (type1 arg1,type2 arg2,type3 arg3,type4 arg4,type5 arg5) \
78{ \
79 long __res; \
80\
81__asm__ volatile ("or %%g0, %1, %%o0\n\t" \
82 "or %%g0, %2, %%o1\n\t" \
83 "or %%g0, %3, %%o2\n\t" \
84 "or %%g0, %4, %%o3\n\t" \
85 "or %%g0, %5, %%o4\n\t" \
86 "or %%g0, %6, %%g1\n\t" \
87 "t 0x10\n\t" \
88 "bcc 1f\n\t" \
89 "or %%g0, %%o0, %0\n\t" \
90 "sub %%g0, %%o0, %0\n\t" \
91 "1:\n\t" \
92 : "=r" (__res) \
93 : "0" ((long)(arg1)),"1" ((long)(arg2)), \
94 "2" ((long)(arg3)),"3" ((long)(arg4)),"4" ((long)(arg5)), \
95 "i" (__NR_##syscall) \
96 : "g1", "o0", "o1", "o2", "o3", "o4"); \
97if (__res>=0) \
98 return (type) __res; \
99errno = -__res; \
100return -1; \
101}
102
103static _hack_syscall5(int,_ptrace,int,__request,int,__pid,int,__addr,int,__data,int,__addr2,ptrace)
104
105#define _ptrace
106
107#endif
108
Wichert Akkerman9ce1a631999-08-29 23:15:07 +0000109#endif
110
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000111/* macros */
112#ifndef MAX
113#define MAX(a,b) (((a) > (b)) ? (a) : (b))
114#endif
115#ifndef MIN
116#define MIN(a,b) (((a) < (b)) ? (a) : (b))
117#endif
118
119void
120tv_tv(tv, a, b)
121struct timeval *tv;
122int a;
123int b;
124{
125 tv->tv_sec = a;
126 tv->tv_usec = b;
127}
128
129int
130tv_nz(a)
131struct timeval *a;
132{
133 return a->tv_sec || a->tv_usec;
134}
135
136int
137tv_cmp(a, b)
138struct timeval *a, *b;
139{
140 if (a->tv_sec < b->tv_sec
141 || (a->tv_sec == b->tv_sec && a->tv_usec < b->tv_usec))
142 return -1;
143 if (a->tv_sec > b->tv_sec
144 || (a->tv_sec == b->tv_sec && a->tv_usec > b->tv_usec))
145 return 1;
146 return 0;
147}
148
149double
150tv_float(tv)
151struct timeval *tv;
152{
153 return tv->tv_sec + tv->tv_usec/1000000.0;
154}
155
156void
157tv_add(tv, a, b)
158struct timeval *tv, *a, *b;
159{
160 tv->tv_sec = a->tv_sec + b->tv_sec;
161 tv->tv_usec = a->tv_usec + b->tv_usec;
162 if (tv->tv_usec > 1000000) {
163 tv->tv_sec++;
164 tv->tv_usec -= 1000000;
165 }
166}
167
168void
169tv_sub(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 (((long) tv->tv_usec) < 0) {
175 tv->tv_sec--;
176 tv->tv_usec += 1000000;
177 }
178}
179
180void
181tv_div(tv, a, n)
182struct timeval *tv, *a;
183int n;
184{
185 tv->tv_usec = (a->tv_sec % n * 1000000 + a->tv_usec + n / 2) / n;
186 tv->tv_sec = a->tv_sec / n + tv->tv_usec / 1000000;
187 tv->tv_usec %= 1000000;
188}
189
190void
191tv_mul(tv, a, n)
192struct timeval *tv, *a;
193int n;
194{
195 tv->tv_usec = a->tv_usec * n;
196 tv->tv_sec = a->tv_sec * n + a->tv_usec / 1000000;
197 tv->tv_usec %= 1000000;
198}
199
200char *
201xlookup(xlat, val)
202struct xlat *xlat;
203int val;
204{
205 for (; xlat->str != NULL; xlat++)
206 if (xlat->val == val)
207 return xlat->str;
208 return NULL;
209}
210
211/*
212 * Print entry in struct xlat table, if there.
213 */
214void
215printxval(xlat, val, dflt)
216struct xlat *xlat;
217int val;
218char *dflt;
219{
220 char *str = xlookup(xlat, val);
221
222 if (str)
223 tprintf("%s", str);
224 else
225 tprintf("%#x /* %s */", val, dflt);
226}
227
228/*
229 * Interpret `xlat' as an array of flags
230 * print the entries whose bits are on in `flags'
231 * return # of flags printed.
232 */
233int
234addflags(xlat, flags)
235struct xlat *xlat;
236int flags;
237{
238 int n;
239
240 for (n = 0; xlat->str; xlat++) {
241 if (xlat->val && (flags & xlat->val) == xlat->val) {
242 tprintf("|%s", xlat->str);
243 flags &= ~xlat->val;
244 n++;
245 }
246 }
247 if (flags) {
248 tprintf("|%#x", flags);
249 n++;
250 }
251 return n;
252}
253
254int
255printflags(xlat, flags)
256struct xlat *xlat;
257int flags;
258{
259 int n;
260 char *sep;
261
262 if (flags == 0 && xlat->val == 0) {
263 tprintf("%s", xlat->str);
264 return 1;
265 }
266
267 sep = "";
268 for (n = 0; xlat->str; xlat++) {
269 if (xlat->val && (flags & xlat->val) == xlat->val) {
270 tprintf("%s%s", sep, xlat->str);
271 flags &= ~xlat->val;
272 sep = "|";
273 n++;
274 }
275 }
276 if (flags) {
277 tprintf("%s%#x", sep, flags);
278 n++;
279 }
280 return n;
281}
282
283void
284printnum(tcp, addr, fmt)
285struct tcb *tcp;
286long addr;
287char *fmt;
288{
289 int num;
290
291 if (!addr) {
292 tprintf("NULL");
293 return;
294 }
295 if (umove(tcp, addr, &num) < 0) {
296 tprintf("%#lx", addr);
297 return;
298 }
299 tprintf("[");
300 tprintf(fmt, num);
301 tprintf("]");
302}
303
304static char path[MAXPATHLEN + 1];
305
306void
307string_quote(str)
308char *str;
309{
310 char buf[2 * MAXPATHLEN + 1];
311 char *s;
312
313 if (!strpbrk(str, "\"\'\\")) {
314 tprintf("\"%s\"", str);
315 return;
316 }
317 for (s = buf; *str; str++) {
318 switch (*str) {
319 case '\"': case '\'': case '\\':
320 *s++ = '\\'; *s++ = *str; break;
321 default:
322 *s++ = *str; break;
323 }
324 }
325 *s = '\0';
326 tprintf("\"%s\"", buf);
327}
328
329void
330printpath(tcp, addr)
331struct tcb *tcp;
332long addr;
333{
334 if (umovestr(tcp, addr, MAXPATHLEN, path) < 0)
335 tprintf("%#lx", addr);
336 else
337 string_quote(path);
338 return;
339}
340
341void
342printpathn(tcp, addr, n)
343struct tcb *tcp;
344long addr;
345int n;
346{
347 if (umovestr(tcp, addr, n, path) < 0)
348 tprintf("%#lx", addr);
349 else {
350 path[n] = '\0';
351 string_quote(path);
352 }
353}
354
355void
356printstr(tcp, addr, len)
357struct tcb *tcp;
358long addr;
359int len;
360{
361 static unsigned char *str = NULL;
362 static char *outstr;
363 int i, n, c, usehex;
364 char *s, *outend;
365
366 if (!addr) {
367 tprintf("NULL");
368 return;
369 }
370 if (!str) {
371 if ((str = malloc(max_strlen)) == NULL
372 || (outstr = malloc(2*max_strlen)) == NULL) {
373 fprintf(stderr, "printstr: no memory\n");
374 tprintf("%#lx", addr);
375 return;
376 }
377 }
Wichert Akkerman2e2553a1999-05-09 00:29:58 +0000378 outend = outstr + max_strlen * 2 - 10;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000379 if (len < 0) {
380 n = max_strlen;
381 if (umovestr(tcp, addr, n, (char *) str) < 0) {
382 tprintf("%#lx", addr);
383 return;
384 }
385 }
386 else {
387 n = MIN(len, max_strlen);
388 if (umoven(tcp, addr, n, (char *) str) < 0) {
389 tprintf("%#lx", addr);
390 return;
391 }
392 }
393
394 usehex = 0;
395 if (xflag > 1)
396 usehex = 1;
397 else if (xflag) {
398 for (i = 0; i < n; i++) {
399 c = str[i];
400 if (len < 0 && c == '\0')
401 break;
402 if (!isprint(c) && !isspace(c)) {
403 usehex = 1;
404 break;
405 }
406 }
407 }
408
409 s = outstr;
410 *s++ = '\"';
411
412 if (usehex) {
413 for (i = 0; i < n; i++) {
414 c = str[i];
415 if (len < 0 && c == '\0')
416 break;
417 sprintf(s, "\\x%02x", c);
418 s += 4;
419 if (s > outend)
420 break;
421 }
422 }
423 else {
424 for (i = 0; i < n; i++) {
425 c = str[i];
426 if (len < 0 && c == '\0')
427 break;
428 switch (c) {
429 case '\"': case '\'': case '\\':
430 *s++ = '\\'; *s++ = c; break;
431 case '\f':
432 *s++ = '\\'; *s++ = 'f'; break;
433 case '\n':
434 *s++ = '\\'; *s++ = 'n'; break;
435 case '\r':
436 *s++ = '\\'; *s++ = 'r'; break;
437 case '\t':
438 *s++ = '\\'; *s++ = 't'; break;
439 case '\v':
440 *s++ = '\\'; *s++ = 'v'; break;
441 default:
442 if (isprint(c))
443 *s++ = c;
444 else if (i < n - 1 && isdigit(str[i + 1])) {
445 sprintf(s, "\\%03o", c);
446 s += 4;
447 }
448 else {
449 sprintf(s, "\\%o", c);
450 s += strlen(s);
451 }
452 break;
453 }
454 if (s > outend)
455 break;
456 }
457 }
458
459 *s++ = '\"';
460 if (i < len || (len < 0 && (i == n || s > outend))) {
461 *s++ = '.'; *s++ = '.'; *s++ = '.';
462 }
463 *s = '\0';
464 tprintf("%s", outstr);
465}
466
467void
468dumpstr(tcp, addr, len)
469struct tcb *tcp;
470long addr;
471int len;
472{
473 static int strsize = -1;
474 static unsigned char *str;
475 static char outstr[80];
476 char *s;
477 int i, j;
478
479 if (strsize < len) {
480 if (str)
481 free(str);
482 if ((str = malloc(len)) == NULL) {
483 fprintf(stderr, "dump: no memory\n");
484 return;
485 }
486 strsize = len;
487 }
488
489 if (umoven(tcp, addr, len, (char *) str) < 0)
490 return;
491
492 for (i = 0; i < len; i += 16) {
493 s = outstr;
494 sprintf(s, " | %05x ", i);
495 s += 9;
496 for (j = 0; j < 16; j++) {
497 if (j == 8)
498 *s++ = ' ';
499 if (i + j < len) {
500 sprintf(s, " %02x", str[i + j]);
501 s += 3;
502 }
503 else {
504 *s++ = ' '; *s++ = ' '; *s++ = ' ';
505 }
506 }
507 *s++ = ' '; *s++ = ' ';
508 for (j = 0; j < 16; j++) {
509 if (j == 8)
510 *s++ = ' ';
511 if (i + j < len) {
512 if (isprint(str[i + j]))
513 *s++ = str[i + j];
514 else
515 *s++ = '.';
516 }
517 else
518 *s++ = ' ';
519 }
520 tprintf("%s |\n", outstr);
521 }
522}
523
524#define PAGMASK (~(PAGSIZ - 1))
525/*
526 * move `len' bytes of data from process `pid'
527 * at address `addr' to our space at `laddr'
528 */
529int
530umoven(tcp, addr, len, laddr)
531struct tcb *tcp;
532long addr;
533int len;
534char *laddr;
535{
536
537#ifdef LINUX
538 int pid = tcp->pid;
539 int n, m;
Wichert Akkerman5daa0281999-03-15 19:49:42 +0000540 int started = 0;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000541 union {
542 long val;
543 char x[sizeof(long)];
544 } u;
545
546 if (addr & (sizeof(long) - 1)) {
547 /* addr not a multiple of sizeof(long) */
548 n = addr - (addr & -sizeof(long)); /* residue */
549 addr &= -sizeof(long); /* residue */
550 errno = 0;
551 u.val = ptrace(PTRACE_PEEKDATA, pid, (char *) addr, 0);
552 if (errno) {
Wichert Akkerman5daa0281999-03-15 19:49:42 +0000553 if (started && (errno==EPERM || errno==EIO)) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000554 /* Ran into 'end of memory' - stupid "printpath" */
555 return 0;
556 }
Wichert Akkerman5daa0281999-03-15 19:49:42 +0000557 /* But if not started, we had a bogus address. */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000558 perror("ptrace: umoven");
559 return -1;
560 }
Wichert Akkerman5daa0281999-03-15 19:49:42 +0000561 started = 1;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000562 memcpy(laddr, &u.x[n], m = MIN(sizeof(long) - n, len));
563 addr += sizeof(long), laddr += m, len -= m;
564 }
565 while (len) {
566 errno = 0;
567 u.val = ptrace(PTRACE_PEEKDATA, pid, (char *) addr, 0);
568 if (errno) {
Wichert Akkerman5daa0281999-03-15 19:49:42 +0000569 if (started && (errno==EPERM || errno==EIO)) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000570 /* Ran into 'end of memory' - stupid "printpath" */
571 return 0;
572 }
573 perror("ptrace: umoven");
574 return -1;
575 }
Wichert Akkerman5daa0281999-03-15 19:49:42 +0000576 started = 1;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000577 memcpy(laddr, u.x, m = MIN(sizeof(long), len));
578 addr += sizeof(long), laddr += m, len -= m;
579 }
580#endif /* LINUX */
581
582#ifdef SUNOS4
583 int pid = tcp->pid;
584#if 0
585 int n, m;
586 union {
587 long val;
588 char x[sizeof(long)];
589 } u;
590
591 if (addr & (sizeof(long) - 1)) {
592 /* addr not a multiple of sizeof(long) */
593 n = addr - (addr & -sizeof(long)); /* residue */
594 addr &= -sizeof(long); /* residue */
595 errno = 0;
596 u.val = ptrace(PTRACE_PEEKDATA, pid, (char *) addr, 0);
597 if (errno) {
598 perror("umoven");
599 return -1;
600 }
601 memcpy(laddr, &u.x[n], m = MIN(sizeof(long) - n, len));
602 addr += sizeof(long), laddr += m, len -= m;
603 }
604 while (len) {
605 errno = 0;
606 u.val = ptrace(PTRACE_PEEKDATA, pid, (char *) addr, 0);
607 if (errno) {
608 perror("umoven");
609 return -1;
610 }
611 memcpy(laddr, u.x, m = MIN(sizeof(long), len));
612 addr += sizeof(long), laddr += m, len -= m;
613 }
614#else /* !oldway */
615 int n;
616
617 while (len) {
618 n = MIN(len, PAGSIZ);
619 n = MIN(n, ((addr + PAGSIZ) & PAGMASK) - addr);
620 if (ptrace(PTRACE_READDATA, pid,
621 (char *) addr, len, laddr) < 0) {
622 perror("umoven: ptrace(PTRACE_READDATA, ...)");
623 abort();
624 return -1;
625 }
626 len -= n;
627 addr += n;
628 laddr += n;
629 }
630#endif /* !oldway */
631#endif /* SUNOS4 */
632
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000633#ifdef USE_PROCFS
Wichert Akkermanea78f0f1999-11-29 15:34:02 +0000634#ifdef HAVE_MP_PROCFS
John Hughesaa09c6b2001-05-15 14:53:43 +0000635 int fd = tcp->pfd_as;
Wichert Akkerman9ce1a631999-08-29 23:15:07 +0000636#else
John Hughesaa09c6b2001-05-15 14:53:43 +0000637 int fd = tcp->pfd;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000638#endif
John Hughesaa09c6b2001-05-15 14:53:43 +0000639 lseek(fd, addr, SEEK_SET);
640 if (read(fd, laddr, len) == -1)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000641 return -1;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000642#endif /* USE_PROCFS */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000643
644 return 0;
645}
646
647/*
648 * like `umove' but make the additional effort of looking
649 * for a terminating zero byte.
650 */
651int
652umovestr(tcp, addr, len, laddr)
653struct tcb *tcp;
654long addr;
655int len;
656char *laddr;
657{
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000658#ifdef USE_PROCFS
John Hughesaa09c6b2001-05-15 14:53:43 +0000659#ifdef HAVE_MP_PROCFS
660 int fd = tcp->pfd_as;
661#else
662 int fd = tcp->pfd;
663#endif
664 /* Some systems (e.g. FreeBSD) can be upset if we read off the
665 end of valid memory, avoid this by trying to read up
666 to page boundaries. But we don't know what a page is (and
667 getpagesize(2) (if it exists) doesn't necessarily return
668 hardware page size). Assume all pages >= 1024 (a-historical
669 I know) */
670
671 int page = 1024; /* How to find this? */
672 int move = page - (addr & (page - 1));
673 int left = len;
674
675 lseek(fd, addr, SEEK_SET);
676
677 while (left) {
678 if (move > left) move = left;
679 if ((move = read(fd, laddr, move)) == -1)
680 return left != len ? 0 : -1;
681 if (memchr (laddr, 0, move)) break;
682 left -= move;
683 laddr += move;
684 addr += move;
685 move = page;
686 }
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000687#else /* !USE_PROCFS */
Wichert Akkerman5daa0281999-03-15 19:49:42 +0000688 int started = 0;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000689 int pid = tcp->pid;
690 int i, n, m;
691 union {
692 long val;
693 char x[sizeof(long)];
694 } u;
695
696 if (addr & (sizeof(long) - 1)) {
697 /* addr not a multiple of sizeof(long) */
698 n = addr - (addr & -sizeof(long)); /* residue */
699 addr &= -sizeof(long); /* residue */
700 errno = 0;
701 u.val = ptrace(PTRACE_PEEKDATA, pid, (char *)addr, 0);
702 if (errno) {
Wichert Akkerman5daa0281999-03-15 19:49:42 +0000703 if (started && (errno==EPERM || errno==EIO)) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000704 /* Ran into 'end of memory' - stupid "printpath" */
705 return 0;
706 }
707 perror("umovestr");
708 return -1;
709 }
Wichert Akkerman5daa0281999-03-15 19:49:42 +0000710 started = 1;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000711 memcpy(laddr, &u.x[n], m = MIN(sizeof(long)-n,len));
712 while (n & (sizeof(long) - 1))
713 if (u.x[n++] == '\0')
714 return 0;
715 addr += sizeof(long), laddr += m, len -= m;
716 }
717 while (len) {
718 errno = 0;
719 u.val = ptrace(PTRACE_PEEKDATA, pid, (char *)addr, 0);
720 if (errno) {
Wichert Akkerman5daa0281999-03-15 19:49:42 +0000721 if (started && (errno==EPERM || errno==EIO)) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000722 /* Ran into 'end of memory' - stupid "printpath" */
723 return 0;
724 }
725 perror("umovestr");
726 return -1;
727 }
Wichert Akkerman5daa0281999-03-15 19:49:42 +0000728 started = 1;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000729 memcpy(laddr, u.x, m = MIN(sizeof(long), len));
730 for (i = 0; i < sizeof(long); i++)
731 if (u.x[i] == '\0')
732 return 0;
733
734 addr += sizeof(long), laddr += m, len -= m;
735 }
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000736#endif /* !USE_PROCFS */
John Hughesaa09c6b2001-05-15 14:53:43 +0000737 return 0;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000738}
739
740#ifdef LINUX
741#ifndef SPARC
742#define PTRACE_WRITETEXT 101
743#define PTRACE_WRITEDATA 102
744#endif /* !SPARC */
745#endif /* LINUX */
746
747#ifdef SUNOS4
748
749static int
750uload(cmd, pid, addr, len, laddr)
751int cmd;
752int pid;
753long addr;
754int len;
755char *laddr;
756{
757#if 0
758 int n;
759
760 while (len) {
761 n = MIN(len, PAGSIZ);
762 n = MIN(n, ((addr + PAGSIZ) & PAGMASK) - addr);
763 if (ptrace(cmd, pid, (char *)addr, n, laddr) < 0) {
764 perror("uload: ptrace(PTRACE_WRITE, ...)");
765 return -1;
766 }
767 len -= n;
768 addr += n;
769 laddr += n;
770 }
771#else
772 int peek, poke;
773 int n, m;
774 union {
775 long val;
776 char x[sizeof(long)];
777 } u;
778
779 if (cmd == PTRACE_WRITETEXT) {
780 peek = PTRACE_PEEKTEXT;
781 poke = PTRACE_POKETEXT;
782 }
783 else {
784 peek = PTRACE_PEEKDATA;
785 poke = PTRACE_POKEDATA;
786 }
787 if (addr & (sizeof(long) - 1)) {
788 /* addr not a multiple of sizeof(long) */
789 n = addr - (addr & -sizeof(long)); /* residue */
790 addr &= -sizeof(long);
791 errno = 0;
792 u.val = ptrace(peek, pid, (char *) addr, 0);
793 if (errno) {
794 perror("uload: POKE");
795 return -1;
796 }
797 memcpy(&u.x[n], laddr, m = MIN(sizeof(long) - n, len));
798 if (ptrace(poke, pid, (char *)addr, u.val) < 0) {
799 perror("uload: POKE");
800 return -1;
801 }
802 addr += sizeof(long), laddr += m, len -= m;
803 }
804 while (len) {
805 if (len < sizeof(long))
806 u.val = ptrace(peek, pid, (char *) addr, 0);
807 memcpy(u.x, laddr, m = MIN(sizeof(long), len));
808 if (ptrace(poke, pid, (char *) addr, u.val) < 0) {
809 perror("uload: POKE");
810 return -1;
811 }
812 addr += sizeof(long), laddr += m, len -= m;
813 }
814#endif
815 return 0;
816}
817
818int
819tload(pid, addr, len, laddr)
820int pid;
821int addr, len;
822char *laddr;
823{
824 return uload(PTRACE_WRITETEXT, pid, addr, len, laddr);
825}
826
827int
828dload(pid, addr, len, laddr)
829int pid;
830int addr;
831int len;
832char *laddr;
833{
834 return uload(PTRACE_WRITEDATA, pid, addr, len, laddr);
835}
836
837#endif /* SUNOS4 */
838
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000839#ifndef USE_PROCFS
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000840
841int
842upeek(pid, off, res)
843int pid;
844long off;
845long *res;
846{
847 long val;
848
849#ifdef SUNOS4_KERNEL_ARCH_KLUDGE
850 {
851 static int is_sun4m = -1;
852 struct utsname name;
853
854 /* Round up the usual suspects. */
855 if (is_sun4m == -1) {
856 if (uname(&name) < 0) {
857 perror("upeek: uname?");
858 exit(1);
859 }
860 is_sun4m = strcmp(name.machine, "sun4m") == 0;
861 if (is_sun4m) {
862 extern struct xlat struct_user_offsets[];
863 struct xlat *x;
864
865 for (x = struct_user_offsets; x->str; x++)
866 x->val += 1024;
867 }
868 }
869 if (is_sun4m)
870 off += 1024;
871 }
872#endif /* SUNOS4_KERNEL_ARCH_KLUDGE */
873 errno = 0;
874 val = ptrace(PTRACE_PEEKUSER, pid, (char *) off, 0);
875 if (val == -1 && errno) {
876 perror("upeek: ptrace(PTRACE_PEEKUSER, ... )");
877 return -1;
878 }
879 *res = val;
880 return 0;
881}
882
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000883#endif /* !USE_PROCFS */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000884
885long
886getpc(tcp)
887struct tcb *tcp;
888{
889
890#ifdef LINUX
891 long pc;
Wichert Akkermanf90da011999-10-31 21:15:38 +0000892#if defined(I386)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000893 if (upeek(tcp->pid, 4*EIP, &pc) < 0)
894 return -1;
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +0000895#elif defined(IA64)
896 if (upeek(tcp->pid, PT_B0, &pc) < 0)
897 return -1;
Wichert Akkermanf90da011999-10-31 21:15:38 +0000898#elif defined(ARM)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000899 if (upeek(tcp->pid, 4*15, &pc) < 0)
900 return -1;
Wichert Akkermanf90da011999-10-31 21:15:38 +0000901#elif defined(POWERPC)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000902 if (upeek(tcp->pid, 4*PT_NIP, &pc) < 0)
903 return -1;
Wichert Akkermanf90da011999-10-31 21:15:38 +0000904#elif defined(M68k)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000905 if (upeek(tcp->pid, 4*PT_PC, &pc) < 0)
906 return -1;
Wichert Akkermanf90da011999-10-31 21:15:38 +0000907#elif defined(ALPHA)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000908 if (upeek(tcp->pid, REG_PC, &pc) < 0)
909 return -1;
Wichert Akkermanf90da011999-10-31 21:15:38 +0000910#elif defined(MIPS)
911 if (upeek(tcp->pid, REG_EPC, &pc) < 0)
912 return -1;
913#elif defined(SPARC)
Wichert Akkerman9ce1a631999-08-29 23:15:07 +0000914 struct regs regs;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000915 if (ptrace(PTRACE_GETREGS,tcp->pid,(char *)&regs,0) < 0)
916 return -1;
Wichert Akkerman9ce1a631999-08-29 23:15:07 +0000917 pc = regs.r_pc;
Wichert Akkerman4dc8a2a1999-12-23 14:20:14 +0000918#elif defined(S390)
919 if(upeek(tcp->pid,PT_PSWADDR,&pc) < 0)
Wichert Akkermanc1652e22001-03-27 12:17:16 +0000920#elif defined(HPPA)
921 if(upeek(tcp->pid,PT_IAOQ0,&pc) < 0)
922 return -1;
Wichert Akkerman7a0b6491999-12-23 15:08:17 +0000923#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000924 return pc;
925#endif /* LINUX */
926
927#ifdef SUNOS4
928 /*
929 * Return current program counter for `pid'
930 * Assumes PC is never 0xffffffff
931 */
932 struct regs regs;
933
934 if (ptrace(PTRACE_GETREGS, tcp->pid, (char *) &regs, 0) < 0) {
935 perror("getpc: ptrace(PTRACE_GETREGS, ...)");
936 return -1;
937 }
938 return regs.r_pc;
939#endif /* SUNOS4 */
940
941#ifdef SVR4
942 /* XXX */
943 return 0;
944#endif /* SVR4 */
945
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000946#ifdef FREEBSD
947 struct reg regs;
948 pread(tcp->pfd_reg, &regs, sizeof(regs), 0);
949 return regs.r_eip;
950#endif /* FREEBSD */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000951}
952
953void
954printcall(tcp)
955struct tcb *tcp;
956{
957
958#ifdef LINUX
959#ifdef I386
960 long eip;
961
962 if (upeek(tcp->pid, 4*EIP, &eip) < 0) {
963 tprintf("[????????] ");
964 return;
965 }
966 tprintf("[%08lx] ", eip);
Wichert Akkermanfaf72222000-02-19 23:59:03 +0000967#elif defined(IA62)
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +0000968 long ip;
969
970 if (upeek(tcp->pid, PT_B0, &ip) < 0) {
971 tprintf("[????????] ");
972 return;
973 }
974 tprintf("[%08lx] ", ip);
Wichert Akkermanfaf72222000-02-19 23:59:03 +0000975#elif defined(POWERPC)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000976 long pc;
977
978 if (upeek(tcp->pid, 4*PT_NIP, &pc) < 0) {
979 tprintf ("[????????] ");
980 return;
981 }
982 tprintf("[%08lx] ", pc);
Wichert Akkermanfaf72222000-02-19 23:59:03 +0000983#elif defined(M68k)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000984 long pc;
985
986 if (upeek(tcp->pid, 4*PT_PC, &pc) < 0) {
987 tprintf ("[????????] ");
988 return;
989 }
990 tprintf("[%08lx] ", pc);
Wichert Akkermanfaf72222000-02-19 23:59:03 +0000991#elif defined(ALPHA)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000992 long pc;
993
994 if (upeek(tcp->pid, REG_PC, &pc) < 0) {
995 tprintf ("[????????] ");
996 return;
997 }
998 tprintf("[%08lx] ", pc);
Wichert Akkermanfaf72222000-02-19 23:59:03 +0000999#elif defined(SPARC)
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001000 struct regs regs;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001001 if (ptrace(PTRACE_GETREGS,tcp->pid,(char *)&regs,0) < 0) {
1002 tprintf("[????????] ");
1003 return;
1004 }
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001005 tprintf("[%08lx] ", regs.r_pc);
Wichert Akkermanc1652e22001-03-27 12:17:16 +00001006#elif defined(HPPA)
1007 long pc;
1008
1009 if(upeek(tcp->pid,PT_IAOQ0,&pc) < 0) {
1010 tprintf ("[????????] ");
1011 return;
1012 }
1013 tprintf("[%08lx] ", pc);
Wichert Akkerman75c422b2001-04-10 10:22:50 +00001014#elif defined(MIPS)
1015 long pc;
1016
1017 if (upeek(tcp->pid, REG_EPC, &pc) < 0) {
1018 tprintf ("[????????] ");
1019 return;
1020 }
1021 tprintf("[%08lx] ", pc);
Wichert Akkermanfaf72222000-02-19 23:59:03 +00001022#endif /* !architecture */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001023#endif /* LINUX */
1024
1025#ifdef SUNOS4
1026 struct regs regs;
1027
1028 if (ptrace(PTRACE_GETREGS, tcp->pid, (char *) &regs, 0) < 0) {
1029 perror("printcall: ptrace(PTRACE_GETREGS, ...)");
1030 tprintf("[????????] ");
1031 return;
1032 }
1033 tprintf("[%08x] ", regs.r_o7);
1034#endif /* SUNOS4 */
1035
1036#ifdef SVR4
1037 /* XXX */
1038 tprintf("[????????] ");
1039#endif
1040
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001041#ifdef FREEBSD
1042 struct reg regs;
1043 pread(tcp->pfd_reg, &regs, sizeof(regs), 0);
1044 tprintf("[%08x] ", regs.r_eip);
1045#endif /* FREEBSD */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001046}
1047
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001048#ifndef USE_PROCFS
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001049
1050int
1051setbpt(tcp)
1052struct tcb *tcp;
1053{
1054
1055#ifdef LINUX
1056#ifdef SPARC
1057 /* We simply use the SunOS breakpoint code. */
1058
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001059 struct regs regs;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001060#define LOOPA 0x30800000 /* ba,a 0 */
1061
1062 if (tcp->flags & TCB_BPTSET) {
1063 fprintf(stderr, "PANIC: TCB already set in pid %u\n", tcp->pid);
1064 return -1;
1065 }
1066 if (ptrace(PTRACE_GETREGS, tcp->pid, (char *)&regs, 0) < 0) {
1067 perror("setbpt: ptrace(PTRACE_GETREGS, ...)");
1068 return -1;
1069 }
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001070 tcp->baddr = regs.r_o7 + 8;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001071 errno = 0;
1072 tcp->inst[0] = ptrace(PTRACE_PEEKTEXT, tcp->pid, (char *)tcp->baddr, 0);
1073 if(errno) {
1074 perror("setbpt: ptrace(PTRACE_PEEKTEXT, ...)");
1075 return -1;
1076 }
1077
1078 /*
1079 * XXX - BRUTAL MODE ON
1080 * We cannot set a real BPT in the child, since it will not be
1081 * traced at the moment it will reach the trap and would probably
1082 * die with a core dump.
1083 * Thus, we are force our way in by taking out two instructions
1084 * and insert an eternal loop instead, in expectance of the SIGSTOP
1085 * generated by out PTRACE_ATTACH.
1086 * Of cause, if we evaporate ourselves in the middle of all this...
1087 */
1088 errno = 0;
1089 ptrace(PTRACE_POKETEXT, tcp->pid, (char *) tcp->baddr, LOOPA);
1090 if(errno) {
1091 perror("setbpt: ptrace(PTRACE_POKETEXT, ...)");
1092 return -1;
1093 }
1094 tcp->flags |= TCB_BPTSET;
1095
1096#else /* !SPARC */
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00001097#ifdef IA64
1098 /*
1099 * Our strategy here is to replace the bundle that contained
1100 * the clone() syscall with a bundle of the form:
1101 *
1102 * { 1: br 1b; br 1b; br 1b }
1103 *
1104 * This ensures that the newly forked child will loop
1105 * endlessly until we've got a chance to attach to it.
1106 */
1107 {
1108# define LOOP0 0x0000100000000017
1109# define LOOP1 0x4000000000200000
1110 unsigned long addr, ipsr;
1111 pid_t pid;
1112
1113 pid = tcp->pid;
1114 if (upeek(pid, PT_CR_IPSR, &ipsr) < 0)
1115 return -1;
1116 if (upeek(pid, PT_CR_IIP, &addr) < 0)
1117 return -1;
1118 tcp->baddr = addr | ((ipsr >> 41) & 0x3); /* store "ri" in low two bits */
1119
1120 errno = 0;
1121 tcp->inst[0] = ptrace(PTRACE_PEEKTEXT, pid, (char *) addr + 0, 0);
1122 tcp->inst[1] = ptrace(PTRACE_PEEKTEXT, pid, (char *) addr + 8, 0);
1123 if (errno) {
1124 perror("setbpt: ptrace(PTRACE_PEEKTEXT, ...)");
1125 return -1;
1126 }
1127
1128 errno = 0;
1129 ptrace(PTRACE_POKETEXT, pid, (char *) addr + 0, LOOP0);
1130 ptrace(PTRACE_POKETEXT, pid, (char *) addr + 8, LOOP1);
1131 if (errno) {
1132 perror("setbpt: ptrace(PTRACE_POKETEXT, ...)");
1133 return -1;
1134 }
1135 tcp->flags |= TCB_BPTSET;
1136 }
1137#else /* !IA64 */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001138
1139#if defined (I386)
1140#define LOOP 0x0000feeb
1141#elif defined (M68K)
1142#define LOOP 0x60fe0000
1143#elif defined (ALPHA)
Wichert Akkerman4dc8a2a1999-12-23 14:20:14 +00001144#define LOOP 0xc3ffffff
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001145#elif defined (POWERPC)
Wichert Akkerman4dc8a2a1999-12-23 14:20:14 +00001146#define LOOP 0x0000feeb
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001147#elif defined(ARM)
Wichert Akkerman9a8a37f1999-12-24 23:19:31 +00001148#define LOOP 0xEAFFFFFE
Wichert Akkermanf90da011999-10-31 21:15:38 +00001149#elif defined(MIPS)
Wichert Akkerman4dc8a2a1999-12-23 14:20:14 +00001150#define LOOP 0x1000ffff
1151#elif defined(S390)
1152#define LOOP 0xa7f40000 /* BRC 15,0 */
Wichert Akkermanc1652e22001-03-27 12:17:16 +00001153#elif defined(HPPA)
1154#define LOOP 0xe81f1ff7 /* b,l,n <loc>,r0 */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001155#else
1156#error unknown architecture
1157#endif
1158
1159 if (tcp->flags & TCB_BPTSET) {
1160 fprintf(stderr, "PANIC: bpt already set in pid %u\n", tcp->pid);
1161 return -1;
1162 }
1163#if defined (I386)
1164 if (upeek(tcp->pid, 4*EIP, &tcp->baddr) < 0)
1165 return -1;
1166#elif defined (M68K)
1167 if (upeek(tcp->pid, 4*PT_PC, &tcp->baddr) < 0)
1168 return -1;
1169#elif defined (ALPHA)
1170 return -1;
1171#elif defined (ARM)
1172 return -1;
Wichert Akkermanf90da011999-10-31 21:15:38 +00001173#elif defined (MIPS)
1174 return -1; /* FIXME: I do not know what i do - Flo */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001175#elif defined (POWERPC)
1176 if (upeek(tcp->pid, 4*PT_NIP, &tcp->baddr) < 0)
1177 return -1;
Wichert Akkerman4dc8a2a1999-12-23 14:20:14 +00001178#elif defined(S390)
1179 if (upeek(tcp->pid,PT_PSWADDR, &tcp->baddr) < 0)
1180 return -1;
Wichert Akkermanc1652e22001-03-27 12:17:16 +00001181#elif defined(HPPA)
1182 if (upeek(tcp->pid, PT_IAOQ0, &tcp->baddr) < 0)
1183 return -1;
1184 tcp->baddr &= ~0x03;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001185#else
1186#error unknown architecture
1187#endif
1188 if (debug)
1189 fprintf(stderr, "[%d] setting bpt at %lx\n", tcp->pid, tcp->baddr);
1190 tcp->inst[0] = ptrace(PTRACE_PEEKTEXT, tcp->pid, (char *) tcp->baddr, 0);
1191 if (errno) {
1192 perror("setbpt: ptrace(PTRACE_PEEKTEXT, ...)");
1193 return -1;
1194 }
1195 ptrace(PTRACE_POKETEXT, tcp->pid, (char *) tcp->baddr, LOOP);
1196 if (errno) {
1197 perror("setbpt: ptrace(PTRACE_POKETEXT, ...)");
1198 return -1;
1199 }
1200 tcp->flags |= TCB_BPTSET;
1201
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00001202#endif /* !IA64 */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001203#endif /* SPARC */
1204#endif /* LINUX */
1205
1206#ifdef SUNOS4
1207#ifdef SPARC /* This code is slightly sparc specific */
1208
Wichert Akkermane6f876c1999-06-22 15:28:30 +00001209 struct regs regs;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001210#define BPT 0x91d02001 /* ta 1 */
1211#define LOOP 0x10800000 /* ba 0 */
1212#define LOOPA 0x30800000 /* ba,a 0 */
1213#define NOP 0x01000000
1214#if LOOPA
1215 static int loopdeloop[1] = {LOOPA};
1216#else
1217 static int loopdeloop[2] = {LOOP, NOP};
1218#endif
1219
1220 if (tcp->flags & TCB_BPTSET) {
1221 fprintf(stderr, "PANIC: TCB already set in pid %u\n", tcp->pid);
1222 return -1;
1223 }
1224 if (ptrace(PTRACE_GETREGS, tcp->pid, (char *)&regs, 0) < 0) {
1225 perror("setbpt: ptrace(PTRACE_GETREGS, ...)");
1226 return -1;
1227 }
1228 tcp->baddr = regs.r_o7 + 8;
1229 if (ptrace(PTRACE_READTEXT, tcp->pid, (char *)tcp->baddr,
1230 sizeof tcp->inst, (char *)tcp->inst) < 0) {
1231 perror("setbpt: ptrace(PTRACE_READTEXT, ...)");
1232 return -1;
1233 }
1234
1235 /*
1236 * XXX - BRUTAL MODE ON
1237 * We cannot set a real BPT in the child, since it will not be
1238 * traced at the moment it will reach the trap and would probably
1239 * die with a core dump.
1240 * Thus, we are force our way in by taking out two instructions
1241 * and insert an eternal loop in stead, in expectance of the SIGSTOP
1242 * generated by out PTRACE_ATTACH.
1243 * Of cause, if we evaporate ourselves in the middle of all this...
1244 */
1245 if (ptrace(PTRACE_WRITETEXT, tcp->pid, (char *) tcp->baddr,
1246 sizeof loopdeloop, (char *) loopdeloop) < 0) {
1247 perror("setbpt: ptrace(PTRACE_WRITETEXT, ...)");
1248 return -1;
1249 }
1250 tcp->flags |= TCB_BPTSET;
1251
1252#endif /* SPARC */
1253#endif /* SUNOS4 */
1254
1255 return 0;
1256}
1257
1258int
1259clearbpt(tcp)
1260struct tcb *tcp;
1261{
1262
1263#ifdef LINUX
Wichert Akkermanfaf72222000-02-19 23:59:03 +00001264#if defined(I386)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001265 long eip;
Wichert Akkermanfaf72222000-02-19 23:59:03 +00001266#elif defined(POWERPC)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001267 long pc;
Wichert Akkermanfaf72222000-02-19 23:59:03 +00001268#elif defined(M68K)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001269 long pc;
Wichert Akkermanfaf72222000-02-19 23:59:03 +00001270#elif defined(ALPHA)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001271 long pc;
Wichert Akkermanc1652e22001-03-27 12:17:16 +00001272#elif defined(HPPA)
1273 long iaoq;
Wichert Akkermanfaf72222000-02-19 23:59:03 +00001274#endif /* architecture */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001275
1276#ifdef SPARC
1277 /* Again, we borrow the SunOS breakpoint code. */
1278 if (!(tcp->flags & TCB_BPTSET)) {
1279 fprintf(stderr, "PANIC: TCB not set in pid %u\n", tcp->pid);
1280 return -1;
1281 }
1282 errno = 0;
1283 ptrace(PTRACE_POKETEXT, tcp->pid, (char *) tcp->baddr, tcp->inst[0]);
1284 if(errno) {
1285 perror("clearbtp: ptrace(PTRACE_POKETEXT, ...)");
1286 return -1;
1287 }
1288 tcp->flags &= ~TCB_BPTSET;
Wichert Akkermanfaf72222000-02-19 23:59:03 +00001289#elif defined(IA64)
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00001290 {
1291 unsigned long addr, ipsr;
1292 pid_t pid;
1293
1294 pid = tcp->pid;
1295
1296 if (upeek(pid, PT_CR_IPSR, &ipsr) < 0)
1297 return -1;
1298 if (upeek(pid, PT_CR_IIP, &addr) < 0)
1299 return -1;
1300
1301 /* restore original bundle: */
1302 errno = 0;
1303 ptrace(PTRACE_POKETEXT, pid, (char *) addr + 0, tcp->inst[0]);
1304 ptrace(PTRACE_POKETEXT, pid, (char *) addr + 8, tcp->inst[1]);
1305 if (errno) {
1306 perror("clearbpt: ptrace(PTRACE_POKETEXT, ...)");
1307 return -1;
1308 }
1309
1310 /* restore original "ri" in ipsr: */
1311 ipsr = (ipsr & ~(0x3ul << 41)) | ((tcp->baddr & 0x3) << 41);
1312 errno = 0;
1313 ptrace(PTRACE_POKEUSER, pid, (char *) PT_CR_IPSR, ipsr);
1314 if (errno) {
1315 perror("clrbpt: ptrace(PTRACE_POKEUSER, ...)");
1316 return -1;
1317 }
1318
1319 tcp->flags &= ~TCB_BPTSET;
1320
1321 if (addr != (tcp->baddr & ~0x3)) {
1322 /* the breakpoint has not been reached yet. */
1323 if (debug)
1324 fprintf(stderr, "NOTE: PC not at bpt (pc %#lx baddr %#lx)\n",
1325 addr, tcp->baddr);
1326 return 0;
1327 }
1328 }
Wichert Akkermanfaf72222000-02-19 23:59:03 +00001329#else /* !IA64 && ! SPARC */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001330
1331 if (debug)
1332 fprintf(stderr, "[%d] clearing bpt\n", tcp->pid);
1333 if (!(tcp->flags & TCB_BPTSET)) {
1334 fprintf(stderr, "PANIC: TCB not set in pid %u\n", tcp->pid);
1335 return -1;
1336 }
1337 errno = 0;
1338 ptrace(PTRACE_POKETEXT, tcp->pid, (char *) tcp->baddr, tcp->inst[0]);
1339 if (errno) {
1340 perror("clearbtp: ptrace(PTRACE_POKETEXT, ...)");
1341 return -1;
1342 }
1343 tcp->flags &= ~TCB_BPTSET;
1344
1345#ifdef I386
1346 if (upeek(tcp->pid, 4*EIP, &eip) < 0)
1347 return -1;
1348 if (eip != tcp->baddr) {
1349 /* The breakpoint has not been reached yet. */
1350 if (debug)
1351 fprintf(stderr,
1352 "NOTE: PC not at bpt (pc %#lx baddr %#lx)\n",
1353 eip, tcp->baddr);
1354 return 0;
1355 }
Wichert Akkermanc7926982000-04-10 22:22:31 +00001356#elif defined(POWERPC)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001357 if (upeek(tcp->pid, 4*PT_NIP, &pc) < 0)
1358 return -1;
1359 if (pc != tcp->baddr) {
1360 /* The breakpoint has not been reached yet. */
1361 if (debug)
1362 fprintf(stderr, "NOTE: PC not at bpt (pc %#lx baddr %#lx)\n",
1363 pc, tcp->baddr);
1364 return 0;
1365 }
Wichert Akkermanfaf72222000-02-19 23:59:03 +00001366#elif defined(M68K)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001367 if (upeek(tcp->pid, 4*PT_PC, &pc) < 0)
1368 return -1;
1369 if (pc != tcp->baddr) {
1370 /* The breakpoint has not been reached yet. */
1371 if (debug)
1372 fprintf(stderr, "NOTE: PC not at bpt (pc %#lx baddr %#lx)\n",
1373 pc, tcp->baddr);
1374 return 0;
1375 }
Wichert Akkermanfaf72222000-02-19 23:59:03 +00001376#elif defined(ALPHA)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001377 if (upeek(tcp->pid, REG_PC, &pc) < 0)
1378 return -1;
1379 if (pc != tcp->baddr) {
1380 /* The breakpoint has not been reached yet. */
1381 if (debug)
1382 fprintf(stderr, "NOTE: PC not at bpt (pc %#lx baddr %#lx)\n",
1383 pc, tcp->baddr);
1384 return 0;
1385 }
Wichert Akkermanc1652e22001-03-27 12:17:16 +00001386#elif defined(HPPA)
1387 if (upeek(tcp->pid, PT_IAOQ0, &iaoq) < 0)
1388 return -1;
1389 iaoq &= ~0x03;
1390 if (iaoq != tcp->baddr && iaoq != tcp->baddr + 4) {
1391 /* The breakpoint has not been reached yet. */
1392 if (debug)
1393 fprintf(stderr, "NOTE: PC not at bpt (iaoq %#lx baddr %#lx)\n",
1394 iaoq, tcp->baddr);
1395 return 0;
1396 }
1397 iaoq = tcp->baddr | 3;
1398 /* We should be pointing at a 'ldi -1000,r1' in glibc, so it is
1399 * safe to set both IAOQ0 and IAOQ1 to that so the PSW N bit
1400 * has no significant effect.
1401 */
1402 ptrace(PTRACE_POKEUSER, tcp->pid, (void *)PT_IAOQ0, iaoq);
1403 ptrace(PTRACE_POKEUSER, tcp->pid, (void *)PT_IAOQ1, iaoq);
Wichert Akkermanfaf72222000-02-19 23:59:03 +00001404#endif /* arch */
1405#endif /* !SPARC && !IA64 */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001406#endif /* LINUX */
1407
1408#ifdef SUNOS4
1409#ifdef SPARC
1410
1411#if !LOOPA
Wichert Akkermane6f876c1999-06-22 15:28:30 +00001412 struct regs regs;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001413#endif
1414
1415 if (!(tcp->flags & TCB_BPTSET)) {
1416 fprintf(stderr, "PANIC: TCB not set in pid %u\n", tcp->pid);
1417 return -1;
1418 }
1419 if (ptrace(PTRACE_WRITETEXT, tcp->pid, (char *) tcp->baddr,
1420 sizeof tcp->inst, (char *) tcp->inst) < 0) {
1421 perror("clearbtp: ptrace(PTRACE_WRITETEXT, ...)");
1422 return -1;
1423 }
1424 tcp->flags &= ~TCB_BPTSET;
1425
1426#if !LOOPA
1427 /*
1428 * Since we don't have a single instruction breakpoint, we may have
1429 * to adjust the program counter after removing the our `breakpoint'.
1430 */
1431 if (ptrace(PTRACE_GETREGS, tcp->pid, (char *)&regs, 0) < 0) {
1432 perror("clearbpt: ptrace(PTRACE_GETREGS, ...)");
1433 return -1;
1434 }
1435 if ((regs.r_pc < tcp->baddr) ||
1436 (regs.r_pc > tcp->baddr + 4)) {
1437 /* The breakpoint has not been reached yet */
1438 if (debug)
1439 fprintf(stderr,
1440 "NOTE: PC not at bpt (pc %#x baddr %#x)\n",
1441 regs.r_pc, tcp->parent->baddr);
1442 return 0;
1443 }
1444 if (regs.r_pc != tcp->baddr)
1445 if (debug)
1446 fprintf(stderr, "NOTE: PC adjusted (%#x -> %#x\n",
1447 regs.r_pc, tcp->baddr);
1448
1449 regs.r_pc = tcp->baddr;
1450 if (ptrace(PTRACE_SETREGS, tcp->pid, (char *)&regs, 0) < 0) {
1451 perror("clearbpt: ptrace(PTRACE_SETREGS, ...)");
1452 return -1;
1453 }
1454#endif /* LOOPA */
1455#endif /* SPARC */
1456#endif /* SUNOS4 */
1457
1458 return 0;
1459}
1460
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001461#endif /* !USE_PROCFS */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001462
1463#ifdef SUNOS4
1464
1465static int
1466getex(pid, hdr)
1467int pid;
1468struct exec *hdr;
1469{
1470 int n;
1471
1472 for (n = 0; n < sizeof *hdr; n += 4) {
1473 long res;
1474 if (upeek(pid, uoff(u_exdata) + n, &res) < 0)
1475 return -1;
1476 memcpy(((char *) hdr) + n, &res, 4);
1477 }
1478 if (debug) {
1479 fprintf(stderr, "[struct exec: magic: %o version %u Mach %o\n",
1480 hdr->a_magic, hdr->a_toolversion, hdr->a_machtype);
1481 fprintf(stderr, "Text %lu Data %lu Bss %lu Syms %lu Entry %#lx]\n",
1482 hdr->a_text, hdr->a_data, hdr->a_bss, hdr->a_syms, hdr->a_entry);
1483 }
1484 return 0;
1485}
1486
1487int
1488fixvfork(tcp)
1489struct tcb *tcp;
1490{
1491 int pid = tcp->pid;
1492 /*
1493 * Change `vfork' in a freshly exec'ed dynamically linked
1494 * executable's (internal) symbol table to plain old `fork'
1495 */
1496
1497 struct exec hdr;
1498 struct link_dynamic dyn;
1499 struct link_dynamic_2 ld;
1500 char *strtab, *cp;
1501
1502 if (getex(pid, &hdr) < 0)
1503 return -1;
1504 if (!hdr.a_dynamic)
1505 return -1;
1506
1507 if (umove(tcp, (int) N_DATADDR(hdr), &dyn) < 0) {
1508 fprintf(stderr, "Cannot read DYNAMIC\n");
1509 return -1;
1510 }
1511 if (umove(tcp, (int) dyn.ld_un.ld_2, &ld) < 0) {
1512 fprintf(stderr, "Cannot read link_dynamic_2\n");
1513 return -1;
1514 }
1515 if ((strtab = malloc((unsigned)ld.ld_symb_size)) == NULL) {
1516 fprintf(stderr, "fixvfork: out of memory\n");
1517 return -1;
1518 }
1519 if (umoven(tcp, (int)ld.ld_symbols+(int)N_TXTADDR(hdr),
1520 (int)ld.ld_symb_size, strtab) < 0)
1521 goto err;
1522
1523#if 0
1524 for (cp = strtab; cp < strtab + ld.ld_symb_size; ) {
1525 fprintf(stderr, "[symbol: %s]\n", cp);
1526 cp += strlen(cp)+1;
1527 }
1528 return 0;
1529#endif
1530 for (cp = strtab; cp < strtab + ld.ld_symb_size; ) {
1531 if (strcmp(cp, "_vfork") == 0) {
1532 if (debug)
1533 fprintf(stderr, "fixvfork: FOUND _vfork\n");
1534 strcpy(cp, "_fork");
1535 break;
1536 }
1537 cp += strlen(cp)+1;
1538 }
1539 if (cp < strtab + ld.ld_symb_size)
1540 /*
1541 * Write entire symbol table back to avoid
1542 * memory alignment bugs in ptrace
1543 */
1544 if (tload(pid, (int)ld.ld_symbols+(int)N_TXTADDR(hdr),
1545 (int)ld.ld_symb_size, strtab) < 0)
1546 goto err;
1547
1548 free(strtab);
1549 return 0;
1550
1551err:
1552 free(strtab);
1553 return -1;
1554}
1555
1556#endif /* SUNOS4 */