blob: c59d25a7e0ded63e239fddb0d6b381bc708999e7 [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>
John Hughes1d08dcf2001-07-10 13:48:44 +000041#if HAVE_SYS_UIO_H
42#include <sys/uio.h>
43#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +000044#ifdef SUNOS4
45#include <machine/reg.h>
46#include <a.out.h>
47#include <link.h>
48#endif /* SUNOS4 */
Wichert Akkerman36915a11999-07-13 15:45:02 +000049
Wichert Akkerman43a74822000-06-27 17:33:32 +000050#if defined(linux) && (__GLIBC__ < 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ < 1))
Wichert Akkerman36915a11999-07-13 15:45:02 +000051#include <linux/ptrace.h>
52#endif
53
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +000054#if defined(LINUX) && defined(IA64)
55#include <asm/ptrace_offsets.h>
56#endif
57
Wichert Akkerman36915a11999-07-13 15:45:02 +000058#ifdef HAVE_SYS_REG_H
59#include <sys/reg.h>
Wichert Akkerman76baf7c1999-02-19 00:21:36 +000060# define PTRACE_PEEKUSR PTRACE_PEEKUSER
Wichert Akkermanfaf72222000-02-19 23:59:03 +000061#elif defined(HAVE_LINUX_PTRACE_H)
62#undef PTRACE_SYSCALL
63#include <linux/ptrace.h>
Wichert Akkerman2e2553a1999-05-09 00:29:58 +000064#endif
65
Wichert Akkerman76baf7c1999-02-19 00:21:36 +000066#ifdef SUNOS4_KERNEL_ARCH_KLUDGE
67#include <sys/utsname.h>
68#endif /* SUNOS4_KERNEL_ARCH_KLUDGE */
69
Wichert Akkerman9ce1a631999-08-29 23:15:07 +000070#if defined(LINUX) && defined(SPARC)
71
72#include <asm/reg.h>
73
74#if !defined(__GLIBC__)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +000075
76#include <linux/unistd.h>
77
78#define _hack_syscall5(type,name,type1,arg1,type2,arg2,type3,arg3,type4,arg4,\
79 type5,arg5,syscall) \
80type name (type1 arg1,type2 arg2,type3 arg3,type4 arg4,type5 arg5) \
81{ \
82 long __res; \
83\
84__asm__ volatile ("or %%g0, %1, %%o0\n\t" \
85 "or %%g0, %2, %%o1\n\t" \
86 "or %%g0, %3, %%o2\n\t" \
87 "or %%g0, %4, %%o3\n\t" \
88 "or %%g0, %5, %%o4\n\t" \
89 "or %%g0, %6, %%g1\n\t" \
90 "t 0x10\n\t" \
91 "bcc 1f\n\t" \
92 "or %%g0, %%o0, %0\n\t" \
93 "sub %%g0, %%o0, %0\n\t" \
94 "1:\n\t" \
95 : "=r" (__res) \
96 : "0" ((long)(arg1)),"1" ((long)(arg2)), \
97 "2" ((long)(arg3)),"3" ((long)(arg4)),"4" ((long)(arg5)), \
98 "i" (__NR_##syscall) \
99 : "g1", "o0", "o1", "o2", "o3", "o4"); \
100if (__res>=0) \
101 return (type) __res; \
102errno = -__res; \
103return -1; \
104}
105
106static _hack_syscall5(int,_ptrace,int,__request,int,__pid,int,__addr,int,__data,int,__addr2,ptrace)
107
108#define _ptrace
109
110#endif
111
Wichert Akkerman9ce1a631999-08-29 23:15:07 +0000112#endif
113
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000114/* macros */
115#ifndef MAX
116#define MAX(a,b) (((a) > (b)) ? (a) : (b))
117#endif
118#ifndef MIN
119#define MIN(a,b) (((a) < (b)) ? (a) : (b))
120#endif
121
122void
123tv_tv(tv, a, b)
124struct timeval *tv;
125int a;
126int b;
127{
128 tv->tv_sec = a;
129 tv->tv_usec = b;
130}
131
132int
133tv_nz(a)
134struct timeval *a;
135{
136 return a->tv_sec || a->tv_usec;
137}
138
139int
140tv_cmp(a, b)
141struct timeval *a, *b;
142{
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 if (a->tv_sec > b->tv_sec
147 || (a->tv_sec == b->tv_sec && a->tv_usec > b->tv_usec))
148 return 1;
149 return 0;
150}
151
152double
153tv_float(tv)
154struct timeval *tv;
155{
156 return tv->tv_sec + tv->tv_usec/1000000.0;
157}
158
159void
160tv_add(tv, a, b)
161struct timeval *tv, *a, *b;
162{
163 tv->tv_sec = a->tv_sec + b->tv_sec;
164 tv->tv_usec = a->tv_usec + b->tv_usec;
165 if (tv->tv_usec > 1000000) {
166 tv->tv_sec++;
167 tv->tv_usec -= 1000000;
168 }
169}
170
171void
172tv_sub(tv, a, b)
173struct timeval *tv, *a, *b;
174{
175 tv->tv_sec = a->tv_sec - b->tv_sec;
176 tv->tv_usec = a->tv_usec - b->tv_usec;
177 if (((long) tv->tv_usec) < 0) {
178 tv->tv_sec--;
179 tv->tv_usec += 1000000;
180 }
181}
182
183void
184tv_div(tv, a, n)
185struct timeval *tv, *a;
186int n;
187{
188 tv->tv_usec = (a->tv_sec % n * 1000000 + a->tv_usec + n / 2) / n;
189 tv->tv_sec = a->tv_sec / n + tv->tv_usec / 1000000;
190 tv->tv_usec %= 1000000;
191}
192
193void
194tv_mul(tv, a, n)
195struct timeval *tv, *a;
196int n;
197{
198 tv->tv_usec = a->tv_usec * n;
199 tv->tv_sec = a->tv_sec * n + a->tv_usec / 1000000;
200 tv->tv_usec %= 1000000;
201}
202
203char *
204xlookup(xlat, val)
205struct xlat *xlat;
206int val;
207{
208 for (; xlat->str != NULL; xlat++)
209 if (xlat->val == val)
210 return xlat->str;
211 return NULL;
212}
213
214/*
215 * Print entry in struct xlat table, if there.
216 */
217void
218printxval(xlat, val, dflt)
219struct xlat *xlat;
220int val;
221char *dflt;
222{
223 char *str = xlookup(xlat, val);
224
225 if (str)
226 tprintf("%s", str);
227 else
228 tprintf("%#x /* %s */", val, dflt);
229}
230
231/*
232 * Interpret `xlat' as an array of flags
233 * print the entries whose bits are on in `flags'
234 * return # of flags printed.
235 */
236int
237addflags(xlat, flags)
238struct xlat *xlat;
239int flags;
240{
241 int n;
242
243 for (n = 0; xlat->str; xlat++) {
244 if (xlat->val && (flags & xlat->val) == xlat->val) {
245 tprintf("|%s", xlat->str);
246 flags &= ~xlat->val;
247 n++;
248 }
249 }
250 if (flags) {
251 tprintf("|%#x", flags);
252 n++;
253 }
254 return n;
255}
256
257int
258printflags(xlat, flags)
259struct xlat *xlat;
260int flags;
261{
262 int n;
263 char *sep;
264
265 if (flags == 0 && xlat->val == 0) {
266 tprintf("%s", xlat->str);
267 return 1;
268 }
269
270 sep = "";
271 for (n = 0; xlat->str; xlat++) {
272 if (xlat->val && (flags & xlat->val) == xlat->val) {
273 tprintf("%s%s", sep, xlat->str);
274 flags &= ~xlat->val;
275 sep = "|";
276 n++;
277 }
278 }
279 if (flags) {
280 tprintf("%s%#x", sep, flags);
281 n++;
282 }
283 return n;
284}
285
286void
287printnum(tcp, addr, fmt)
288struct tcb *tcp;
289long addr;
290char *fmt;
291{
292 int num;
293
294 if (!addr) {
295 tprintf("NULL");
296 return;
297 }
298 if (umove(tcp, addr, &num) < 0) {
299 tprintf("%#lx", addr);
300 return;
301 }
302 tprintf("[");
303 tprintf(fmt, num);
304 tprintf("]");
305}
306
307static char path[MAXPATHLEN + 1];
308
309void
310string_quote(str)
311char *str;
312{
313 char buf[2 * MAXPATHLEN + 1];
314 char *s;
315
316 if (!strpbrk(str, "\"\'\\")) {
317 tprintf("\"%s\"", str);
318 return;
319 }
320 for (s = buf; *str; str++) {
321 switch (*str) {
322 case '\"': case '\'': case '\\':
323 *s++ = '\\'; *s++ = *str; break;
324 default:
325 *s++ = *str; break;
326 }
327 }
328 *s = '\0';
329 tprintf("\"%s\"", buf);
330}
331
332void
333printpath(tcp, addr)
334struct tcb *tcp;
335long addr;
336{
337 if (umovestr(tcp, addr, MAXPATHLEN, path) < 0)
338 tprintf("%#lx", addr);
339 else
340 string_quote(path);
341 return;
342}
343
344void
345printpathn(tcp, addr, n)
346struct tcb *tcp;
347long addr;
348int n;
349{
350 if (umovestr(tcp, addr, n, path) < 0)
351 tprintf("%#lx", addr);
352 else {
353 path[n] = '\0';
354 string_quote(path);
355 }
356}
357
358void
359printstr(tcp, addr, len)
360struct tcb *tcp;
361long addr;
362int len;
363{
364 static unsigned char *str = NULL;
365 static char *outstr;
366 int i, n, c, usehex;
367 char *s, *outend;
368
369 if (!addr) {
370 tprintf("NULL");
371 return;
372 }
373 if (!str) {
374 if ((str = malloc(max_strlen)) == NULL
375 || (outstr = malloc(2*max_strlen)) == NULL) {
376 fprintf(stderr, "printstr: no memory\n");
377 tprintf("%#lx", addr);
378 return;
379 }
380 }
Wichert Akkerman2e2553a1999-05-09 00:29:58 +0000381 outend = outstr + max_strlen * 2 - 10;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000382 if (len < 0) {
383 n = max_strlen;
384 if (umovestr(tcp, addr, n, (char *) str) < 0) {
385 tprintf("%#lx", addr);
386 return;
387 }
388 }
389 else {
390 n = MIN(len, max_strlen);
391 if (umoven(tcp, addr, n, (char *) str) < 0) {
392 tprintf("%#lx", addr);
393 return;
394 }
395 }
396
397 usehex = 0;
398 if (xflag > 1)
399 usehex = 1;
400 else if (xflag) {
401 for (i = 0; i < n; i++) {
402 c = str[i];
403 if (len < 0 && c == '\0')
404 break;
405 if (!isprint(c) && !isspace(c)) {
406 usehex = 1;
407 break;
408 }
409 }
410 }
411
412 s = outstr;
413 *s++ = '\"';
414
415 if (usehex) {
416 for (i = 0; i < n; i++) {
417 c = str[i];
418 if (len < 0 && c == '\0')
419 break;
420 sprintf(s, "\\x%02x", c);
421 s += 4;
422 if (s > outend)
423 break;
424 }
425 }
426 else {
427 for (i = 0; i < n; i++) {
428 c = str[i];
429 if (len < 0 && c == '\0')
430 break;
431 switch (c) {
432 case '\"': case '\'': case '\\':
433 *s++ = '\\'; *s++ = c; break;
434 case '\f':
435 *s++ = '\\'; *s++ = 'f'; break;
436 case '\n':
437 *s++ = '\\'; *s++ = 'n'; break;
438 case '\r':
439 *s++ = '\\'; *s++ = 'r'; break;
440 case '\t':
441 *s++ = '\\'; *s++ = 't'; break;
442 case '\v':
443 *s++ = '\\'; *s++ = 'v'; break;
444 default:
445 if (isprint(c))
446 *s++ = c;
447 else if (i < n - 1 && isdigit(str[i + 1])) {
448 sprintf(s, "\\%03o", c);
449 s += 4;
450 }
451 else {
452 sprintf(s, "\\%o", c);
453 s += strlen(s);
454 }
455 break;
456 }
457 if (s > outend)
458 break;
459 }
460 }
461
462 *s++ = '\"';
463 if (i < len || (len < 0 && (i == n || s > outend))) {
464 *s++ = '.'; *s++ = '.'; *s++ = '.';
465 }
466 *s = '\0';
467 tprintf("%s", outstr);
468}
469
John Hughes1d08dcf2001-07-10 13:48:44 +0000470#if HAVE_SYS_UIO_H
471void
472dumpiov(tcp, len, addr)
473struct tcb * tcp;
474int len;
475long addr;
476{
477 struct iovec *iov;
478 int i;
479
480
481 if ((iov = (struct iovec *) malloc(len * sizeof *iov)) == NULL) {
482 fprintf(stderr, "dump: No memory");
483 return;
484 }
485 if (umoven(tcp, addr,
486 len * sizeof *iov, (char *) iov) >= 0) {
487
488 for (i = 0; i < len; i++) {
489 /* include the buffer number to make it easy to
490 * match up the trace with the source */
491 tprintf(" * %lu bytes in buffer %d\n",
492 (unsigned long)iov[i].iov_len, i);
493 dumpstr(tcp, (long) iov[i].iov_base,
494 iov[i].iov_len);
495 }
496 }
497 free((char *) iov);
498
499}
500#endif
501
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000502void
503dumpstr(tcp, addr, len)
504struct tcb *tcp;
505long addr;
506int len;
507{
508 static int strsize = -1;
509 static unsigned char *str;
510 static char outstr[80];
511 char *s;
512 int i, j;
513
514 if (strsize < len) {
515 if (str)
516 free(str);
517 if ((str = malloc(len)) == NULL) {
518 fprintf(stderr, "dump: no memory\n");
519 return;
520 }
521 strsize = len;
522 }
523
524 if (umoven(tcp, addr, len, (char *) str) < 0)
525 return;
526
527 for (i = 0; i < len; i += 16) {
528 s = outstr;
529 sprintf(s, " | %05x ", i);
530 s += 9;
531 for (j = 0; j < 16; j++) {
532 if (j == 8)
533 *s++ = ' ';
534 if (i + j < len) {
535 sprintf(s, " %02x", str[i + j]);
536 s += 3;
537 }
538 else {
539 *s++ = ' '; *s++ = ' '; *s++ = ' ';
540 }
541 }
542 *s++ = ' '; *s++ = ' ';
543 for (j = 0; j < 16; j++) {
544 if (j == 8)
545 *s++ = ' ';
546 if (i + j < len) {
547 if (isprint(str[i + j]))
548 *s++ = str[i + j];
549 else
550 *s++ = '.';
551 }
552 else
553 *s++ = ' ';
554 }
555 tprintf("%s |\n", outstr);
556 }
557}
558
559#define PAGMASK (~(PAGSIZ - 1))
560/*
561 * move `len' bytes of data from process `pid'
562 * at address `addr' to our space at `laddr'
563 */
564int
565umoven(tcp, addr, len, laddr)
566struct tcb *tcp;
567long addr;
568int len;
569char *laddr;
570{
571
572#ifdef LINUX
573 int pid = tcp->pid;
574 int n, m;
Wichert Akkerman5daa0281999-03-15 19:49:42 +0000575 int started = 0;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000576 union {
577 long val;
578 char x[sizeof(long)];
579 } u;
580
581 if (addr & (sizeof(long) - 1)) {
582 /* addr not a multiple of sizeof(long) */
583 n = addr - (addr & -sizeof(long)); /* residue */
584 addr &= -sizeof(long); /* residue */
585 errno = 0;
586 u.val = ptrace(PTRACE_PEEKDATA, pid, (char *) addr, 0);
587 if (errno) {
Wichert Akkerman5daa0281999-03-15 19:49:42 +0000588 if (started && (errno==EPERM || errno==EIO)) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000589 /* Ran into 'end of memory' - stupid "printpath" */
590 return 0;
591 }
Wichert Akkerman5daa0281999-03-15 19:49:42 +0000592 /* But if not started, we had a bogus address. */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000593 perror("ptrace: umoven");
594 return -1;
595 }
Wichert Akkerman5daa0281999-03-15 19:49:42 +0000596 started = 1;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000597 memcpy(laddr, &u.x[n], m = MIN(sizeof(long) - n, len));
598 addr += sizeof(long), laddr += m, len -= m;
599 }
600 while (len) {
601 errno = 0;
602 u.val = ptrace(PTRACE_PEEKDATA, pid, (char *) addr, 0);
603 if (errno) {
Wichert Akkerman5daa0281999-03-15 19:49:42 +0000604 if (started && (errno==EPERM || errno==EIO)) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000605 /* Ran into 'end of memory' - stupid "printpath" */
606 return 0;
607 }
608 perror("ptrace: umoven");
609 return -1;
610 }
Wichert Akkerman5daa0281999-03-15 19:49:42 +0000611 started = 1;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000612 memcpy(laddr, u.x, m = MIN(sizeof(long), len));
613 addr += sizeof(long), laddr += m, len -= m;
614 }
615#endif /* LINUX */
616
617#ifdef SUNOS4
618 int pid = tcp->pid;
619#if 0
620 int n, m;
621 union {
622 long val;
623 char x[sizeof(long)];
624 } u;
625
626 if (addr & (sizeof(long) - 1)) {
627 /* addr not a multiple of sizeof(long) */
628 n = addr - (addr & -sizeof(long)); /* residue */
629 addr &= -sizeof(long); /* residue */
630 errno = 0;
631 u.val = ptrace(PTRACE_PEEKDATA, pid, (char *) addr, 0);
632 if (errno) {
633 perror("umoven");
634 return -1;
635 }
636 memcpy(laddr, &u.x[n], m = MIN(sizeof(long) - n, len));
637 addr += sizeof(long), laddr += m, len -= m;
638 }
639 while (len) {
640 errno = 0;
641 u.val = ptrace(PTRACE_PEEKDATA, pid, (char *) addr, 0);
642 if (errno) {
643 perror("umoven");
644 return -1;
645 }
646 memcpy(laddr, u.x, m = MIN(sizeof(long), len));
647 addr += sizeof(long), laddr += m, len -= m;
648 }
649#else /* !oldway */
650 int n;
651
652 while (len) {
653 n = MIN(len, PAGSIZ);
654 n = MIN(n, ((addr + PAGSIZ) & PAGMASK) - addr);
655 if (ptrace(PTRACE_READDATA, pid,
656 (char *) addr, len, laddr) < 0) {
657 perror("umoven: ptrace(PTRACE_READDATA, ...)");
658 abort();
659 return -1;
660 }
661 len -= n;
662 addr += n;
663 laddr += n;
664 }
665#endif /* !oldway */
666#endif /* SUNOS4 */
667
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000668#ifdef USE_PROCFS
Wichert Akkermanea78f0f1999-11-29 15:34:02 +0000669#ifdef HAVE_MP_PROCFS
John Hughesaa09c6b2001-05-15 14:53:43 +0000670 int fd = tcp->pfd_as;
Wichert Akkerman9ce1a631999-08-29 23:15:07 +0000671#else
John Hughesaa09c6b2001-05-15 14:53:43 +0000672 int fd = tcp->pfd;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000673#endif
John Hughesaa09c6b2001-05-15 14:53:43 +0000674 lseek(fd, addr, SEEK_SET);
675 if (read(fd, laddr, len) == -1)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000676 return -1;
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000677#endif /* USE_PROCFS */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000678
679 return 0;
680}
681
682/*
683 * like `umove' but make the additional effort of looking
684 * for a terminating zero byte.
685 */
686int
687umovestr(tcp, addr, len, laddr)
688struct tcb *tcp;
689long addr;
690int len;
691char *laddr;
692{
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000693#ifdef USE_PROCFS
John Hughesaa09c6b2001-05-15 14:53:43 +0000694#ifdef HAVE_MP_PROCFS
695 int fd = tcp->pfd_as;
696#else
697 int fd = tcp->pfd;
698#endif
699 /* Some systems (e.g. FreeBSD) can be upset if we read off the
700 end of valid memory, avoid this by trying to read up
701 to page boundaries. But we don't know what a page is (and
702 getpagesize(2) (if it exists) doesn't necessarily return
703 hardware page size). Assume all pages >= 1024 (a-historical
704 I know) */
705
706 int page = 1024; /* How to find this? */
707 int move = page - (addr & (page - 1));
708 int left = len;
709
710 lseek(fd, addr, SEEK_SET);
711
712 while (left) {
713 if (move > left) move = left;
John Hughes9cecf7f2001-10-16 10:20:22 +0000714 if ((move = read(fd, laddr, move)) <= 0)
John Hughesaa09c6b2001-05-15 14:53:43 +0000715 return left != len ? 0 : -1;
716 if (memchr (laddr, 0, move)) break;
717 left -= move;
718 laddr += move;
719 addr += move;
720 move = page;
721 }
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000722#else /* !USE_PROCFS */
Wichert Akkerman5daa0281999-03-15 19:49:42 +0000723 int started = 0;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000724 int pid = tcp->pid;
725 int i, n, m;
726 union {
727 long val;
728 char x[sizeof(long)];
729 } u;
730
731 if (addr & (sizeof(long) - 1)) {
732 /* addr not a multiple of sizeof(long) */
733 n = addr - (addr & -sizeof(long)); /* residue */
734 addr &= -sizeof(long); /* residue */
735 errno = 0;
736 u.val = ptrace(PTRACE_PEEKDATA, pid, (char *)addr, 0);
737 if (errno) {
Wichert Akkerman5daa0281999-03-15 19:49:42 +0000738 if (started && (errno==EPERM || errno==EIO)) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000739 /* Ran into 'end of memory' - stupid "printpath" */
740 return 0;
741 }
742 perror("umovestr");
743 return -1;
744 }
Wichert Akkerman5daa0281999-03-15 19:49:42 +0000745 started = 1;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000746 memcpy(laddr, &u.x[n], m = MIN(sizeof(long)-n,len));
747 while (n & (sizeof(long) - 1))
748 if (u.x[n++] == '\0')
749 return 0;
750 addr += sizeof(long), laddr += m, len -= m;
751 }
752 while (len) {
753 errno = 0;
754 u.val = ptrace(PTRACE_PEEKDATA, pid, (char *)addr, 0);
755 if (errno) {
Wichert Akkerman5daa0281999-03-15 19:49:42 +0000756 if (started && (errno==EPERM || errno==EIO)) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000757 /* Ran into 'end of memory' - stupid "printpath" */
758 return 0;
759 }
760 perror("umovestr");
761 return -1;
762 }
Wichert Akkerman5daa0281999-03-15 19:49:42 +0000763 started = 1;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000764 memcpy(laddr, u.x, m = MIN(sizeof(long), len));
765 for (i = 0; i < sizeof(long); i++)
766 if (u.x[i] == '\0')
767 return 0;
768
769 addr += sizeof(long), laddr += m, len -= m;
770 }
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000771#endif /* !USE_PROCFS */
John Hughesaa09c6b2001-05-15 14:53:43 +0000772 return 0;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000773}
774
775#ifdef LINUX
776#ifndef SPARC
777#define PTRACE_WRITETEXT 101
778#define PTRACE_WRITEDATA 102
779#endif /* !SPARC */
780#endif /* LINUX */
781
782#ifdef SUNOS4
783
784static int
785uload(cmd, pid, addr, len, laddr)
786int cmd;
787int pid;
788long addr;
789int len;
790char *laddr;
791{
792#if 0
793 int n;
794
795 while (len) {
796 n = MIN(len, PAGSIZ);
797 n = MIN(n, ((addr + PAGSIZ) & PAGMASK) - addr);
798 if (ptrace(cmd, pid, (char *)addr, n, laddr) < 0) {
799 perror("uload: ptrace(PTRACE_WRITE, ...)");
800 return -1;
801 }
802 len -= n;
803 addr += n;
804 laddr += n;
805 }
806#else
807 int peek, poke;
808 int n, m;
809 union {
810 long val;
811 char x[sizeof(long)];
812 } u;
813
814 if (cmd == PTRACE_WRITETEXT) {
815 peek = PTRACE_PEEKTEXT;
816 poke = PTRACE_POKETEXT;
817 }
818 else {
819 peek = PTRACE_PEEKDATA;
820 poke = PTRACE_POKEDATA;
821 }
822 if (addr & (sizeof(long) - 1)) {
823 /* addr not a multiple of sizeof(long) */
824 n = addr - (addr & -sizeof(long)); /* residue */
825 addr &= -sizeof(long);
826 errno = 0;
827 u.val = ptrace(peek, pid, (char *) addr, 0);
828 if (errno) {
829 perror("uload: POKE");
830 return -1;
831 }
832 memcpy(&u.x[n], laddr, m = MIN(sizeof(long) - n, len));
833 if (ptrace(poke, pid, (char *)addr, u.val) < 0) {
834 perror("uload: POKE");
835 return -1;
836 }
837 addr += sizeof(long), laddr += m, len -= m;
838 }
839 while (len) {
840 if (len < sizeof(long))
841 u.val = ptrace(peek, pid, (char *) addr, 0);
842 memcpy(u.x, laddr, m = MIN(sizeof(long), len));
843 if (ptrace(poke, pid, (char *) addr, u.val) < 0) {
844 perror("uload: POKE");
845 return -1;
846 }
847 addr += sizeof(long), laddr += m, len -= m;
848 }
849#endif
850 return 0;
851}
852
853int
854tload(pid, addr, len, laddr)
855int pid;
856int addr, len;
857char *laddr;
858{
859 return uload(PTRACE_WRITETEXT, pid, addr, len, laddr);
860}
861
862int
863dload(pid, addr, len, laddr)
864int pid;
865int addr;
866int len;
867char *laddr;
868{
869 return uload(PTRACE_WRITEDATA, pid, addr, len, laddr);
870}
871
872#endif /* SUNOS4 */
873
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000874#ifndef USE_PROCFS
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000875
876int
877upeek(pid, off, res)
878int pid;
879long off;
880long *res;
881{
882 long val;
883
884#ifdef SUNOS4_KERNEL_ARCH_KLUDGE
885 {
886 static int is_sun4m = -1;
887 struct utsname name;
888
889 /* Round up the usual suspects. */
890 if (is_sun4m == -1) {
891 if (uname(&name) < 0) {
892 perror("upeek: uname?");
893 exit(1);
894 }
895 is_sun4m = strcmp(name.machine, "sun4m") == 0;
896 if (is_sun4m) {
897 extern struct xlat struct_user_offsets[];
898 struct xlat *x;
899
900 for (x = struct_user_offsets; x->str; x++)
901 x->val += 1024;
902 }
903 }
904 if (is_sun4m)
905 off += 1024;
906 }
907#endif /* SUNOS4_KERNEL_ARCH_KLUDGE */
908 errno = 0;
909 val = ptrace(PTRACE_PEEKUSER, pid, (char *) off, 0);
910 if (val == -1 && errno) {
911 perror("upeek: ptrace(PTRACE_PEEKUSER, ... )");
912 return -1;
913 }
914 *res = val;
915 return 0;
916}
917
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000918#endif /* !USE_PROCFS */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000919
920long
921getpc(tcp)
922struct tcb *tcp;
923{
924
925#ifdef LINUX
926 long pc;
Wichert Akkermanf90da011999-10-31 21:15:38 +0000927#if defined(I386)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000928 if (upeek(tcp->pid, 4*EIP, &pc) < 0)
929 return -1;
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +0000930#elif defined(IA64)
931 if (upeek(tcp->pid, PT_B0, &pc) < 0)
932 return -1;
Wichert Akkermanf90da011999-10-31 21:15:38 +0000933#elif defined(ARM)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000934 if (upeek(tcp->pid, 4*15, &pc) < 0)
935 return -1;
Wichert Akkermanf90da011999-10-31 21:15:38 +0000936#elif defined(POWERPC)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000937 if (upeek(tcp->pid, 4*PT_NIP, &pc) < 0)
938 return -1;
Wichert Akkermanf90da011999-10-31 21:15:38 +0000939#elif defined(M68k)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000940 if (upeek(tcp->pid, 4*PT_PC, &pc) < 0)
941 return -1;
Wichert Akkermanf90da011999-10-31 21:15:38 +0000942#elif defined(ALPHA)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000943 if (upeek(tcp->pid, REG_PC, &pc) < 0)
944 return -1;
Wichert Akkermanf90da011999-10-31 21:15:38 +0000945#elif defined(MIPS)
946 if (upeek(tcp->pid, REG_EPC, &pc) < 0)
947 return -1;
948#elif defined(SPARC)
Wichert Akkerman9ce1a631999-08-29 23:15:07 +0000949 struct regs regs;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000950 if (ptrace(PTRACE_GETREGS,tcp->pid,(char *)&regs,0) < 0)
951 return -1;
Wichert Akkerman9ce1a631999-08-29 23:15:07 +0000952 pc = regs.r_pc;
Wichert Akkerman4dc8a2a1999-12-23 14:20:14 +0000953#elif defined(S390)
954 if(upeek(tcp->pid,PT_PSWADDR,&pc) < 0)
Wichert Akkermanc1652e22001-03-27 12:17:16 +0000955#elif defined(HPPA)
956 if(upeek(tcp->pid,PT_IAOQ0,&pc) < 0)
957 return -1;
Wichert Akkerman7a0b6491999-12-23 15:08:17 +0000958#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000959 return pc;
960#endif /* LINUX */
961
962#ifdef SUNOS4
963 /*
964 * Return current program counter for `pid'
965 * Assumes PC is never 0xffffffff
966 */
967 struct regs regs;
968
969 if (ptrace(PTRACE_GETREGS, tcp->pid, (char *) &regs, 0) < 0) {
970 perror("getpc: ptrace(PTRACE_GETREGS, ...)");
971 return -1;
972 }
973 return regs.r_pc;
974#endif /* SUNOS4 */
975
976#ifdef SVR4
977 /* XXX */
978 return 0;
979#endif /* SVR4 */
980
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000981#ifdef FREEBSD
982 struct reg regs;
983 pread(tcp->pfd_reg, &regs, sizeof(regs), 0);
984 return regs.r_eip;
985#endif /* FREEBSD */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000986}
987
988void
989printcall(tcp)
990struct tcb *tcp;
991{
992
993#ifdef LINUX
994#ifdef I386
995 long eip;
996
997 if (upeek(tcp->pid, 4*EIP, &eip) < 0) {
998 tprintf("[????????] ");
999 return;
1000 }
1001 tprintf("[%08lx] ", eip);
Wichert Akkermanfaf72222000-02-19 23:59:03 +00001002#elif defined(IA62)
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00001003 long ip;
1004
1005 if (upeek(tcp->pid, PT_B0, &ip) < 0) {
1006 tprintf("[????????] ");
1007 return;
1008 }
1009 tprintf("[%08lx] ", ip);
Wichert Akkermanfaf72222000-02-19 23:59:03 +00001010#elif defined(POWERPC)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001011 long pc;
1012
1013 if (upeek(tcp->pid, 4*PT_NIP, &pc) < 0) {
1014 tprintf ("[????????] ");
1015 return;
1016 }
1017 tprintf("[%08lx] ", pc);
Wichert Akkermanfaf72222000-02-19 23:59:03 +00001018#elif defined(M68k)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001019 long pc;
1020
1021 if (upeek(tcp->pid, 4*PT_PC, &pc) < 0) {
1022 tprintf ("[????????] ");
1023 return;
1024 }
1025 tprintf("[%08lx] ", pc);
Wichert Akkermanfaf72222000-02-19 23:59:03 +00001026#elif defined(ALPHA)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001027 long pc;
1028
1029 if (upeek(tcp->pid, REG_PC, &pc) < 0) {
1030 tprintf ("[????????] ");
1031 return;
1032 }
1033 tprintf("[%08lx] ", pc);
Wichert Akkermanfaf72222000-02-19 23:59:03 +00001034#elif defined(SPARC)
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001035 struct regs regs;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001036 if (ptrace(PTRACE_GETREGS,tcp->pid,(char *)&regs,0) < 0) {
1037 tprintf("[????????] ");
1038 return;
1039 }
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001040 tprintf("[%08lx] ", regs.r_pc);
Wichert Akkermanc1652e22001-03-27 12:17:16 +00001041#elif defined(HPPA)
1042 long pc;
1043
1044 if(upeek(tcp->pid,PT_IAOQ0,&pc) < 0) {
1045 tprintf ("[????????] ");
1046 return;
1047 }
1048 tprintf("[%08lx] ", pc);
Wichert Akkerman75c422b2001-04-10 10:22:50 +00001049#elif defined(MIPS)
1050 long pc;
1051
1052 if (upeek(tcp->pid, REG_EPC, &pc) < 0) {
1053 tprintf ("[????????] ");
1054 return;
1055 }
1056 tprintf("[%08lx] ", pc);
Wichert Akkermanfaf72222000-02-19 23:59:03 +00001057#endif /* !architecture */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001058#endif /* LINUX */
1059
1060#ifdef SUNOS4
1061 struct regs regs;
1062
1063 if (ptrace(PTRACE_GETREGS, tcp->pid, (char *) &regs, 0) < 0) {
1064 perror("printcall: ptrace(PTRACE_GETREGS, ...)");
1065 tprintf("[????????] ");
1066 return;
1067 }
1068 tprintf("[%08x] ", regs.r_o7);
1069#endif /* SUNOS4 */
1070
1071#ifdef SVR4
1072 /* XXX */
1073 tprintf("[????????] ");
1074#endif
1075
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001076#ifdef FREEBSD
1077 struct reg regs;
1078 pread(tcp->pfd_reg, &regs, sizeof(regs), 0);
1079 tprintf("[%08x] ", regs.r_eip);
1080#endif /* FREEBSD */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001081}
1082
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001083#ifndef USE_PROCFS
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001084
1085int
1086setbpt(tcp)
1087struct tcb *tcp;
1088{
1089
1090#ifdef LINUX
1091#ifdef SPARC
1092 /* We simply use the SunOS breakpoint code. */
1093
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001094 struct regs regs;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001095#define LOOPA 0x30800000 /* ba,a 0 */
1096
1097 if (tcp->flags & TCB_BPTSET) {
1098 fprintf(stderr, "PANIC: TCB already set in pid %u\n", tcp->pid);
1099 return -1;
1100 }
1101 if (ptrace(PTRACE_GETREGS, tcp->pid, (char *)&regs, 0) < 0) {
1102 perror("setbpt: ptrace(PTRACE_GETREGS, ...)");
1103 return -1;
1104 }
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001105 tcp->baddr = regs.r_o7 + 8;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001106 errno = 0;
1107 tcp->inst[0] = ptrace(PTRACE_PEEKTEXT, tcp->pid, (char *)tcp->baddr, 0);
1108 if(errno) {
1109 perror("setbpt: ptrace(PTRACE_PEEKTEXT, ...)");
1110 return -1;
1111 }
1112
1113 /*
1114 * XXX - BRUTAL MODE ON
1115 * We cannot set a real BPT in the child, since it will not be
1116 * traced at the moment it will reach the trap and would probably
1117 * die with a core dump.
1118 * Thus, we are force our way in by taking out two instructions
1119 * and insert an eternal loop instead, in expectance of the SIGSTOP
1120 * generated by out PTRACE_ATTACH.
1121 * Of cause, if we evaporate ourselves in the middle of all this...
1122 */
1123 errno = 0;
1124 ptrace(PTRACE_POKETEXT, tcp->pid, (char *) tcp->baddr, LOOPA);
1125 if(errno) {
1126 perror("setbpt: ptrace(PTRACE_POKETEXT, ...)");
1127 return -1;
1128 }
1129 tcp->flags |= TCB_BPTSET;
1130
1131#else /* !SPARC */
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00001132#ifdef IA64
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00001133 if (ia32) {
1134# define LOOP 0x0000feeb
1135 if (tcp->flags & TCB_BPTSET) {
1136 fprintf(stderr, "PANIC: bpt already set in pid %u\n",
1137 tcp->pid);
1138 return -1;
1139 }
1140 if (upeek(tcp->pid, PT_CR_IIP, &tcp->baddr) < 0)
1141 return -1;
1142 if (debug)
1143 fprintf(stderr, "[%d] setting bpt at %lx\n",
1144 tcp->pid, tcp->baddr);
1145 tcp->inst[0] = ptrace(PTRACE_PEEKTEXT, tcp->pid,
1146 (char *) tcp->baddr, 0);
1147 if (errno) {
1148 perror("setbpt: ptrace(PTRACE_PEEKTEXT, ...)");
1149 return -1;
1150 }
1151 ptrace(PTRACE_POKETEXT, tcp->pid, (char *) tcp->baddr, LOOP);
1152 if (errno) {
1153 perror("setbpt: ptrace(PTRACE_POKETEXT, ...)");
1154 return -1;
1155 }
1156 tcp->flags |= TCB_BPTSET;
1157 } else {
1158 /*
1159 * XXX Use break instead!
1160 *
1161 * Our strategy here is to replace the bundle that
1162 * contained the clone() syscall with a bundle of the
1163 * form:
1164 *
1165 * { 1: br 1b; br 1b; br 1b }
1166 *
1167 * This ensures that the newly forked child will loop
1168 * endlessly until we've got a chance to attach to it.
1169 */
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00001170# define LOOP0 0x0000100000000017
1171# define LOOP1 0x4000000000200000
1172 unsigned long addr, ipsr;
1173 pid_t pid;
1174
1175 pid = tcp->pid;
1176 if (upeek(pid, PT_CR_IPSR, &ipsr) < 0)
1177 return -1;
1178 if (upeek(pid, PT_CR_IIP, &addr) < 0)
1179 return -1;
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00001180 /* store "ri" in low two bits */
1181 tcp->baddr = addr | ((ipsr >> 41) & 0x3);
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00001182
1183 errno = 0;
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00001184 tcp->inst[0] = ptrace(PTRACE_PEEKTEXT, pid, (char *) addr + 0,
1185 0);
1186 tcp->inst[1] = ptrace(PTRACE_PEEKTEXT, pid, (char *) addr + 8,
1187 0);
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00001188 if (errno) {
1189 perror("setbpt: ptrace(PTRACE_PEEKTEXT, ...)");
1190 return -1;
1191 }
1192
1193 errno = 0;
1194 ptrace(PTRACE_POKETEXT, pid, (char *) addr + 0, LOOP0);
1195 ptrace(PTRACE_POKETEXT, pid, (char *) addr + 8, LOOP1);
1196 if (errno) {
1197 perror("setbpt: ptrace(PTRACE_POKETEXT, ...)");
1198 return -1;
1199 }
1200 tcp->flags |= TCB_BPTSET;
1201 }
1202#else /* !IA64 */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001203
1204#if defined (I386)
1205#define LOOP 0x0000feeb
1206#elif defined (M68K)
1207#define LOOP 0x60fe0000
1208#elif defined (ALPHA)
Wichert Akkerman4dc8a2a1999-12-23 14:20:14 +00001209#define LOOP 0xc3ffffff
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001210#elif defined (POWERPC)
Wichert Akkerman4dc8a2a1999-12-23 14:20:14 +00001211#define LOOP 0x0000feeb
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001212#elif defined(ARM)
Wichert Akkerman9a8a37f1999-12-24 23:19:31 +00001213#define LOOP 0xEAFFFFFE
Wichert Akkermanf90da011999-10-31 21:15:38 +00001214#elif defined(MIPS)
Wichert Akkerman4dc8a2a1999-12-23 14:20:14 +00001215#define LOOP 0x1000ffff
1216#elif defined(S390)
1217#define LOOP 0xa7f40000 /* BRC 15,0 */
Wichert Akkermanc1652e22001-03-27 12:17:16 +00001218#elif defined(HPPA)
1219#define LOOP 0xe81f1ff7 /* b,l,n <loc>,r0 */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001220#else
1221#error unknown architecture
1222#endif
1223
1224 if (tcp->flags & TCB_BPTSET) {
1225 fprintf(stderr, "PANIC: bpt already set in pid %u\n", tcp->pid);
1226 return -1;
1227 }
1228#if defined (I386)
1229 if (upeek(tcp->pid, 4*EIP, &tcp->baddr) < 0)
1230 return -1;
1231#elif defined (M68K)
1232 if (upeek(tcp->pid, 4*PT_PC, &tcp->baddr) < 0)
1233 return -1;
1234#elif defined (ALPHA)
1235 return -1;
1236#elif defined (ARM)
1237 return -1;
Wichert Akkermanf90da011999-10-31 21:15:38 +00001238#elif defined (MIPS)
1239 return -1; /* FIXME: I do not know what i do - Flo */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001240#elif defined (POWERPC)
1241 if (upeek(tcp->pid, 4*PT_NIP, &tcp->baddr) < 0)
1242 return -1;
Wichert Akkerman4dc8a2a1999-12-23 14:20:14 +00001243#elif defined(S390)
1244 if (upeek(tcp->pid,PT_PSWADDR, &tcp->baddr) < 0)
1245 return -1;
Wichert Akkermanc1652e22001-03-27 12:17:16 +00001246#elif defined(HPPA)
1247 if (upeek(tcp->pid, PT_IAOQ0, &tcp->baddr) < 0)
1248 return -1;
1249 tcp->baddr &= ~0x03;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001250#else
1251#error unknown architecture
1252#endif
1253 if (debug)
1254 fprintf(stderr, "[%d] setting bpt at %lx\n", tcp->pid, tcp->baddr);
1255 tcp->inst[0] = ptrace(PTRACE_PEEKTEXT, tcp->pid, (char *) tcp->baddr, 0);
1256 if (errno) {
1257 perror("setbpt: ptrace(PTRACE_PEEKTEXT, ...)");
1258 return -1;
1259 }
1260 ptrace(PTRACE_POKETEXT, tcp->pid, (char *) tcp->baddr, LOOP);
1261 if (errno) {
1262 perror("setbpt: ptrace(PTRACE_POKETEXT, ...)");
1263 return -1;
1264 }
1265 tcp->flags |= TCB_BPTSET;
1266
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00001267#endif /* !IA64 */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001268#endif /* SPARC */
1269#endif /* LINUX */
1270
1271#ifdef SUNOS4
1272#ifdef SPARC /* This code is slightly sparc specific */
1273
Wichert Akkermane6f876c1999-06-22 15:28:30 +00001274 struct regs regs;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001275#define BPT 0x91d02001 /* ta 1 */
1276#define LOOP 0x10800000 /* ba 0 */
1277#define LOOPA 0x30800000 /* ba,a 0 */
1278#define NOP 0x01000000
1279#if LOOPA
1280 static int loopdeloop[1] = {LOOPA};
1281#else
1282 static int loopdeloop[2] = {LOOP, NOP};
1283#endif
1284
1285 if (tcp->flags & TCB_BPTSET) {
1286 fprintf(stderr, "PANIC: TCB already set in pid %u\n", tcp->pid);
1287 return -1;
1288 }
1289 if (ptrace(PTRACE_GETREGS, tcp->pid, (char *)&regs, 0) < 0) {
1290 perror("setbpt: ptrace(PTRACE_GETREGS, ...)");
1291 return -1;
1292 }
1293 tcp->baddr = regs.r_o7 + 8;
1294 if (ptrace(PTRACE_READTEXT, tcp->pid, (char *)tcp->baddr,
1295 sizeof tcp->inst, (char *)tcp->inst) < 0) {
1296 perror("setbpt: ptrace(PTRACE_READTEXT, ...)");
1297 return -1;
1298 }
1299
1300 /*
1301 * XXX - BRUTAL MODE ON
1302 * We cannot set a real BPT in the child, since it will not be
1303 * traced at the moment it will reach the trap and would probably
1304 * die with a core dump.
1305 * Thus, we are force our way in by taking out two instructions
1306 * and insert an eternal loop in stead, in expectance of the SIGSTOP
1307 * generated by out PTRACE_ATTACH.
1308 * Of cause, if we evaporate ourselves in the middle of all this...
1309 */
1310 if (ptrace(PTRACE_WRITETEXT, tcp->pid, (char *) tcp->baddr,
1311 sizeof loopdeloop, (char *) loopdeloop) < 0) {
1312 perror("setbpt: ptrace(PTRACE_WRITETEXT, ...)");
1313 return -1;
1314 }
1315 tcp->flags |= TCB_BPTSET;
1316
1317#endif /* SPARC */
1318#endif /* SUNOS4 */
1319
1320 return 0;
1321}
1322
1323int
1324clearbpt(tcp)
1325struct tcb *tcp;
1326{
1327
1328#ifdef LINUX
Wichert Akkermanfaf72222000-02-19 23:59:03 +00001329#if defined(I386)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001330 long eip;
Wichert Akkermanfaf72222000-02-19 23:59:03 +00001331#elif defined(POWERPC)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001332 long pc;
Wichert Akkermanfaf72222000-02-19 23:59:03 +00001333#elif defined(M68K)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001334 long pc;
Wichert Akkermanfaf72222000-02-19 23:59:03 +00001335#elif defined(ALPHA)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001336 long pc;
Wichert Akkermanc1652e22001-03-27 12:17:16 +00001337#elif defined(HPPA)
1338 long iaoq;
Wichert Akkermanfaf72222000-02-19 23:59:03 +00001339#endif /* architecture */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001340
1341#ifdef SPARC
1342 /* Again, we borrow the SunOS breakpoint code. */
1343 if (!(tcp->flags & TCB_BPTSET)) {
1344 fprintf(stderr, "PANIC: TCB not set in pid %u\n", tcp->pid);
1345 return -1;
1346 }
1347 errno = 0;
1348 ptrace(PTRACE_POKETEXT, tcp->pid, (char *) tcp->baddr, tcp->inst[0]);
1349 if(errno) {
1350 perror("clearbtp: ptrace(PTRACE_POKETEXT, ...)");
1351 return -1;
1352 }
1353 tcp->flags &= ~TCB_BPTSET;
Wichert Akkermanfaf72222000-02-19 23:59:03 +00001354#elif defined(IA64)
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00001355 if (ia32) {
1356 unsigned long addr;
1357
1358 if (debug)
1359 fprintf(stderr, "[%d] clearing bpt\n", tcp->pid);
1360 if (!(tcp->flags & TCB_BPTSET)) {
1361 fprintf(stderr, "PANIC: TCB not set in pid %u\n", tcp->pid);
1362 return -1;
1363 }
1364 errno = 0;
1365 ptrace(PTRACE_POKETEXT, tcp->pid, (char *) tcp->baddr, tcp->inst[0]);
1366 if (errno) {
1367 perror("clearbtp: ptrace(PTRACE_POKETEXT, ...)");
1368 return -1;
1369 }
1370 tcp->flags &= ~TCB_BPTSET;
1371
1372 if (upeek(tcp->pid, PT_CR_IIP, &addr) < 0)
1373 return -1;
1374 if (addr != tcp->baddr) {
1375 /* The breakpoint has not been reached yet. */
1376 if (debug)
1377 fprintf(stderr,
1378 "NOTE: PC not at bpt (pc %#lx baddr %#lx)\n",
1379 addr, tcp->baddr);
1380 return 0;
1381 }
1382 } else {
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00001383 unsigned long addr, ipsr;
1384 pid_t pid;
1385
1386 pid = tcp->pid;
1387
1388 if (upeek(pid, PT_CR_IPSR, &ipsr) < 0)
1389 return -1;
1390 if (upeek(pid, PT_CR_IIP, &addr) < 0)
1391 return -1;
1392
1393 /* restore original bundle: */
1394 errno = 0;
1395 ptrace(PTRACE_POKETEXT, pid, (char *) addr + 0, tcp->inst[0]);
1396 ptrace(PTRACE_POKETEXT, pid, (char *) addr + 8, tcp->inst[1]);
1397 if (errno) {
1398 perror("clearbpt: ptrace(PTRACE_POKETEXT, ...)");
1399 return -1;
1400 }
1401
1402 /* restore original "ri" in ipsr: */
1403 ipsr = (ipsr & ~(0x3ul << 41)) | ((tcp->baddr & 0x3) << 41);
1404 errno = 0;
1405 ptrace(PTRACE_POKEUSER, pid, (char *) PT_CR_IPSR, ipsr);
1406 if (errno) {
1407 perror("clrbpt: ptrace(PTRACE_POKEUSER, ...)");
1408 return -1;
1409 }
1410
1411 tcp->flags &= ~TCB_BPTSET;
1412
1413 if (addr != (tcp->baddr & ~0x3)) {
1414 /* the breakpoint has not been reached yet. */
1415 if (debug)
1416 fprintf(stderr, "NOTE: PC not at bpt (pc %#lx baddr %#lx)\n",
1417 addr, tcp->baddr);
1418 return 0;
1419 }
1420 }
Wichert Akkermanfaf72222000-02-19 23:59:03 +00001421#else /* !IA64 && ! SPARC */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001422
1423 if (debug)
1424 fprintf(stderr, "[%d] clearing bpt\n", tcp->pid);
1425 if (!(tcp->flags & TCB_BPTSET)) {
1426 fprintf(stderr, "PANIC: TCB not set in pid %u\n", tcp->pid);
1427 return -1;
1428 }
1429 errno = 0;
1430 ptrace(PTRACE_POKETEXT, tcp->pid, (char *) tcp->baddr, tcp->inst[0]);
1431 if (errno) {
1432 perror("clearbtp: ptrace(PTRACE_POKETEXT, ...)");
1433 return -1;
1434 }
1435 tcp->flags &= ~TCB_BPTSET;
1436
1437#ifdef I386
1438 if (upeek(tcp->pid, 4*EIP, &eip) < 0)
1439 return -1;
1440 if (eip != tcp->baddr) {
1441 /* The breakpoint has not been reached yet. */
1442 if (debug)
1443 fprintf(stderr,
1444 "NOTE: PC not at bpt (pc %#lx baddr %#lx)\n",
1445 eip, tcp->baddr);
1446 return 0;
1447 }
Wichert Akkermanc7926982000-04-10 22:22:31 +00001448#elif defined(POWERPC)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001449 if (upeek(tcp->pid, 4*PT_NIP, &pc) < 0)
1450 return -1;
1451 if (pc != tcp->baddr) {
1452 /* The breakpoint has not been reached yet. */
1453 if (debug)
1454 fprintf(stderr, "NOTE: PC not at bpt (pc %#lx baddr %#lx)\n",
1455 pc, tcp->baddr);
1456 return 0;
1457 }
Wichert Akkermanfaf72222000-02-19 23:59:03 +00001458#elif defined(M68K)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001459 if (upeek(tcp->pid, 4*PT_PC, &pc) < 0)
1460 return -1;
1461 if (pc != tcp->baddr) {
1462 /* The breakpoint has not been reached yet. */
1463 if (debug)
1464 fprintf(stderr, "NOTE: PC not at bpt (pc %#lx baddr %#lx)\n",
1465 pc, tcp->baddr);
1466 return 0;
1467 }
Wichert Akkermanfaf72222000-02-19 23:59:03 +00001468#elif defined(ALPHA)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001469 if (upeek(tcp->pid, REG_PC, &pc) < 0)
1470 return -1;
1471 if (pc != tcp->baddr) {
1472 /* The breakpoint has not been reached yet. */
1473 if (debug)
1474 fprintf(stderr, "NOTE: PC not at bpt (pc %#lx baddr %#lx)\n",
1475 pc, tcp->baddr);
1476 return 0;
1477 }
Wichert Akkermanc1652e22001-03-27 12:17:16 +00001478#elif defined(HPPA)
1479 if (upeek(tcp->pid, PT_IAOQ0, &iaoq) < 0)
1480 return -1;
1481 iaoq &= ~0x03;
1482 if (iaoq != tcp->baddr && iaoq != tcp->baddr + 4) {
1483 /* The breakpoint has not been reached yet. */
1484 if (debug)
1485 fprintf(stderr, "NOTE: PC not at bpt (iaoq %#lx baddr %#lx)\n",
1486 iaoq, tcp->baddr);
1487 return 0;
1488 }
1489 iaoq = tcp->baddr | 3;
1490 /* We should be pointing at a 'ldi -1000,r1' in glibc, so it is
1491 * safe to set both IAOQ0 and IAOQ1 to that so the PSW N bit
1492 * has no significant effect.
1493 */
1494 ptrace(PTRACE_POKEUSER, tcp->pid, (void *)PT_IAOQ0, iaoq);
1495 ptrace(PTRACE_POKEUSER, tcp->pid, (void *)PT_IAOQ1, iaoq);
Wichert Akkermanfaf72222000-02-19 23:59:03 +00001496#endif /* arch */
1497#endif /* !SPARC && !IA64 */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001498#endif /* LINUX */
1499
1500#ifdef SUNOS4
1501#ifdef SPARC
1502
1503#if !LOOPA
Wichert Akkermane6f876c1999-06-22 15:28:30 +00001504 struct regs regs;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001505#endif
1506
1507 if (!(tcp->flags & TCB_BPTSET)) {
1508 fprintf(stderr, "PANIC: TCB not set in pid %u\n", tcp->pid);
1509 return -1;
1510 }
1511 if (ptrace(PTRACE_WRITETEXT, tcp->pid, (char *) tcp->baddr,
1512 sizeof tcp->inst, (char *) tcp->inst) < 0) {
1513 perror("clearbtp: ptrace(PTRACE_WRITETEXT, ...)");
1514 return -1;
1515 }
1516 tcp->flags &= ~TCB_BPTSET;
1517
1518#if !LOOPA
1519 /*
1520 * Since we don't have a single instruction breakpoint, we may have
1521 * to adjust the program counter after removing the our `breakpoint'.
1522 */
1523 if (ptrace(PTRACE_GETREGS, tcp->pid, (char *)&regs, 0) < 0) {
1524 perror("clearbpt: ptrace(PTRACE_GETREGS, ...)");
1525 return -1;
1526 }
1527 if ((regs.r_pc < tcp->baddr) ||
1528 (regs.r_pc > tcp->baddr + 4)) {
1529 /* The breakpoint has not been reached yet */
1530 if (debug)
1531 fprintf(stderr,
1532 "NOTE: PC not at bpt (pc %#x baddr %#x)\n",
1533 regs.r_pc, tcp->parent->baddr);
1534 return 0;
1535 }
1536 if (regs.r_pc != tcp->baddr)
1537 if (debug)
1538 fprintf(stderr, "NOTE: PC adjusted (%#x -> %#x\n",
1539 regs.r_pc, tcp->baddr);
1540
1541 regs.r_pc = tcp->baddr;
1542 if (ptrace(PTRACE_SETREGS, tcp->pid, (char *)&regs, 0) < 0) {
1543 perror("clearbpt: ptrace(PTRACE_SETREGS, ...)");
1544 return -1;
1545 }
1546#endif /* LOOPA */
1547#endif /* SPARC */
1548#endif /* SUNOS4 */
1549
1550 return 0;
1551}
1552
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001553#endif /* !USE_PROCFS */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001554
1555#ifdef SUNOS4
1556
1557static int
1558getex(pid, hdr)
1559int pid;
1560struct exec *hdr;
1561{
1562 int n;
1563
1564 for (n = 0; n < sizeof *hdr; n += 4) {
1565 long res;
1566 if (upeek(pid, uoff(u_exdata) + n, &res) < 0)
1567 return -1;
1568 memcpy(((char *) hdr) + n, &res, 4);
1569 }
1570 if (debug) {
1571 fprintf(stderr, "[struct exec: magic: %o version %u Mach %o\n",
1572 hdr->a_magic, hdr->a_toolversion, hdr->a_machtype);
1573 fprintf(stderr, "Text %lu Data %lu Bss %lu Syms %lu Entry %#lx]\n",
1574 hdr->a_text, hdr->a_data, hdr->a_bss, hdr->a_syms, hdr->a_entry);
1575 }
1576 return 0;
1577}
1578
1579int
1580fixvfork(tcp)
1581struct tcb *tcp;
1582{
1583 int pid = tcp->pid;
1584 /*
1585 * Change `vfork' in a freshly exec'ed dynamically linked
1586 * executable's (internal) symbol table to plain old `fork'
1587 */
1588
1589 struct exec hdr;
1590 struct link_dynamic dyn;
1591 struct link_dynamic_2 ld;
1592 char *strtab, *cp;
1593
1594 if (getex(pid, &hdr) < 0)
1595 return -1;
1596 if (!hdr.a_dynamic)
1597 return -1;
1598
1599 if (umove(tcp, (int) N_DATADDR(hdr), &dyn) < 0) {
1600 fprintf(stderr, "Cannot read DYNAMIC\n");
1601 return -1;
1602 }
1603 if (umove(tcp, (int) dyn.ld_un.ld_2, &ld) < 0) {
1604 fprintf(stderr, "Cannot read link_dynamic_2\n");
1605 return -1;
1606 }
1607 if ((strtab = malloc((unsigned)ld.ld_symb_size)) == NULL) {
1608 fprintf(stderr, "fixvfork: out of memory\n");
1609 return -1;
1610 }
1611 if (umoven(tcp, (int)ld.ld_symbols+(int)N_TXTADDR(hdr),
1612 (int)ld.ld_symb_size, strtab) < 0)
1613 goto err;
1614
1615#if 0
1616 for (cp = strtab; cp < strtab + ld.ld_symb_size; ) {
1617 fprintf(stderr, "[symbol: %s]\n", cp);
1618 cp += strlen(cp)+1;
1619 }
1620 return 0;
1621#endif
1622 for (cp = strtab; cp < strtab + ld.ld_symb_size; ) {
1623 if (strcmp(cp, "_vfork") == 0) {
1624 if (debug)
1625 fprintf(stderr, "fixvfork: FOUND _vfork\n");
1626 strcpy(cp, "_fork");
1627 break;
1628 }
1629 cp += strlen(cp)+1;
1630 }
1631 if (cp < strtab + ld.ld_symb_size)
1632 /*
1633 * Write entire symbol table back to avoid
1634 * memory alignment bugs in ptrace
1635 */
1636 if (tload(pid, (int)ld.ld_symbols+(int)N_TXTADDR(hdr),
1637 (int)ld.ld_symb_size, strtab) < 0)
1638 goto err;
1639
1640 free(strtab);
1641 return 0;
1642
1643err:
1644 free(strtab);
1645 return -1;
1646}
1647
1648#endif /* SUNOS4 */