blob: d34a66d00551d1cb5e4bf1074090b21812413f9d [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) {
Michal Ludvig0e035502002-09-23 15:41:01 +0000911 char buf[60];
912 sprintf(buf,"upeek: ptrace(PTRACE_PEEKUSER,%d,%lu,0)",pid,off);
913 perror(buf);
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000914 return -1;
915 }
916 *res = val;
917 return 0;
918}
919
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000920#endif /* !USE_PROCFS */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000921
922long
923getpc(tcp)
924struct tcb *tcp;
925{
926
927#ifdef LINUX
928 long pc;
Wichert Akkermanf90da011999-10-31 21:15:38 +0000929#if defined(I386)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000930 if (upeek(tcp->pid, 4*EIP, &pc) < 0)
931 return -1;
Michal Ludvig0e035502002-09-23 15:41:01 +0000932#elif defined(X86_64)
933 if (upeek(tcp->pid, 8*RIP, &pc) < 0)
934 return -1;
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +0000935#elif defined(IA64)
936 if (upeek(tcp->pid, PT_B0, &pc) < 0)
937 return -1;
Wichert Akkermanf90da011999-10-31 21:15:38 +0000938#elif defined(ARM)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000939 if (upeek(tcp->pid, 4*15, &pc) < 0)
940 return -1;
Wichert Akkermanf90da011999-10-31 21:15:38 +0000941#elif defined(POWERPC)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000942 if (upeek(tcp->pid, 4*PT_NIP, &pc) < 0)
943 return -1;
Wichert Akkermanf90da011999-10-31 21:15:38 +0000944#elif defined(M68k)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000945 if (upeek(tcp->pid, 4*PT_PC, &pc) < 0)
946 return -1;
Wichert Akkermanf90da011999-10-31 21:15:38 +0000947#elif defined(ALPHA)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000948 if (upeek(tcp->pid, REG_PC, &pc) < 0)
949 return -1;
Wichert Akkermanf90da011999-10-31 21:15:38 +0000950#elif defined(MIPS)
951 if (upeek(tcp->pid, REG_EPC, &pc) < 0)
952 return -1;
953#elif defined(SPARC)
Wichert Akkerman9ce1a631999-08-29 23:15:07 +0000954 struct regs regs;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000955 if (ptrace(PTRACE_GETREGS,tcp->pid,(char *)&regs,0) < 0)
956 return -1;
Wichert Akkerman9ce1a631999-08-29 23:15:07 +0000957 pc = regs.r_pc;
Wichert Akkerman4dc8a2a1999-12-23 14:20:14 +0000958#elif defined(S390)
959 if(upeek(tcp->pid,PT_PSWADDR,&pc) < 0)
Wichert Akkermanc1652e22001-03-27 12:17:16 +0000960#elif defined(HPPA)
961 if(upeek(tcp->pid,PT_IAOQ0,&pc) < 0)
962 return -1;
Wichert Akkermanccef6372002-05-01 16:39:22 +0000963#elif defined(SH)
964 if (upeek(tcp->pid, 4*REG_PC ,&pc) < 0)
965 return -1;
Wichert Akkerman7a0b6491999-12-23 15:08:17 +0000966#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000967 return pc;
968#endif /* LINUX */
969
970#ifdef SUNOS4
971 /*
972 * Return current program counter for `pid'
973 * Assumes PC is never 0xffffffff
974 */
975 struct regs regs;
976
977 if (ptrace(PTRACE_GETREGS, tcp->pid, (char *) &regs, 0) < 0) {
978 perror("getpc: ptrace(PTRACE_GETREGS, ...)");
979 return -1;
980 }
981 return regs.r_pc;
982#endif /* SUNOS4 */
983
984#ifdef SVR4
985 /* XXX */
986 return 0;
987#endif /* SVR4 */
988
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000989#ifdef FREEBSD
990 struct reg regs;
991 pread(tcp->pfd_reg, &regs, sizeof(regs), 0);
992 return regs.r_eip;
993#endif /* FREEBSD */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000994}
995
996void
997printcall(tcp)
998struct tcb *tcp;
999{
1000
1001#ifdef LINUX
1002#ifdef I386
1003 long eip;
1004
1005 if (upeek(tcp->pid, 4*EIP, &eip) < 0) {
1006 tprintf("[????????] ");
1007 return;
1008 }
1009 tprintf("[%08lx] ", eip);
Michal Ludvig0e035502002-09-23 15:41:01 +00001010#elif defined(X86_64)
1011 long rip;
1012
1013 if (upeek(tcp->pid, 8*RIP, &rip) < 0) {
1014 tprintf("[????????] ");
1015 return;
1016 }
1017 tprintf("[%16lx] ", rip);
Wichert Akkermanfaf72222000-02-19 23:59:03 +00001018#elif defined(IA62)
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00001019 long ip;
1020
1021 if (upeek(tcp->pid, PT_B0, &ip) < 0) {
1022 tprintf("[????????] ");
1023 return;
1024 }
1025 tprintf("[%08lx] ", ip);
Wichert Akkermanfaf72222000-02-19 23:59:03 +00001026#elif defined(POWERPC)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001027 long pc;
1028
1029 if (upeek(tcp->pid, 4*PT_NIP, &pc) < 0) {
1030 tprintf ("[????????] ");
1031 return;
1032 }
1033 tprintf("[%08lx] ", pc);
Wichert Akkermanfaf72222000-02-19 23:59:03 +00001034#elif defined(M68k)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001035 long pc;
1036
1037 if (upeek(tcp->pid, 4*PT_PC, &pc) < 0) {
1038 tprintf ("[????????] ");
1039 return;
1040 }
1041 tprintf("[%08lx] ", pc);
Wichert Akkermanfaf72222000-02-19 23:59:03 +00001042#elif defined(ALPHA)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001043 long pc;
1044
1045 if (upeek(tcp->pid, REG_PC, &pc) < 0) {
1046 tprintf ("[????????] ");
1047 return;
1048 }
1049 tprintf("[%08lx] ", pc);
Wichert Akkermanfaf72222000-02-19 23:59:03 +00001050#elif defined(SPARC)
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001051 struct regs regs;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001052 if (ptrace(PTRACE_GETREGS,tcp->pid,(char *)&regs,0) < 0) {
1053 tprintf("[????????] ");
1054 return;
1055 }
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001056 tprintf("[%08lx] ", regs.r_pc);
Wichert Akkermanc1652e22001-03-27 12:17:16 +00001057#elif defined(HPPA)
1058 long pc;
1059
1060 if(upeek(tcp->pid,PT_IAOQ0,&pc) < 0) {
1061 tprintf ("[????????] ");
1062 return;
1063 }
1064 tprintf("[%08lx] ", pc);
Wichert Akkerman75c422b2001-04-10 10:22:50 +00001065#elif defined(MIPS)
1066 long pc;
1067
1068 if (upeek(tcp->pid, REG_EPC, &pc) < 0) {
1069 tprintf ("[????????] ");
1070 return;
1071 }
1072 tprintf("[%08lx] ", pc);
Wichert Akkermanccef6372002-05-01 16:39:22 +00001073#elif defined(SH)
1074 long pc;
1075
1076 if (upeek(tcp->pid, 4*REG_PC, &pc) < 0) {
1077 tprintf ("[????????] ");
1078 return;
1079 }
1080 tprintf("[%08lx] ", pc);
Wichert Akkermanfaf72222000-02-19 23:59:03 +00001081#endif /* !architecture */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001082#endif /* LINUX */
1083
1084#ifdef SUNOS4
1085 struct regs regs;
1086
1087 if (ptrace(PTRACE_GETREGS, tcp->pid, (char *) &regs, 0) < 0) {
1088 perror("printcall: ptrace(PTRACE_GETREGS, ...)");
1089 tprintf("[????????] ");
1090 return;
1091 }
1092 tprintf("[%08x] ", regs.r_o7);
1093#endif /* SUNOS4 */
1094
1095#ifdef SVR4
1096 /* XXX */
1097 tprintf("[????????] ");
1098#endif
1099
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001100#ifdef FREEBSD
1101 struct reg regs;
1102 pread(tcp->pfd_reg, &regs, sizeof(regs), 0);
1103 tprintf("[%08x] ", regs.r_eip);
1104#endif /* FREEBSD */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001105}
1106
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001107#ifndef USE_PROCFS
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001108
1109int
1110setbpt(tcp)
1111struct tcb *tcp;
1112{
1113
1114#ifdef LINUX
1115#ifdef SPARC
1116 /* We simply use the SunOS breakpoint code. */
1117
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001118 struct regs regs;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001119#define LOOPA 0x30800000 /* ba,a 0 */
1120
1121 if (tcp->flags & TCB_BPTSET) {
1122 fprintf(stderr, "PANIC: TCB already set in pid %u\n", tcp->pid);
1123 return -1;
1124 }
1125 if (ptrace(PTRACE_GETREGS, tcp->pid, (char *)&regs, 0) < 0) {
1126 perror("setbpt: ptrace(PTRACE_GETREGS, ...)");
1127 return -1;
1128 }
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001129 tcp->baddr = regs.r_o7 + 8;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001130 errno = 0;
1131 tcp->inst[0] = ptrace(PTRACE_PEEKTEXT, tcp->pid, (char *)tcp->baddr, 0);
1132 if(errno) {
1133 perror("setbpt: ptrace(PTRACE_PEEKTEXT, ...)");
1134 return -1;
1135 }
1136
1137 /*
1138 * XXX - BRUTAL MODE ON
1139 * We cannot set a real BPT in the child, since it will not be
1140 * traced at the moment it will reach the trap and would probably
1141 * die with a core dump.
1142 * Thus, we are force our way in by taking out two instructions
1143 * and insert an eternal loop instead, in expectance of the SIGSTOP
1144 * generated by out PTRACE_ATTACH.
1145 * Of cause, if we evaporate ourselves in the middle of all this...
1146 */
1147 errno = 0;
1148 ptrace(PTRACE_POKETEXT, tcp->pid, (char *) tcp->baddr, LOOPA);
1149 if(errno) {
1150 perror("setbpt: ptrace(PTRACE_POKETEXT, ...)");
1151 return -1;
1152 }
1153 tcp->flags |= TCB_BPTSET;
1154
1155#else /* !SPARC */
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00001156#ifdef IA64
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00001157 if (ia32) {
1158# define LOOP 0x0000feeb
1159 if (tcp->flags & TCB_BPTSET) {
1160 fprintf(stderr, "PANIC: bpt already set in pid %u\n",
1161 tcp->pid);
1162 return -1;
1163 }
1164 if (upeek(tcp->pid, PT_CR_IIP, &tcp->baddr) < 0)
1165 return -1;
1166 if (debug)
1167 fprintf(stderr, "[%d] setting bpt at %lx\n",
1168 tcp->pid, tcp->baddr);
1169 tcp->inst[0] = ptrace(PTRACE_PEEKTEXT, tcp->pid,
1170 (char *) tcp->baddr, 0);
1171 if (errno) {
1172 perror("setbpt: ptrace(PTRACE_PEEKTEXT, ...)");
1173 return -1;
1174 }
1175 ptrace(PTRACE_POKETEXT, tcp->pid, (char *) tcp->baddr, LOOP);
1176 if (errno) {
1177 perror("setbpt: ptrace(PTRACE_POKETEXT, ...)");
1178 return -1;
1179 }
1180 tcp->flags |= TCB_BPTSET;
1181 } else {
1182 /*
1183 * XXX Use break instead!
1184 *
1185 * Our strategy here is to replace the bundle that
1186 * contained the clone() syscall with a bundle of the
1187 * form:
1188 *
1189 * { 1: br 1b; br 1b; br 1b }
1190 *
1191 * This ensures that the newly forked child will loop
1192 * endlessly until we've got a chance to attach to it.
1193 */
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00001194# define LOOP0 0x0000100000000017
1195# define LOOP1 0x4000000000200000
1196 unsigned long addr, ipsr;
1197 pid_t pid;
1198
1199 pid = tcp->pid;
1200 if (upeek(pid, PT_CR_IPSR, &ipsr) < 0)
1201 return -1;
1202 if (upeek(pid, PT_CR_IIP, &addr) < 0)
1203 return -1;
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00001204 /* store "ri" in low two bits */
1205 tcp->baddr = addr | ((ipsr >> 41) & 0x3);
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00001206
1207 errno = 0;
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00001208 tcp->inst[0] = ptrace(PTRACE_PEEKTEXT, pid, (char *) addr + 0,
1209 0);
1210 tcp->inst[1] = ptrace(PTRACE_PEEKTEXT, pid, (char *) addr + 8,
1211 0);
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00001212 if (errno) {
1213 perror("setbpt: ptrace(PTRACE_PEEKTEXT, ...)");
1214 return -1;
1215 }
1216
1217 errno = 0;
1218 ptrace(PTRACE_POKETEXT, pid, (char *) addr + 0, LOOP0);
1219 ptrace(PTRACE_POKETEXT, pid, (char *) addr + 8, LOOP1);
1220 if (errno) {
1221 perror("setbpt: ptrace(PTRACE_POKETEXT, ...)");
1222 return -1;
1223 }
1224 tcp->flags |= TCB_BPTSET;
1225 }
1226#else /* !IA64 */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001227
Michal Ludvig0e035502002-09-23 15:41:01 +00001228#if defined (I386) || defined(X86_64)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001229#define LOOP 0x0000feeb
1230#elif defined (M68K)
1231#define LOOP 0x60fe0000
1232#elif defined (ALPHA)
Wichert Akkerman4dc8a2a1999-12-23 14:20:14 +00001233#define LOOP 0xc3ffffff
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001234#elif defined (POWERPC)
Wichert Akkerman4dc8a2a1999-12-23 14:20:14 +00001235#define LOOP 0x0000feeb
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001236#elif defined(ARM)
Wichert Akkerman9a8a37f1999-12-24 23:19:31 +00001237#define LOOP 0xEAFFFFFE
Wichert Akkermanf90da011999-10-31 21:15:38 +00001238#elif defined(MIPS)
Wichert Akkerman4dc8a2a1999-12-23 14:20:14 +00001239#define LOOP 0x1000ffff
1240#elif defined(S390)
1241#define LOOP 0xa7f40000 /* BRC 15,0 */
Wichert Akkermanc1652e22001-03-27 12:17:16 +00001242#elif defined(HPPA)
1243#define LOOP 0xe81f1ff7 /* b,l,n <loc>,r0 */
Wichert Akkermanccef6372002-05-01 16:39:22 +00001244#elif defined(SH)
1245#ifdef __LITTLE_ENDIAN__
1246#define LOOP 0x0000affe
1247#else
1248#define LOOP 0xfeaf0000
1249#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001250#else
1251#error unknown architecture
1252#endif
1253
1254 if (tcp->flags & TCB_BPTSET) {
1255 fprintf(stderr, "PANIC: bpt already set in pid %u\n", tcp->pid);
1256 return -1;
1257 }
1258#if defined (I386)
1259 if (upeek(tcp->pid, 4*EIP, &tcp->baddr) < 0)
1260 return -1;
Michal Ludvig0e035502002-09-23 15:41:01 +00001261#elif defined (X86_64)
1262 if (upeek(tcp->pid, 8*RIP, &tcp->baddr) < 0)
1263 return -1;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001264#elif defined (M68K)
1265 if (upeek(tcp->pid, 4*PT_PC, &tcp->baddr) < 0)
1266 return -1;
1267#elif defined (ALPHA)
1268 return -1;
1269#elif defined (ARM)
1270 return -1;
Wichert Akkermanf90da011999-10-31 21:15:38 +00001271#elif defined (MIPS)
1272 return -1; /* FIXME: I do not know what i do - Flo */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001273#elif defined (POWERPC)
1274 if (upeek(tcp->pid, 4*PT_NIP, &tcp->baddr) < 0)
1275 return -1;
Wichert Akkerman4dc8a2a1999-12-23 14:20:14 +00001276#elif defined(S390)
1277 if (upeek(tcp->pid,PT_PSWADDR, &tcp->baddr) < 0)
1278 return -1;
Wichert Akkermanc1652e22001-03-27 12:17:16 +00001279#elif defined(HPPA)
1280 if (upeek(tcp->pid, PT_IAOQ0, &tcp->baddr) < 0)
1281 return -1;
1282 tcp->baddr &= ~0x03;
Wichert Akkermanccef6372002-05-01 16:39:22 +00001283#elif defined(SH)
1284 if (upeek(tcp->pid, 4*REG_PC, &tcp->baddr) < 0)
1285 return -1;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001286#else
1287#error unknown architecture
1288#endif
1289 if (debug)
1290 fprintf(stderr, "[%d] setting bpt at %lx\n", tcp->pid, tcp->baddr);
1291 tcp->inst[0] = ptrace(PTRACE_PEEKTEXT, tcp->pid, (char *) tcp->baddr, 0);
1292 if (errno) {
1293 perror("setbpt: ptrace(PTRACE_PEEKTEXT, ...)");
1294 return -1;
1295 }
1296 ptrace(PTRACE_POKETEXT, tcp->pid, (char *) tcp->baddr, LOOP);
1297 if (errno) {
1298 perror("setbpt: ptrace(PTRACE_POKETEXT, ...)");
1299 return -1;
1300 }
1301 tcp->flags |= TCB_BPTSET;
1302
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00001303#endif /* !IA64 */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001304#endif /* SPARC */
1305#endif /* LINUX */
1306
1307#ifdef SUNOS4
1308#ifdef SPARC /* This code is slightly sparc specific */
1309
Wichert Akkermane6f876c1999-06-22 15:28:30 +00001310 struct regs regs;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001311#define BPT 0x91d02001 /* ta 1 */
1312#define LOOP 0x10800000 /* ba 0 */
1313#define LOOPA 0x30800000 /* ba,a 0 */
1314#define NOP 0x01000000
1315#if LOOPA
1316 static int loopdeloop[1] = {LOOPA};
1317#else
1318 static int loopdeloop[2] = {LOOP, NOP};
1319#endif
1320
1321 if (tcp->flags & TCB_BPTSET) {
1322 fprintf(stderr, "PANIC: TCB already set in pid %u\n", tcp->pid);
1323 return -1;
1324 }
1325 if (ptrace(PTRACE_GETREGS, tcp->pid, (char *)&regs, 0) < 0) {
1326 perror("setbpt: ptrace(PTRACE_GETREGS, ...)");
1327 return -1;
1328 }
1329 tcp->baddr = regs.r_o7 + 8;
1330 if (ptrace(PTRACE_READTEXT, tcp->pid, (char *)tcp->baddr,
1331 sizeof tcp->inst, (char *)tcp->inst) < 0) {
1332 perror("setbpt: ptrace(PTRACE_READTEXT, ...)");
1333 return -1;
1334 }
1335
1336 /*
1337 * XXX - BRUTAL MODE ON
1338 * We cannot set a real BPT in the child, since it will not be
1339 * traced at the moment it will reach the trap and would probably
1340 * die with a core dump.
1341 * Thus, we are force our way in by taking out two instructions
1342 * and insert an eternal loop in stead, in expectance of the SIGSTOP
1343 * generated by out PTRACE_ATTACH.
1344 * Of cause, if we evaporate ourselves in the middle of all this...
1345 */
1346 if (ptrace(PTRACE_WRITETEXT, tcp->pid, (char *) tcp->baddr,
1347 sizeof loopdeloop, (char *) loopdeloop) < 0) {
1348 perror("setbpt: ptrace(PTRACE_WRITETEXT, ...)");
1349 return -1;
1350 }
1351 tcp->flags |= TCB_BPTSET;
1352
1353#endif /* SPARC */
1354#endif /* SUNOS4 */
1355
1356 return 0;
1357}
1358
1359int
1360clearbpt(tcp)
1361struct tcb *tcp;
1362{
1363
1364#ifdef LINUX
Michal Ludvig0e035502002-09-23 15:41:01 +00001365#if defined(I386) || defined(X86_64)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001366 long eip;
Wichert Akkermanfaf72222000-02-19 23:59:03 +00001367#elif defined(POWERPC)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001368 long pc;
Wichert Akkermanfaf72222000-02-19 23:59:03 +00001369#elif defined(M68K)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001370 long pc;
Wichert Akkermanfaf72222000-02-19 23:59:03 +00001371#elif defined(ALPHA)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001372 long pc;
Wichert Akkermanc1652e22001-03-27 12:17:16 +00001373#elif defined(HPPA)
1374 long iaoq;
Wichert Akkermanccef6372002-05-01 16:39:22 +00001375#elif defined(SH)
1376 long pc;
Wichert Akkermanfaf72222000-02-19 23:59:03 +00001377#endif /* architecture */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001378
1379#ifdef SPARC
1380 /* Again, we borrow the SunOS breakpoint code. */
1381 if (!(tcp->flags & TCB_BPTSET)) {
1382 fprintf(stderr, "PANIC: TCB not set in pid %u\n", tcp->pid);
1383 return -1;
1384 }
1385 errno = 0;
1386 ptrace(PTRACE_POKETEXT, tcp->pid, (char *) tcp->baddr, tcp->inst[0]);
1387 if(errno) {
1388 perror("clearbtp: ptrace(PTRACE_POKETEXT, ...)");
1389 return -1;
1390 }
1391 tcp->flags &= ~TCB_BPTSET;
Wichert Akkermanfaf72222000-02-19 23:59:03 +00001392#elif defined(IA64)
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00001393 if (ia32) {
1394 unsigned long addr;
1395
1396 if (debug)
1397 fprintf(stderr, "[%d] clearing bpt\n", tcp->pid);
1398 if (!(tcp->flags & TCB_BPTSET)) {
1399 fprintf(stderr, "PANIC: TCB not set in pid %u\n", tcp->pid);
1400 return -1;
1401 }
1402 errno = 0;
1403 ptrace(PTRACE_POKETEXT, tcp->pid, (char *) tcp->baddr, tcp->inst[0]);
1404 if (errno) {
1405 perror("clearbtp: ptrace(PTRACE_POKETEXT, ...)");
1406 return -1;
1407 }
1408 tcp->flags &= ~TCB_BPTSET;
1409
1410 if (upeek(tcp->pid, PT_CR_IIP, &addr) < 0)
1411 return -1;
1412 if (addr != tcp->baddr) {
1413 /* The breakpoint has not been reached yet. */
1414 if (debug)
1415 fprintf(stderr,
1416 "NOTE: PC not at bpt (pc %#lx baddr %#lx)\n",
1417 addr, tcp->baddr);
1418 return 0;
1419 }
1420 } else {
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00001421 unsigned long addr, ipsr;
1422 pid_t pid;
1423
1424 pid = tcp->pid;
1425
1426 if (upeek(pid, PT_CR_IPSR, &ipsr) < 0)
1427 return -1;
1428 if (upeek(pid, PT_CR_IIP, &addr) < 0)
1429 return -1;
1430
1431 /* restore original bundle: */
1432 errno = 0;
1433 ptrace(PTRACE_POKETEXT, pid, (char *) addr + 0, tcp->inst[0]);
1434 ptrace(PTRACE_POKETEXT, pid, (char *) addr + 8, tcp->inst[1]);
1435 if (errno) {
1436 perror("clearbpt: ptrace(PTRACE_POKETEXT, ...)");
1437 return -1;
1438 }
1439
1440 /* restore original "ri" in ipsr: */
1441 ipsr = (ipsr & ~(0x3ul << 41)) | ((tcp->baddr & 0x3) << 41);
1442 errno = 0;
1443 ptrace(PTRACE_POKEUSER, pid, (char *) PT_CR_IPSR, ipsr);
1444 if (errno) {
1445 perror("clrbpt: ptrace(PTRACE_POKEUSER, ...)");
1446 return -1;
1447 }
1448
1449 tcp->flags &= ~TCB_BPTSET;
1450
1451 if (addr != (tcp->baddr & ~0x3)) {
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 addr, tcp->baddr);
1456 return 0;
1457 }
1458 }
Wichert Akkermanfaf72222000-02-19 23:59:03 +00001459#else /* !IA64 && ! SPARC */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001460
1461 if (debug)
1462 fprintf(stderr, "[%d] clearing bpt\n", tcp->pid);
1463 if (!(tcp->flags & TCB_BPTSET)) {
1464 fprintf(stderr, "PANIC: TCB not set in pid %u\n", tcp->pid);
1465 return -1;
1466 }
1467 errno = 0;
1468 ptrace(PTRACE_POKETEXT, tcp->pid, (char *) tcp->baddr, tcp->inst[0]);
1469 if (errno) {
1470 perror("clearbtp: ptrace(PTRACE_POKETEXT, ...)");
1471 return -1;
1472 }
1473 tcp->flags &= ~TCB_BPTSET;
1474
1475#ifdef I386
1476 if (upeek(tcp->pid, 4*EIP, &eip) < 0)
1477 return -1;
1478 if (eip != tcp->baddr) {
1479 /* The breakpoint has not been reached yet. */
1480 if (debug)
1481 fprintf(stderr,
1482 "NOTE: PC not at bpt (pc %#lx baddr %#lx)\n",
1483 eip, tcp->baddr);
1484 return 0;
1485 }
Michal Ludvig0e035502002-09-23 15:41:01 +00001486#elif defined(X86_64)
1487 if (upeek(tcp->pid, 8*RIP, &eip) < 0)
1488 return -1;
1489 if (eip != tcp->baddr) {
1490 /* The breakpoint has not been reached yet. */
1491 if (debug)
1492 fprintf(stderr,
1493 "NOTE: PC not at bpt (pc %#lx baddr %#lx)\n",
1494 eip, tcp->baddr);
1495 return 0;
1496 }
Wichert Akkermanc7926982000-04-10 22:22:31 +00001497#elif defined(POWERPC)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001498 if (upeek(tcp->pid, 4*PT_NIP, &pc) < 0)
1499 return -1;
1500 if (pc != tcp->baddr) {
1501 /* The breakpoint has not been reached yet. */
1502 if (debug)
1503 fprintf(stderr, "NOTE: PC not at bpt (pc %#lx baddr %#lx)\n",
1504 pc, tcp->baddr);
1505 return 0;
1506 }
Wichert Akkermanfaf72222000-02-19 23:59:03 +00001507#elif defined(M68K)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001508 if (upeek(tcp->pid, 4*PT_PC, &pc) < 0)
1509 return -1;
1510 if (pc != tcp->baddr) {
1511 /* The breakpoint has not been reached yet. */
1512 if (debug)
1513 fprintf(stderr, "NOTE: PC not at bpt (pc %#lx baddr %#lx)\n",
1514 pc, tcp->baddr);
1515 return 0;
1516 }
Wichert Akkermanfaf72222000-02-19 23:59:03 +00001517#elif defined(ALPHA)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001518 if (upeek(tcp->pid, REG_PC, &pc) < 0)
1519 return -1;
1520 if (pc != tcp->baddr) {
1521 /* The breakpoint has not been reached yet. */
1522 if (debug)
1523 fprintf(stderr, "NOTE: PC not at bpt (pc %#lx baddr %#lx)\n",
1524 pc, tcp->baddr);
1525 return 0;
1526 }
Wichert Akkermanc1652e22001-03-27 12:17:16 +00001527#elif defined(HPPA)
1528 if (upeek(tcp->pid, PT_IAOQ0, &iaoq) < 0)
1529 return -1;
1530 iaoq &= ~0x03;
1531 if (iaoq != tcp->baddr && iaoq != tcp->baddr + 4) {
1532 /* The breakpoint has not been reached yet. */
1533 if (debug)
1534 fprintf(stderr, "NOTE: PC not at bpt (iaoq %#lx baddr %#lx)\n",
1535 iaoq, tcp->baddr);
1536 return 0;
1537 }
1538 iaoq = tcp->baddr | 3;
1539 /* We should be pointing at a 'ldi -1000,r1' in glibc, so it is
1540 * safe to set both IAOQ0 and IAOQ1 to that so the PSW N bit
1541 * has no significant effect.
1542 */
1543 ptrace(PTRACE_POKEUSER, tcp->pid, (void *)PT_IAOQ0, iaoq);
1544 ptrace(PTRACE_POKEUSER, tcp->pid, (void *)PT_IAOQ1, iaoq);
Wichert Akkermanccef6372002-05-01 16:39:22 +00001545#elif defined(SH)
1546 if (upeek(tcp->pid, 4*REG_PC, &pc) < 0)
1547 return -1;
1548 if (pc != tcp->baddr) {
1549 /* The breakpoint has not been reached yet. */
1550 if (debug)
1551 fprintf(stderr, "NOTE: PC not at bpt (pc %#lx baddr %#lx)\n",
1552 pc, tcp->baddr);
1553 return 0;
1554 }
1555
Wichert Akkermanfaf72222000-02-19 23:59:03 +00001556#endif /* arch */
1557#endif /* !SPARC && !IA64 */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001558#endif /* LINUX */
1559
1560#ifdef SUNOS4
1561#ifdef SPARC
1562
1563#if !LOOPA
Wichert Akkermane6f876c1999-06-22 15:28:30 +00001564 struct regs regs;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001565#endif
1566
1567 if (!(tcp->flags & TCB_BPTSET)) {
1568 fprintf(stderr, "PANIC: TCB not set in pid %u\n", tcp->pid);
1569 return -1;
1570 }
1571 if (ptrace(PTRACE_WRITETEXT, tcp->pid, (char *) tcp->baddr,
1572 sizeof tcp->inst, (char *) tcp->inst) < 0) {
1573 perror("clearbtp: ptrace(PTRACE_WRITETEXT, ...)");
1574 return -1;
1575 }
1576 tcp->flags &= ~TCB_BPTSET;
1577
1578#if !LOOPA
1579 /*
1580 * Since we don't have a single instruction breakpoint, we may have
1581 * to adjust the program counter after removing the our `breakpoint'.
1582 */
1583 if (ptrace(PTRACE_GETREGS, tcp->pid, (char *)&regs, 0) < 0) {
1584 perror("clearbpt: ptrace(PTRACE_GETREGS, ...)");
1585 return -1;
1586 }
1587 if ((regs.r_pc < tcp->baddr) ||
1588 (regs.r_pc > tcp->baddr + 4)) {
1589 /* The breakpoint has not been reached yet */
1590 if (debug)
1591 fprintf(stderr,
1592 "NOTE: PC not at bpt (pc %#x baddr %#x)\n",
1593 regs.r_pc, tcp->parent->baddr);
1594 return 0;
1595 }
1596 if (regs.r_pc != tcp->baddr)
1597 if (debug)
1598 fprintf(stderr, "NOTE: PC adjusted (%#x -> %#x\n",
1599 regs.r_pc, tcp->baddr);
1600
1601 regs.r_pc = tcp->baddr;
1602 if (ptrace(PTRACE_SETREGS, tcp->pid, (char *)&regs, 0) < 0) {
1603 perror("clearbpt: ptrace(PTRACE_SETREGS, ...)");
1604 return -1;
1605 }
1606#endif /* LOOPA */
1607#endif /* SPARC */
1608#endif /* SUNOS4 */
1609
1610 return 0;
1611}
1612
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001613#endif /* !USE_PROCFS */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001614
1615#ifdef SUNOS4
1616
1617static int
1618getex(pid, hdr)
1619int pid;
1620struct exec *hdr;
1621{
1622 int n;
1623
1624 for (n = 0; n < sizeof *hdr; n += 4) {
1625 long res;
1626 if (upeek(pid, uoff(u_exdata) + n, &res) < 0)
1627 return -1;
1628 memcpy(((char *) hdr) + n, &res, 4);
1629 }
1630 if (debug) {
1631 fprintf(stderr, "[struct exec: magic: %o version %u Mach %o\n",
1632 hdr->a_magic, hdr->a_toolversion, hdr->a_machtype);
1633 fprintf(stderr, "Text %lu Data %lu Bss %lu Syms %lu Entry %#lx]\n",
1634 hdr->a_text, hdr->a_data, hdr->a_bss, hdr->a_syms, hdr->a_entry);
1635 }
1636 return 0;
1637}
1638
1639int
1640fixvfork(tcp)
1641struct tcb *tcp;
1642{
1643 int pid = tcp->pid;
1644 /*
1645 * Change `vfork' in a freshly exec'ed dynamically linked
1646 * executable's (internal) symbol table to plain old `fork'
1647 */
1648
1649 struct exec hdr;
1650 struct link_dynamic dyn;
1651 struct link_dynamic_2 ld;
1652 char *strtab, *cp;
1653
1654 if (getex(pid, &hdr) < 0)
1655 return -1;
1656 if (!hdr.a_dynamic)
1657 return -1;
1658
1659 if (umove(tcp, (int) N_DATADDR(hdr), &dyn) < 0) {
1660 fprintf(stderr, "Cannot read DYNAMIC\n");
1661 return -1;
1662 }
1663 if (umove(tcp, (int) dyn.ld_un.ld_2, &ld) < 0) {
1664 fprintf(stderr, "Cannot read link_dynamic_2\n");
1665 return -1;
1666 }
1667 if ((strtab = malloc((unsigned)ld.ld_symb_size)) == NULL) {
1668 fprintf(stderr, "fixvfork: out of memory\n");
1669 return -1;
1670 }
1671 if (umoven(tcp, (int)ld.ld_symbols+(int)N_TXTADDR(hdr),
1672 (int)ld.ld_symb_size, strtab) < 0)
1673 goto err;
1674
1675#if 0
1676 for (cp = strtab; cp < strtab + ld.ld_symb_size; ) {
1677 fprintf(stderr, "[symbol: %s]\n", cp);
1678 cp += strlen(cp)+1;
1679 }
1680 return 0;
1681#endif
1682 for (cp = strtab; cp < strtab + ld.ld_symb_size; ) {
1683 if (strcmp(cp, "_vfork") == 0) {
1684 if (debug)
1685 fprintf(stderr, "fixvfork: FOUND _vfork\n");
1686 strcpy(cp, "_fork");
1687 break;
1688 }
1689 cp += strlen(cp)+1;
1690 }
1691 if (cp < strtab + ld.ld_symb_size)
1692 /*
1693 * Write entire symbol table back to avoid
1694 * memory alignment bugs in ptrace
1695 */
1696 if (tload(pid, (int)ld.ld_symbols+(int)N_TXTADDR(hdr),
1697 (int)ld.ld_symb_size, strtab) < 0)
1698 goto err;
1699
1700 free(strtab);
1701 return 0;
1702
1703err:
1704 free(strtab);
1705 return -1;
1706}
1707
1708#endif /* SUNOS4 */