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