blob: 5aedec6fe510ca3629ff404473859ddd6e65553c [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;
714 if ((move = read(fd, laddr, move)) == -1)
715 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
1133 /*
1134 * Our strategy here is to replace the bundle that contained
1135 * the clone() syscall with a bundle of the form:
1136 *
1137 * { 1: br 1b; br 1b; br 1b }
1138 *
1139 * This ensures that the newly forked child will loop
1140 * endlessly until we've got a chance to attach to it.
1141 */
1142 {
1143# define LOOP0 0x0000100000000017
1144# define LOOP1 0x4000000000200000
1145 unsigned long addr, ipsr;
1146 pid_t pid;
1147
1148 pid = tcp->pid;
1149 if (upeek(pid, PT_CR_IPSR, &ipsr) < 0)
1150 return -1;
1151 if (upeek(pid, PT_CR_IIP, &addr) < 0)
1152 return -1;
1153 tcp->baddr = addr | ((ipsr >> 41) & 0x3); /* store "ri" in low two bits */
1154
1155 errno = 0;
1156 tcp->inst[0] = ptrace(PTRACE_PEEKTEXT, pid, (char *) addr + 0, 0);
1157 tcp->inst[1] = ptrace(PTRACE_PEEKTEXT, pid, (char *) addr + 8, 0);
1158 if (errno) {
1159 perror("setbpt: ptrace(PTRACE_PEEKTEXT, ...)");
1160 return -1;
1161 }
1162
1163 errno = 0;
1164 ptrace(PTRACE_POKETEXT, pid, (char *) addr + 0, LOOP0);
1165 ptrace(PTRACE_POKETEXT, pid, (char *) addr + 8, LOOP1);
1166 if (errno) {
1167 perror("setbpt: ptrace(PTRACE_POKETEXT, ...)");
1168 return -1;
1169 }
1170 tcp->flags |= TCB_BPTSET;
1171 }
1172#else /* !IA64 */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001173
1174#if defined (I386)
1175#define LOOP 0x0000feeb
1176#elif defined (M68K)
1177#define LOOP 0x60fe0000
1178#elif defined (ALPHA)
Wichert Akkerman4dc8a2a1999-12-23 14:20:14 +00001179#define LOOP 0xc3ffffff
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001180#elif defined (POWERPC)
Wichert Akkerman4dc8a2a1999-12-23 14:20:14 +00001181#define LOOP 0x0000feeb
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001182#elif defined(ARM)
Wichert Akkerman9a8a37f1999-12-24 23:19:31 +00001183#define LOOP 0xEAFFFFFE
Wichert Akkermanf90da011999-10-31 21:15:38 +00001184#elif defined(MIPS)
Wichert Akkerman4dc8a2a1999-12-23 14:20:14 +00001185#define LOOP 0x1000ffff
1186#elif defined(S390)
1187#define LOOP 0xa7f40000 /* BRC 15,0 */
Wichert Akkermanc1652e22001-03-27 12:17:16 +00001188#elif defined(HPPA)
1189#define LOOP 0xe81f1ff7 /* b,l,n <loc>,r0 */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001190#else
1191#error unknown architecture
1192#endif
1193
1194 if (tcp->flags & TCB_BPTSET) {
1195 fprintf(stderr, "PANIC: bpt already set in pid %u\n", tcp->pid);
1196 return -1;
1197 }
1198#if defined (I386)
1199 if (upeek(tcp->pid, 4*EIP, &tcp->baddr) < 0)
1200 return -1;
1201#elif defined (M68K)
1202 if (upeek(tcp->pid, 4*PT_PC, &tcp->baddr) < 0)
1203 return -1;
1204#elif defined (ALPHA)
1205 return -1;
1206#elif defined (ARM)
1207 return -1;
Wichert Akkermanf90da011999-10-31 21:15:38 +00001208#elif defined (MIPS)
1209 return -1; /* FIXME: I do not know what i do - Flo */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001210#elif defined (POWERPC)
1211 if (upeek(tcp->pid, 4*PT_NIP, &tcp->baddr) < 0)
1212 return -1;
Wichert Akkerman4dc8a2a1999-12-23 14:20:14 +00001213#elif defined(S390)
1214 if (upeek(tcp->pid,PT_PSWADDR, &tcp->baddr) < 0)
1215 return -1;
Wichert Akkermanc1652e22001-03-27 12:17:16 +00001216#elif defined(HPPA)
1217 if (upeek(tcp->pid, PT_IAOQ0, &tcp->baddr) < 0)
1218 return -1;
1219 tcp->baddr &= ~0x03;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001220#else
1221#error unknown architecture
1222#endif
1223 if (debug)
1224 fprintf(stderr, "[%d] setting bpt at %lx\n", tcp->pid, tcp->baddr);
1225 tcp->inst[0] = ptrace(PTRACE_PEEKTEXT, tcp->pid, (char *) tcp->baddr, 0);
1226 if (errno) {
1227 perror("setbpt: ptrace(PTRACE_PEEKTEXT, ...)");
1228 return -1;
1229 }
1230 ptrace(PTRACE_POKETEXT, tcp->pid, (char *) tcp->baddr, LOOP);
1231 if (errno) {
1232 perror("setbpt: ptrace(PTRACE_POKETEXT, ...)");
1233 return -1;
1234 }
1235 tcp->flags |= TCB_BPTSET;
1236
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00001237#endif /* !IA64 */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001238#endif /* SPARC */
1239#endif /* LINUX */
1240
1241#ifdef SUNOS4
1242#ifdef SPARC /* This code is slightly sparc specific */
1243
Wichert Akkermane6f876c1999-06-22 15:28:30 +00001244 struct regs regs;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001245#define BPT 0x91d02001 /* ta 1 */
1246#define LOOP 0x10800000 /* ba 0 */
1247#define LOOPA 0x30800000 /* ba,a 0 */
1248#define NOP 0x01000000
1249#if LOOPA
1250 static int loopdeloop[1] = {LOOPA};
1251#else
1252 static int loopdeloop[2] = {LOOP, NOP};
1253#endif
1254
1255 if (tcp->flags & TCB_BPTSET) {
1256 fprintf(stderr, "PANIC: TCB already set in pid %u\n", tcp->pid);
1257 return -1;
1258 }
1259 if (ptrace(PTRACE_GETREGS, tcp->pid, (char *)&regs, 0) < 0) {
1260 perror("setbpt: ptrace(PTRACE_GETREGS, ...)");
1261 return -1;
1262 }
1263 tcp->baddr = regs.r_o7 + 8;
1264 if (ptrace(PTRACE_READTEXT, tcp->pid, (char *)tcp->baddr,
1265 sizeof tcp->inst, (char *)tcp->inst) < 0) {
1266 perror("setbpt: ptrace(PTRACE_READTEXT, ...)");
1267 return -1;
1268 }
1269
1270 /*
1271 * XXX - BRUTAL MODE ON
1272 * We cannot set a real BPT in the child, since it will not be
1273 * traced at the moment it will reach the trap and would probably
1274 * die with a core dump.
1275 * Thus, we are force our way in by taking out two instructions
1276 * and insert an eternal loop in stead, in expectance of the SIGSTOP
1277 * generated by out PTRACE_ATTACH.
1278 * Of cause, if we evaporate ourselves in the middle of all this...
1279 */
1280 if (ptrace(PTRACE_WRITETEXT, tcp->pid, (char *) tcp->baddr,
1281 sizeof loopdeloop, (char *) loopdeloop) < 0) {
1282 perror("setbpt: ptrace(PTRACE_WRITETEXT, ...)");
1283 return -1;
1284 }
1285 tcp->flags |= TCB_BPTSET;
1286
1287#endif /* SPARC */
1288#endif /* SUNOS4 */
1289
1290 return 0;
1291}
1292
1293int
1294clearbpt(tcp)
1295struct tcb *tcp;
1296{
1297
1298#ifdef LINUX
Wichert Akkermanfaf72222000-02-19 23:59:03 +00001299#if defined(I386)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001300 long eip;
Wichert Akkermanfaf72222000-02-19 23:59:03 +00001301#elif defined(POWERPC)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001302 long pc;
Wichert Akkermanfaf72222000-02-19 23:59:03 +00001303#elif defined(M68K)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001304 long pc;
Wichert Akkermanfaf72222000-02-19 23:59:03 +00001305#elif defined(ALPHA)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001306 long pc;
Wichert Akkermanc1652e22001-03-27 12:17:16 +00001307#elif defined(HPPA)
1308 long iaoq;
Wichert Akkermanfaf72222000-02-19 23:59:03 +00001309#endif /* architecture */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001310
1311#ifdef SPARC
1312 /* Again, we borrow the SunOS breakpoint code. */
1313 if (!(tcp->flags & TCB_BPTSET)) {
1314 fprintf(stderr, "PANIC: TCB not set in pid %u\n", tcp->pid);
1315 return -1;
1316 }
1317 errno = 0;
1318 ptrace(PTRACE_POKETEXT, tcp->pid, (char *) tcp->baddr, tcp->inst[0]);
1319 if(errno) {
1320 perror("clearbtp: ptrace(PTRACE_POKETEXT, ...)");
1321 return -1;
1322 }
1323 tcp->flags &= ~TCB_BPTSET;
Wichert Akkermanfaf72222000-02-19 23:59:03 +00001324#elif defined(IA64)
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00001325 {
1326 unsigned long addr, ipsr;
1327 pid_t pid;
1328
1329 pid = tcp->pid;
1330
1331 if (upeek(pid, PT_CR_IPSR, &ipsr) < 0)
1332 return -1;
1333 if (upeek(pid, PT_CR_IIP, &addr) < 0)
1334 return -1;
1335
1336 /* restore original bundle: */
1337 errno = 0;
1338 ptrace(PTRACE_POKETEXT, pid, (char *) addr + 0, tcp->inst[0]);
1339 ptrace(PTRACE_POKETEXT, pid, (char *) addr + 8, tcp->inst[1]);
1340 if (errno) {
1341 perror("clearbpt: ptrace(PTRACE_POKETEXT, ...)");
1342 return -1;
1343 }
1344
1345 /* restore original "ri" in ipsr: */
1346 ipsr = (ipsr & ~(0x3ul << 41)) | ((tcp->baddr & 0x3) << 41);
1347 errno = 0;
1348 ptrace(PTRACE_POKEUSER, pid, (char *) PT_CR_IPSR, ipsr);
1349 if (errno) {
1350 perror("clrbpt: ptrace(PTRACE_POKEUSER, ...)");
1351 return -1;
1352 }
1353
1354 tcp->flags &= ~TCB_BPTSET;
1355
1356 if (addr != (tcp->baddr & ~0x3)) {
1357 /* the breakpoint has not been reached yet. */
1358 if (debug)
1359 fprintf(stderr, "NOTE: PC not at bpt (pc %#lx baddr %#lx)\n",
1360 addr, tcp->baddr);
1361 return 0;
1362 }
1363 }
Wichert Akkermanfaf72222000-02-19 23:59:03 +00001364#else /* !IA64 && ! SPARC */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001365
1366 if (debug)
1367 fprintf(stderr, "[%d] clearing bpt\n", tcp->pid);
1368 if (!(tcp->flags & TCB_BPTSET)) {
1369 fprintf(stderr, "PANIC: TCB not set in pid %u\n", tcp->pid);
1370 return -1;
1371 }
1372 errno = 0;
1373 ptrace(PTRACE_POKETEXT, tcp->pid, (char *) tcp->baddr, tcp->inst[0]);
1374 if (errno) {
1375 perror("clearbtp: ptrace(PTRACE_POKETEXT, ...)");
1376 return -1;
1377 }
1378 tcp->flags &= ~TCB_BPTSET;
1379
1380#ifdef I386
1381 if (upeek(tcp->pid, 4*EIP, &eip) < 0)
1382 return -1;
1383 if (eip != tcp->baddr) {
1384 /* The breakpoint has not been reached yet. */
1385 if (debug)
1386 fprintf(stderr,
1387 "NOTE: PC not at bpt (pc %#lx baddr %#lx)\n",
1388 eip, tcp->baddr);
1389 return 0;
1390 }
Wichert Akkermanc7926982000-04-10 22:22:31 +00001391#elif defined(POWERPC)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001392 if (upeek(tcp->pid, 4*PT_NIP, &pc) < 0)
1393 return -1;
1394 if (pc != tcp->baddr) {
1395 /* The breakpoint has not been reached yet. */
1396 if (debug)
1397 fprintf(stderr, "NOTE: PC not at bpt (pc %#lx baddr %#lx)\n",
1398 pc, tcp->baddr);
1399 return 0;
1400 }
Wichert Akkermanfaf72222000-02-19 23:59:03 +00001401#elif defined(M68K)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001402 if (upeek(tcp->pid, 4*PT_PC, &pc) < 0)
1403 return -1;
1404 if (pc != tcp->baddr) {
1405 /* The breakpoint has not been reached yet. */
1406 if (debug)
1407 fprintf(stderr, "NOTE: PC not at bpt (pc %#lx baddr %#lx)\n",
1408 pc, tcp->baddr);
1409 return 0;
1410 }
Wichert Akkermanfaf72222000-02-19 23:59:03 +00001411#elif defined(ALPHA)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001412 if (upeek(tcp->pid, REG_PC, &pc) < 0)
1413 return -1;
1414 if (pc != tcp->baddr) {
1415 /* The breakpoint has not been reached yet. */
1416 if (debug)
1417 fprintf(stderr, "NOTE: PC not at bpt (pc %#lx baddr %#lx)\n",
1418 pc, tcp->baddr);
1419 return 0;
1420 }
Wichert Akkermanc1652e22001-03-27 12:17:16 +00001421#elif defined(HPPA)
1422 if (upeek(tcp->pid, PT_IAOQ0, &iaoq) < 0)
1423 return -1;
1424 iaoq &= ~0x03;
1425 if (iaoq != tcp->baddr && iaoq != tcp->baddr + 4) {
1426 /* The breakpoint has not been reached yet. */
1427 if (debug)
1428 fprintf(stderr, "NOTE: PC not at bpt (iaoq %#lx baddr %#lx)\n",
1429 iaoq, tcp->baddr);
1430 return 0;
1431 }
1432 iaoq = tcp->baddr | 3;
1433 /* We should be pointing at a 'ldi -1000,r1' in glibc, so it is
1434 * safe to set both IAOQ0 and IAOQ1 to that so the PSW N bit
1435 * has no significant effect.
1436 */
1437 ptrace(PTRACE_POKEUSER, tcp->pid, (void *)PT_IAOQ0, iaoq);
1438 ptrace(PTRACE_POKEUSER, tcp->pid, (void *)PT_IAOQ1, iaoq);
Wichert Akkermanfaf72222000-02-19 23:59:03 +00001439#endif /* arch */
1440#endif /* !SPARC && !IA64 */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001441#endif /* LINUX */
1442
1443#ifdef SUNOS4
1444#ifdef SPARC
1445
1446#if !LOOPA
Wichert Akkermane6f876c1999-06-22 15:28:30 +00001447 struct regs regs;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001448#endif
1449
1450 if (!(tcp->flags & TCB_BPTSET)) {
1451 fprintf(stderr, "PANIC: TCB not set in pid %u\n", tcp->pid);
1452 return -1;
1453 }
1454 if (ptrace(PTRACE_WRITETEXT, tcp->pid, (char *) tcp->baddr,
1455 sizeof tcp->inst, (char *) tcp->inst) < 0) {
1456 perror("clearbtp: ptrace(PTRACE_WRITETEXT, ...)");
1457 return -1;
1458 }
1459 tcp->flags &= ~TCB_BPTSET;
1460
1461#if !LOOPA
1462 /*
1463 * Since we don't have a single instruction breakpoint, we may have
1464 * to adjust the program counter after removing the our `breakpoint'.
1465 */
1466 if (ptrace(PTRACE_GETREGS, tcp->pid, (char *)&regs, 0) < 0) {
1467 perror("clearbpt: ptrace(PTRACE_GETREGS, ...)");
1468 return -1;
1469 }
1470 if ((regs.r_pc < tcp->baddr) ||
1471 (regs.r_pc > tcp->baddr + 4)) {
1472 /* The breakpoint has not been reached yet */
1473 if (debug)
1474 fprintf(stderr,
1475 "NOTE: PC not at bpt (pc %#x baddr %#x)\n",
1476 regs.r_pc, tcp->parent->baddr);
1477 return 0;
1478 }
1479 if (regs.r_pc != tcp->baddr)
1480 if (debug)
1481 fprintf(stderr, "NOTE: PC adjusted (%#x -> %#x\n",
1482 regs.r_pc, tcp->baddr);
1483
1484 regs.r_pc = tcp->baddr;
1485 if (ptrace(PTRACE_SETREGS, tcp->pid, (char *)&regs, 0) < 0) {
1486 perror("clearbpt: ptrace(PTRACE_SETREGS, ...)");
1487 return -1;
1488 }
1489#endif /* LOOPA */
1490#endif /* SPARC */
1491#endif /* SUNOS4 */
1492
1493 return 0;
1494}
1495
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001496#endif /* !USE_PROCFS */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001497
1498#ifdef SUNOS4
1499
1500static int
1501getex(pid, hdr)
1502int pid;
1503struct exec *hdr;
1504{
1505 int n;
1506
1507 for (n = 0; n < sizeof *hdr; n += 4) {
1508 long res;
1509 if (upeek(pid, uoff(u_exdata) + n, &res) < 0)
1510 return -1;
1511 memcpy(((char *) hdr) + n, &res, 4);
1512 }
1513 if (debug) {
1514 fprintf(stderr, "[struct exec: magic: %o version %u Mach %o\n",
1515 hdr->a_magic, hdr->a_toolversion, hdr->a_machtype);
1516 fprintf(stderr, "Text %lu Data %lu Bss %lu Syms %lu Entry %#lx]\n",
1517 hdr->a_text, hdr->a_data, hdr->a_bss, hdr->a_syms, hdr->a_entry);
1518 }
1519 return 0;
1520}
1521
1522int
1523fixvfork(tcp)
1524struct tcb *tcp;
1525{
1526 int pid = tcp->pid;
1527 /*
1528 * Change `vfork' in a freshly exec'ed dynamically linked
1529 * executable's (internal) symbol table to plain old `fork'
1530 */
1531
1532 struct exec hdr;
1533 struct link_dynamic dyn;
1534 struct link_dynamic_2 ld;
1535 char *strtab, *cp;
1536
1537 if (getex(pid, &hdr) < 0)
1538 return -1;
1539 if (!hdr.a_dynamic)
1540 return -1;
1541
1542 if (umove(tcp, (int) N_DATADDR(hdr), &dyn) < 0) {
1543 fprintf(stderr, "Cannot read DYNAMIC\n");
1544 return -1;
1545 }
1546 if (umove(tcp, (int) dyn.ld_un.ld_2, &ld) < 0) {
1547 fprintf(stderr, "Cannot read link_dynamic_2\n");
1548 return -1;
1549 }
1550 if ((strtab = malloc((unsigned)ld.ld_symb_size)) == NULL) {
1551 fprintf(stderr, "fixvfork: out of memory\n");
1552 return -1;
1553 }
1554 if (umoven(tcp, (int)ld.ld_symbols+(int)N_TXTADDR(hdr),
1555 (int)ld.ld_symb_size, strtab) < 0)
1556 goto err;
1557
1558#if 0
1559 for (cp = strtab; cp < strtab + ld.ld_symb_size; ) {
1560 fprintf(stderr, "[symbol: %s]\n", cp);
1561 cp += strlen(cp)+1;
1562 }
1563 return 0;
1564#endif
1565 for (cp = strtab; cp < strtab + ld.ld_symb_size; ) {
1566 if (strcmp(cp, "_vfork") == 0) {
1567 if (debug)
1568 fprintf(stderr, "fixvfork: FOUND _vfork\n");
1569 strcpy(cp, "_fork");
1570 break;
1571 }
1572 cp += strlen(cp)+1;
1573 }
1574 if (cp < strtab + ld.ld_symb_size)
1575 /*
1576 * Write entire symbol table back to avoid
1577 * memory alignment bugs in ptrace
1578 */
1579 if (tload(pid, (int)ld.ld_symbols+(int)N_TXTADDR(hdr),
1580 (int)ld.ld_symb_size, strtab) < 0)
1581 goto err;
1582
1583 free(strtab);
1584 return 0;
1585
1586err:
1587 free(strtab);
1588 return -1;
1589}
1590
1591#endif /* SUNOS4 */