blob: a6a245cadd761607cbc86982075596089b804a95 [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>
Roland McGrath1e85cf92002-12-16 20:40:54 +000052#endif
Wichert Akkerman36915a11999-07-13 15:45:02 +000053
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
Roland McGrath1e85cf92002-12-16 20:40:54 +0000480
John Hughes1d08dcf2001-07-10 13:48:44 +0000481 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) {
Roland McGrath1e85cf92002-12-16 20:40:54 +0000487
John Hughes1d08dcf2001-07-10 13:48:44 +0000488 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);
Roland McGrath1e85cf92002-12-16 20:40:54 +0000498
John Hughes1d08dcf2001-07-10 13:48:44 +0000499}
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) {
Roland McGrath1e85cf92002-12-16 20:40:54 +0000911 char buf[60];
Michal Ludvig0e035502002-09-23 15:41:01 +0000912 sprintf(buf,"upeek: ptrace(PTRACE_PEEKUSER,%d,%lu,0)",pid,off);
Roland McGrath1e85cf92002-12-16 20:40:54 +0000913 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;
Michal Ludvig10a88d02002-10-07 14:31:00 +0000958#elif defined(S390) || defined(S390X)
Wichert Akkerman4dc8a2a1999-12-23 14:20:14 +0000959 if(upeek(tcp->pid,PT_PSWADDR,&pc) < 0)
Michal Ludvig10a88d02002-10-07 14:31:00 +0000960 return -1;
Wichert Akkermanc1652e22001-03-27 12:17:16 +0000961#elif defined(HPPA)
962 if(upeek(tcp->pid,PT_IAOQ0,&pc) < 0)
963 return -1;
Wichert Akkermanccef6372002-05-01 16:39:22 +0000964#elif defined(SH)
965 if (upeek(tcp->pid, 4*REG_PC ,&pc) < 0)
966 return -1;
Wichert Akkerman7a0b6491999-12-23 15:08:17 +0000967#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000968 return pc;
969#endif /* LINUX */
970
971#ifdef SUNOS4
972 /*
973 * Return current program counter for `pid'
974 * Assumes PC is never 0xffffffff
975 */
976 struct regs regs;
977
978 if (ptrace(PTRACE_GETREGS, tcp->pid, (char *) &regs, 0) < 0) {
979 perror("getpc: ptrace(PTRACE_GETREGS, ...)");
980 return -1;
981 }
982 return regs.r_pc;
983#endif /* SUNOS4 */
984
985#ifdef SVR4
986 /* XXX */
987 return 0;
988#endif /* SVR4 */
989
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +0000990#ifdef FREEBSD
991 struct reg regs;
992 pread(tcp->pfd_reg, &regs, sizeof(regs), 0);
993 return regs.r_eip;
994#endif /* FREEBSD */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000995}
996
997void
998printcall(tcp)
999struct tcb *tcp;
1000{
1001
1002#ifdef LINUX
1003#ifdef I386
1004 long eip;
1005
1006 if (upeek(tcp->pid, 4*EIP, &eip) < 0) {
1007 tprintf("[????????] ");
1008 return;
1009 }
1010 tprintf("[%08lx] ", eip);
Michal Ludvig0e035502002-09-23 15:41:01 +00001011#elif defined(X86_64)
1012 long rip;
1013
1014 if (upeek(tcp->pid, 8*RIP, &rip) < 0) {
1015 tprintf("[????????] ");
1016 return;
1017 }
1018 tprintf("[%16lx] ", rip);
Wichert Akkermanfaf72222000-02-19 23:59:03 +00001019#elif defined(IA62)
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00001020 long ip;
1021
1022 if (upeek(tcp->pid, PT_B0, &ip) < 0) {
1023 tprintf("[????????] ");
1024 return;
1025 }
1026 tprintf("[%08lx] ", ip);
Wichert Akkermanfaf72222000-02-19 23:59:03 +00001027#elif defined(POWERPC)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001028 long pc;
1029
1030 if (upeek(tcp->pid, 4*PT_NIP, &pc) < 0) {
1031 tprintf ("[????????] ");
1032 return;
1033 }
1034 tprintf("[%08lx] ", pc);
Wichert Akkermanfaf72222000-02-19 23:59:03 +00001035#elif defined(M68k)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001036 long pc;
1037
1038 if (upeek(tcp->pid, 4*PT_PC, &pc) < 0) {
1039 tprintf ("[????????] ");
1040 return;
1041 }
1042 tprintf("[%08lx] ", pc);
Wichert Akkermanfaf72222000-02-19 23:59:03 +00001043#elif defined(ALPHA)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001044 long pc;
1045
1046 if (upeek(tcp->pid, REG_PC, &pc) < 0) {
1047 tprintf ("[????????] ");
1048 return;
1049 }
1050 tprintf("[%08lx] ", pc);
Wichert Akkermanfaf72222000-02-19 23:59:03 +00001051#elif defined(SPARC)
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001052 struct regs regs;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001053 if (ptrace(PTRACE_GETREGS,tcp->pid,(char *)&regs,0) < 0) {
1054 tprintf("[????????] ");
1055 return;
1056 }
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001057 tprintf("[%08lx] ", regs.r_pc);
Wichert Akkermanc1652e22001-03-27 12:17:16 +00001058#elif defined(HPPA)
1059 long pc;
1060
1061 if(upeek(tcp->pid,PT_IAOQ0,&pc) < 0) {
1062 tprintf ("[????????] ");
1063 return;
1064 }
1065 tprintf("[%08lx] ", pc);
Wichert Akkerman75c422b2001-04-10 10:22:50 +00001066#elif defined(MIPS)
1067 long pc;
1068
1069 if (upeek(tcp->pid, REG_EPC, &pc) < 0) {
1070 tprintf ("[????????] ");
1071 return;
1072 }
1073 tprintf("[%08lx] ", pc);
Wichert Akkermanccef6372002-05-01 16:39:22 +00001074#elif defined(SH)
1075 long pc;
1076
1077 if (upeek(tcp->pid, 4*REG_PC, &pc) < 0) {
1078 tprintf ("[????????] ");
1079 return;
1080 }
1081 tprintf("[%08lx] ", pc);
Wichert Akkermanfaf72222000-02-19 23:59:03 +00001082#endif /* !architecture */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001083#endif /* LINUX */
1084
1085#ifdef SUNOS4
1086 struct regs regs;
1087
1088 if (ptrace(PTRACE_GETREGS, tcp->pid, (char *) &regs, 0) < 0) {
1089 perror("printcall: ptrace(PTRACE_GETREGS, ...)");
1090 tprintf("[????????] ");
1091 return;
1092 }
1093 tprintf("[%08x] ", regs.r_o7);
1094#endif /* SUNOS4 */
1095
1096#ifdef SVR4
1097 /* XXX */
1098 tprintf("[????????] ");
1099#endif
1100
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001101#ifdef FREEBSD
1102 struct reg regs;
1103 pread(tcp->pfd_reg, &regs, sizeof(regs), 0);
1104 tprintf("[%08x] ", regs.r_eip);
1105#endif /* FREEBSD */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001106}
1107
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001108#ifndef USE_PROCFS
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001109
1110int
1111setbpt(tcp)
1112struct tcb *tcp;
1113{
1114
1115#ifdef LINUX
1116#ifdef SPARC
1117 /* We simply use the SunOS breakpoint code. */
1118
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001119 struct regs regs;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001120#define LOOPA 0x30800000 /* ba,a 0 */
1121
1122 if (tcp->flags & TCB_BPTSET) {
1123 fprintf(stderr, "PANIC: TCB already set in pid %u\n", tcp->pid);
1124 return -1;
1125 }
1126 if (ptrace(PTRACE_GETREGS, tcp->pid, (char *)&regs, 0) < 0) {
1127 perror("setbpt: ptrace(PTRACE_GETREGS, ...)");
1128 return -1;
1129 }
Wichert Akkerman9ce1a631999-08-29 23:15:07 +00001130 tcp->baddr = regs.r_o7 + 8;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001131 errno = 0;
1132 tcp->inst[0] = ptrace(PTRACE_PEEKTEXT, tcp->pid, (char *)tcp->baddr, 0);
1133 if(errno) {
1134 perror("setbpt: ptrace(PTRACE_PEEKTEXT, ...)");
1135 return -1;
1136 }
1137
1138 /*
1139 * XXX - BRUTAL MODE ON
1140 * We cannot set a real BPT in the child, since it will not be
1141 * traced at the moment it will reach the trap and would probably
1142 * die with a core dump.
1143 * Thus, we are force our way in by taking out two instructions
1144 * and insert an eternal loop instead, in expectance of the SIGSTOP
1145 * generated by out PTRACE_ATTACH.
1146 * Of cause, if we evaporate ourselves in the middle of all this...
1147 */
1148 errno = 0;
1149 ptrace(PTRACE_POKETEXT, tcp->pid, (char *) tcp->baddr, LOOPA);
1150 if(errno) {
1151 perror("setbpt: ptrace(PTRACE_POKETEXT, ...)");
1152 return -1;
1153 }
1154 tcp->flags |= TCB_BPTSET;
1155
1156#else /* !SPARC */
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00001157#ifdef IA64
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00001158 if (ia32) {
1159# define LOOP 0x0000feeb
1160 if (tcp->flags & TCB_BPTSET) {
1161 fprintf(stderr, "PANIC: bpt already set in pid %u\n",
1162 tcp->pid);
1163 return -1;
1164 }
1165 if (upeek(tcp->pid, PT_CR_IIP, &tcp->baddr) < 0)
1166 return -1;
1167 if (debug)
1168 fprintf(stderr, "[%d] setting bpt at %lx\n",
1169 tcp->pid, tcp->baddr);
1170 tcp->inst[0] = ptrace(PTRACE_PEEKTEXT, tcp->pid,
1171 (char *) tcp->baddr, 0);
1172 if (errno) {
1173 perror("setbpt: ptrace(PTRACE_PEEKTEXT, ...)");
1174 return -1;
1175 }
1176 ptrace(PTRACE_POKETEXT, tcp->pid, (char *) tcp->baddr, LOOP);
1177 if (errno) {
1178 perror("setbpt: ptrace(PTRACE_POKETEXT, ...)");
1179 return -1;
1180 }
1181 tcp->flags |= TCB_BPTSET;
1182 } else {
1183 /*
1184 * XXX Use break instead!
1185 *
1186 * Our strategy here is to replace the bundle that
1187 * contained the clone() syscall with a bundle of the
1188 * form:
1189 *
1190 * { 1: br 1b; br 1b; br 1b }
1191 *
1192 * This ensures that the newly forked child will loop
1193 * endlessly until we've got a chance to attach to it.
1194 */
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00001195# define LOOP0 0x0000100000000017
1196# define LOOP1 0x4000000000200000
1197 unsigned long addr, ipsr;
1198 pid_t pid;
1199
1200 pid = tcp->pid;
1201 if (upeek(pid, PT_CR_IPSR, &ipsr) < 0)
1202 return -1;
1203 if (upeek(pid, PT_CR_IIP, &addr) < 0)
1204 return -1;
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00001205 /* store "ri" in low two bits */
1206 tcp->baddr = addr | ((ipsr >> 41) & 0x3);
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00001207
1208 errno = 0;
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00001209 tcp->inst[0] = ptrace(PTRACE_PEEKTEXT, pid, (char *) addr + 0,
1210 0);
1211 tcp->inst[1] = ptrace(PTRACE_PEEKTEXT, pid, (char *) addr + 8,
1212 0);
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00001213 if (errno) {
1214 perror("setbpt: ptrace(PTRACE_PEEKTEXT, ...)");
1215 return -1;
1216 }
1217
1218 errno = 0;
1219 ptrace(PTRACE_POKETEXT, pid, (char *) addr + 0, LOOP0);
1220 ptrace(PTRACE_POKETEXT, pid, (char *) addr + 8, LOOP1);
1221 if (errno) {
1222 perror("setbpt: ptrace(PTRACE_POKETEXT, ...)");
1223 return -1;
1224 }
1225 tcp->flags |= TCB_BPTSET;
1226 }
1227#else /* !IA64 */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001228
Michal Ludvig0e035502002-09-23 15:41:01 +00001229#if defined (I386) || defined(X86_64)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001230#define LOOP 0x0000feeb
1231#elif defined (M68K)
1232#define LOOP 0x60fe0000
1233#elif defined (ALPHA)
Wichert Akkerman4dc8a2a1999-12-23 14:20:14 +00001234#define LOOP 0xc3ffffff
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001235#elif defined (POWERPC)
Roland McGrath1e85cf92002-12-16 20:40:54 +00001236#define LOOP 0x48000000
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001237#elif defined(ARM)
Wichert Akkerman9a8a37f1999-12-24 23:19:31 +00001238#define LOOP 0xEAFFFFFE
Wichert Akkermanf90da011999-10-31 21:15:38 +00001239#elif defined(MIPS)
Wichert Akkerman4dc8a2a1999-12-23 14:20:14 +00001240#define LOOP 0x1000ffff
1241#elif defined(S390)
1242#define LOOP 0xa7f40000 /* BRC 15,0 */
Michal Ludvig10a88d02002-10-07 14:31:00 +00001243#elif defined(S390X)
1244#define LOOP 0xa7f4000000000000UL /* BRC 15,0 */
Wichert Akkermanc1652e22001-03-27 12:17:16 +00001245#elif defined(HPPA)
1246#define LOOP 0xe81f1ff7 /* b,l,n <loc>,r0 */
Wichert Akkermanccef6372002-05-01 16:39:22 +00001247#elif defined(SH)
1248#ifdef __LITTLE_ENDIAN__
1249#define LOOP 0x0000affe
1250#else
1251#define LOOP 0xfeaf0000
1252#endif
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001253#else
1254#error unknown architecture
1255#endif
1256
1257 if (tcp->flags & TCB_BPTSET) {
1258 fprintf(stderr, "PANIC: bpt already set in pid %u\n", tcp->pid);
1259 return -1;
1260 }
1261#if defined (I386)
1262 if (upeek(tcp->pid, 4*EIP, &tcp->baddr) < 0)
1263 return -1;
Michal Ludvig0e035502002-09-23 15:41:01 +00001264#elif defined (X86_64)
1265 if (upeek(tcp->pid, 8*RIP, &tcp->baddr) < 0)
1266 return -1;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001267#elif defined (M68K)
1268 if (upeek(tcp->pid, 4*PT_PC, &tcp->baddr) < 0)
1269 return -1;
1270#elif defined (ALPHA)
1271 return -1;
1272#elif defined (ARM)
1273 return -1;
Wichert Akkermanf90da011999-10-31 21:15:38 +00001274#elif defined (MIPS)
1275 return -1; /* FIXME: I do not know what i do - Flo */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001276#elif defined (POWERPC)
1277 if (upeek(tcp->pid, 4*PT_NIP, &tcp->baddr) < 0)
1278 return -1;
Michal Ludvig10a88d02002-10-07 14:31:00 +00001279#elif defined(S390) || defined(S390X)
Wichert Akkerman4dc8a2a1999-12-23 14:20:14 +00001280 if (upeek(tcp->pid,PT_PSWADDR, &tcp->baddr) < 0)
1281 return -1;
Wichert Akkermanc1652e22001-03-27 12:17:16 +00001282#elif defined(HPPA)
1283 if (upeek(tcp->pid, PT_IAOQ0, &tcp->baddr) < 0)
1284 return -1;
1285 tcp->baddr &= ~0x03;
Wichert Akkermanccef6372002-05-01 16:39:22 +00001286#elif defined(SH)
1287 if (upeek(tcp->pid, 4*REG_PC, &tcp->baddr) < 0)
1288 return -1;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001289#else
1290#error unknown architecture
1291#endif
1292 if (debug)
1293 fprintf(stderr, "[%d] setting bpt at %lx\n", tcp->pid, tcp->baddr);
1294 tcp->inst[0] = ptrace(PTRACE_PEEKTEXT, tcp->pid, (char *) tcp->baddr, 0);
1295 if (errno) {
1296 perror("setbpt: ptrace(PTRACE_PEEKTEXT, ...)");
1297 return -1;
1298 }
1299 ptrace(PTRACE_POKETEXT, tcp->pid, (char *) tcp->baddr, LOOP);
1300 if (errno) {
1301 perror("setbpt: ptrace(PTRACE_POKETEXT, ...)");
1302 return -1;
1303 }
1304 tcp->flags |= TCB_BPTSET;
1305
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00001306#endif /* !IA64 */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001307#endif /* SPARC */
1308#endif /* LINUX */
1309
1310#ifdef SUNOS4
1311#ifdef SPARC /* This code is slightly sparc specific */
1312
Wichert Akkermane6f876c1999-06-22 15:28:30 +00001313 struct regs regs;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001314#define BPT 0x91d02001 /* ta 1 */
1315#define LOOP 0x10800000 /* ba 0 */
1316#define LOOPA 0x30800000 /* ba,a 0 */
1317#define NOP 0x01000000
1318#if LOOPA
1319 static int loopdeloop[1] = {LOOPA};
1320#else
1321 static int loopdeloop[2] = {LOOP, NOP};
1322#endif
1323
1324 if (tcp->flags & TCB_BPTSET) {
1325 fprintf(stderr, "PANIC: TCB already set in pid %u\n", tcp->pid);
1326 return -1;
1327 }
1328 if (ptrace(PTRACE_GETREGS, tcp->pid, (char *)&regs, 0) < 0) {
1329 perror("setbpt: ptrace(PTRACE_GETREGS, ...)");
1330 return -1;
1331 }
1332 tcp->baddr = regs.r_o7 + 8;
1333 if (ptrace(PTRACE_READTEXT, tcp->pid, (char *)tcp->baddr,
1334 sizeof tcp->inst, (char *)tcp->inst) < 0) {
1335 perror("setbpt: ptrace(PTRACE_READTEXT, ...)");
1336 return -1;
1337 }
1338
1339 /*
1340 * XXX - BRUTAL MODE ON
1341 * We cannot set a real BPT in the child, since it will not be
1342 * traced at the moment it will reach the trap and would probably
1343 * die with a core dump.
1344 * Thus, we are force our way in by taking out two instructions
1345 * and insert an eternal loop in stead, in expectance of the SIGSTOP
1346 * generated by out PTRACE_ATTACH.
1347 * Of cause, if we evaporate ourselves in the middle of all this...
1348 */
1349 if (ptrace(PTRACE_WRITETEXT, tcp->pid, (char *) tcp->baddr,
1350 sizeof loopdeloop, (char *) loopdeloop) < 0) {
1351 perror("setbpt: ptrace(PTRACE_WRITETEXT, ...)");
1352 return -1;
1353 }
1354 tcp->flags |= TCB_BPTSET;
1355
1356#endif /* SPARC */
1357#endif /* SUNOS4 */
1358
1359 return 0;
1360}
1361
1362int
1363clearbpt(tcp)
1364struct tcb *tcp;
1365{
1366
1367#ifdef LINUX
Michal Ludvig0e035502002-09-23 15:41:01 +00001368#if defined(I386) || defined(X86_64)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001369 long eip;
Wichert Akkermanfaf72222000-02-19 23:59:03 +00001370#elif defined(POWERPC)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001371 long pc;
Wichert Akkermanfaf72222000-02-19 23:59:03 +00001372#elif defined(M68K)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001373 long pc;
Wichert Akkermanfaf72222000-02-19 23:59:03 +00001374#elif defined(ALPHA)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001375 long pc;
Wichert Akkermanc1652e22001-03-27 12:17:16 +00001376#elif defined(HPPA)
1377 long iaoq;
Wichert Akkermanccef6372002-05-01 16:39:22 +00001378#elif defined(SH)
1379 long pc;
Wichert Akkermanfaf72222000-02-19 23:59:03 +00001380#endif /* architecture */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001381
1382#ifdef SPARC
1383 /* Again, we borrow the SunOS breakpoint code. */
1384 if (!(tcp->flags & TCB_BPTSET)) {
1385 fprintf(stderr, "PANIC: TCB not set in pid %u\n", tcp->pid);
1386 return -1;
1387 }
1388 errno = 0;
1389 ptrace(PTRACE_POKETEXT, tcp->pid, (char *) tcp->baddr, tcp->inst[0]);
1390 if(errno) {
1391 perror("clearbtp: ptrace(PTRACE_POKETEXT, ...)");
1392 return -1;
1393 }
1394 tcp->flags &= ~TCB_BPTSET;
Wichert Akkermanfaf72222000-02-19 23:59:03 +00001395#elif defined(IA64)
Wichert Akkerman7b3346b2001-10-09 23:47:38 +00001396 if (ia32) {
1397 unsigned long addr;
1398
1399 if (debug)
1400 fprintf(stderr, "[%d] clearing bpt\n", tcp->pid);
1401 if (!(tcp->flags & TCB_BPTSET)) {
1402 fprintf(stderr, "PANIC: TCB not set in pid %u\n", tcp->pid);
1403 return -1;
1404 }
1405 errno = 0;
1406 ptrace(PTRACE_POKETEXT, tcp->pid, (char *) tcp->baddr, tcp->inst[0]);
1407 if (errno) {
1408 perror("clearbtp: ptrace(PTRACE_POKETEXT, ...)");
1409 return -1;
1410 }
1411 tcp->flags &= ~TCB_BPTSET;
1412
1413 if (upeek(tcp->pid, PT_CR_IIP, &addr) < 0)
1414 return -1;
1415 if (addr != tcp->baddr) {
1416 /* The breakpoint has not been reached yet. */
1417 if (debug)
1418 fprintf(stderr,
1419 "NOTE: PC not at bpt (pc %#lx baddr %#lx)\n",
1420 addr, tcp->baddr);
1421 return 0;
1422 }
1423 } else {
Wichert Akkerman8b1b40c2000-02-03 21:58:30 +00001424 unsigned long addr, ipsr;
1425 pid_t pid;
1426
1427 pid = tcp->pid;
1428
1429 if (upeek(pid, PT_CR_IPSR, &ipsr) < 0)
1430 return -1;
1431 if (upeek(pid, PT_CR_IIP, &addr) < 0)
1432 return -1;
1433
1434 /* restore original bundle: */
1435 errno = 0;
1436 ptrace(PTRACE_POKETEXT, pid, (char *) addr + 0, tcp->inst[0]);
1437 ptrace(PTRACE_POKETEXT, pid, (char *) addr + 8, tcp->inst[1]);
1438 if (errno) {
1439 perror("clearbpt: ptrace(PTRACE_POKETEXT, ...)");
1440 return -1;
1441 }
1442
1443 /* restore original "ri" in ipsr: */
1444 ipsr = (ipsr & ~(0x3ul << 41)) | ((tcp->baddr & 0x3) << 41);
1445 errno = 0;
1446 ptrace(PTRACE_POKEUSER, pid, (char *) PT_CR_IPSR, ipsr);
1447 if (errno) {
1448 perror("clrbpt: ptrace(PTRACE_POKEUSER, ...)");
1449 return -1;
1450 }
1451
1452 tcp->flags &= ~TCB_BPTSET;
1453
1454 if (addr != (tcp->baddr & ~0x3)) {
1455 /* the breakpoint has not been reached yet. */
1456 if (debug)
1457 fprintf(stderr, "NOTE: PC not at bpt (pc %#lx baddr %#lx)\n",
1458 addr, tcp->baddr);
1459 return 0;
1460 }
1461 }
Wichert Akkermanfaf72222000-02-19 23:59:03 +00001462#else /* !IA64 && ! SPARC */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001463
1464 if (debug)
1465 fprintf(stderr, "[%d] clearing bpt\n", tcp->pid);
1466 if (!(tcp->flags & TCB_BPTSET)) {
1467 fprintf(stderr, "PANIC: TCB not set in pid %u\n", tcp->pid);
1468 return -1;
1469 }
1470 errno = 0;
1471 ptrace(PTRACE_POKETEXT, tcp->pid, (char *) tcp->baddr, tcp->inst[0]);
1472 if (errno) {
1473 perror("clearbtp: ptrace(PTRACE_POKETEXT, ...)");
1474 return -1;
1475 }
1476 tcp->flags &= ~TCB_BPTSET;
1477
1478#ifdef I386
1479 if (upeek(tcp->pid, 4*EIP, &eip) < 0)
1480 return -1;
1481 if (eip != tcp->baddr) {
1482 /* The breakpoint has not been reached yet. */
1483 if (debug)
1484 fprintf(stderr,
1485 "NOTE: PC not at bpt (pc %#lx baddr %#lx)\n",
1486 eip, tcp->baddr);
1487 return 0;
1488 }
Michal Ludvig0e035502002-09-23 15:41:01 +00001489#elif defined(X86_64)
1490 if (upeek(tcp->pid, 8*RIP, &eip) < 0)
1491 return -1;
1492 if (eip != tcp->baddr) {
1493 /* The breakpoint has not been reached yet. */
1494 if (debug)
1495 fprintf(stderr,
1496 "NOTE: PC not at bpt (pc %#lx baddr %#lx)\n",
1497 eip, tcp->baddr);
1498 return 0;
1499 }
Wichert Akkermanc7926982000-04-10 22:22:31 +00001500#elif defined(POWERPC)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001501 if (upeek(tcp->pid, 4*PT_NIP, &pc) < 0)
1502 return -1;
1503 if (pc != tcp->baddr) {
1504 /* The breakpoint has not been reached yet. */
1505 if (debug)
1506 fprintf(stderr, "NOTE: PC not at bpt (pc %#lx baddr %#lx)\n",
1507 pc, tcp->baddr);
1508 return 0;
1509 }
Wichert Akkermanfaf72222000-02-19 23:59:03 +00001510#elif defined(M68K)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001511 if (upeek(tcp->pid, 4*PT_PC, &pc) < 0)
1512 return -1;
1513 if (pc != tcp->baddr) {
1514 /* The breakpoint has not been reached yet. */
1515 if (debug)
1516 fprintf(stderr, "NOTE: PC not at bpt (pc %#lx baddr %#lx)\n",
1517 pc, tcp->baddr);
1518 return 0;
1519 }
Wichert Akkermanfaf72222000-02-19 23:59:03 +00001520#elif defined(ALPHA)
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001521 if (upeek(tcp->pid, REG_PC, &pc) < 0)
1522 return -1;
1523 if (pc != tcp->baddr) {
1524 /* The breakpoint has not been reached yet. */
1525 if (debug)
1526 fprintf(stderr, "NOTE: PC not at bpt (pc %#lx baddr %#lx)\n",
1527 pc, tcp->baddr);
1528 return 0;
1529 }
Wichert Akkermanc1652e22001-03-27 12:17:16 +00001530#elif defined(HPPA)
1531 if (upeek(tcp->pid, PT_IAOQ0, &iaoq) < 0)
1532 return -1;
1533 iaoq &= ~0x03;
1534 if (iaoq != tcp->baddr && iaoq != tcp->baddr + 4) {
1535 /* The breakpoint has not been reached yet. */
1536 if (debug)
1537 fprintf(stderr, "NOTE: PC not at bpt (iaoq %#lx baddr %#lx)\n",
1538 iaoq, tcp->baddr);
1539 return 0;
1540 }
1541 iaoq = tcp->baddr | 3;
1542 /* We should be pointing at a 'ldi -1000,r1' in glibc, so it is
1543 * safe to set both IAOQ0 and IAOQ1 to that so the PSW N bit
1544 * has no significant effect.
1545 */
1546 ptrace(PTRACE_POKEUSER, tcp->pid, (void *)PT_IAOQ0, iaoq);
1547 ptrace(PTRACE_POKEUSER, tcp->pid, (void *)PT_IAOQ1, iaoq);
Wichert Akkermanccef6372002-05-01 16:39:22 +00001548#elif defined(SH)
1549 if (upeek(tcp->pid, 4*REG_PC, &pc) < 0)
1550 return -1;
1551 if (pc != tcp->baddr) {
1552 /* The breakpoint has not been reached yet. */
1553 if (debug)
1554 fprintf(stderr, "NOTE: PC not at bpt (pc %#lx baddr %#lx)\n",
1555 pc, tcp->baddr);
1556 return 0;
1557 }
1558
Wichert Akkermanfaf72222000-02-19 23:59:03 +00001559#endif /* arch */
1560#endif /* !SPARC && !IA64 */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001561#endif /* LINUX */
1562
1563#ifdef SUNOS4
1564#ifdef SPARC
1565
1566#if !LOOPA
Wichert Akkermane6f876c1999-06-22 15:28:30 +00001567 struct regs regs;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001568#endif
1569
1570 if (!(tcp->flags & TCB_BPTSET)) {
1571 fprintf(stderr, "PANIC: TCB not set in pid %u\n", tcp->pid);
1572 return -1;
1573 }
1574 if (ptrace(PTRACE_WRITETEXT, tcp->pid, (char *) tcp->baddr,
1575 sizeof tcp->inst, (char *) tcp->inst) < 0) {
1576 perror("clearbtp: ptrace(PTRACE_WRITETEXT, ...)");
1577 return -1;
1578 }
1579 tcp->flags &= ~TCB_BPTSET;
1580
1581#if !LOOPA
1582 /*
1583 * Since we don't have a single instruction breakpoint, we may have
1584 * to adjust the program counter after removing the our `breakpoint'.
1585 */
1586 if (ptrace(PTRACE_GETREGS, tcp->pid, (char *)&regs, 0) < 0) {
1587 perror("clearbpt: ptrace(PTRACE_GETREGS, ...)");
1588 return -1;
1589 }
1590 if ((regs.r_pc < tcp->baddr) ||
1591 (regs.r_pc > tcp->baddr + 4)) {
1592 /* The breakpoint has not been reached yet */
1593 if (debug)
1594 fprintf(stderr,
1595 "NOTE: PC not at bpt (pc %#x baddr %#x)\n",
1596 regs.r_pc, tcp->parent->baddr);
1597 return 0;
1598 }
1599 if (regs.r_pc != tcp->baddr)
1600 if (debug)
1601 fprintf(stderr, "NOTE: PC adjusted (%#x -> %#x\n",
1602 regs.r_pc, tcp->baddr);
1603
1604 regs.r_pc = tcp->baddr;
1605 if (ptrace(PTRACE_SETREGS, tcp->pid, (char *)&regs, 0) < 0) {
1606 perror("clearbpt: ptrace(PTRACE_SETREGS, ...)");
1607 return -1;
1608 }
1609#endif /* LOOPA */
1610#endif /* SPARC */
1611#endif /* SUNOS4 */
1612
1613 return 0;
1614}
1615
Wichert Akkermanbf79f2e2000-09-01 21:03:06 +00001616#endif /* !USE_PROCFS */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +00001617
1618#ifdef SUNOS4
1619
1620static int
1621getex(pid, hdr)
1622int pid;
1623struct exec *hdr;
1624{
1625 int n;
1626
1627 for (n = 0; n < sizeof *hdr; n += 4) {
1628 long res;
1629 if (upeek(pid, uoff(u_exdata) + n, &res) < 0)
1630 return -1;
1631 memcpy(((char *) hdr) + n, &res, 4);
1632 }
1633 if (debug) {
1634 fprintf(stderr, "[struct exec: magic: %o version %u Mach %o\n",
1635 hdr->a_magic, hdr->a_toolversion, hdr->a_machtype);
1636 fprintf(stderr, "Text %lu Data %lu Bss %lu Syms %lu Entry %#lx]\n",
1637 hdr->a_text, hdr->a_data, hdr->a_bss, hdr->a_syms, hdr->a_entry);
1638 }
1639 return 0;
1640}
1641
1642int
1643fixvfork(tcp)
1644struct tcb *tcp;
1645{
1646 int pid = tcp->pid;
1647 /*
1648 * Change `vfork' in a freshly exec'ed dynamically linked
1649 * executable's (internal) symbol table to plain old `fork'
1650 */
1651
1652 struct exec hdr;
1653 struct link_dynamic dyn;
1654 struct link_dynamic_2 ld;
1655 char *strtab, *cp;
1656
1657 if (getex(pid, &hdr) < 0)
1658 return -1;
1659 if (!hdr.a_dynamic)
1660 return -1;
1661
1662 if (umove(tcp, (int) N_DATADDR(hdr), &dyn) < 0) {
1663 fprintf(stderr, "Cannot read DYNAMIC\n");
1664 return -1;
1665 }
1666 if (umove(tcp, (int) dyn.ld_un.ld_2, &ld) < 0) {
1667 fprintf(stderr, "Cannot read link_dynamic_2\n");
1668 return -1;
1669 }
1670 if ((strtab = malloc((unsigned)ld.ld_symb_size)) == NULL) {
1671 fprintf(stderr, "fixvfork: out of memory\n");
1672 return -1;
1673 }
1674 if (umoven(tcp, (int)ld.ld_symbols+(int)N_TXTADDR(hdr),
1675 (int)ld.ld_symb_size, strtab) < 0)
1676 goto err;
1677
1678#if 0
1679 for (cp = strtab; cp < strtab + ld.ld_symb_size; ) {
1680 fprintf(stderr, "[symbol: %s]\n", cp);
1681 cp += strlen(cp)+1;
1682 }
1683 return 0;
1684#endif
1685 for (cp = strtab; cp < strtab + ld.ld_symb_size; ) {
1686 if (strcmp(cp, "_vfork") == 0) {
1687 if (debug)
1688 fprintf(stderr, "fixvfork: FOUND _vfork\n");
1689 strcpy(cp, "_fork");
1690 break;
1691 }
1692 cp += strlen(cp)+1;
1693 }
1694 if (cp < strtab + ld.ld_symb_size)
1695 /*
1696 * Write entire symbol table back to avoid
1697 * memory alignment bugs in ptrace
1698 */
1699 if (tload(pid, (int)ld.ld_symbols+(int)N_TXTADDR(hdr),
1700 (int)ld.ld_symb_size, strtab) < 0)
1701 goto err;
1702
1703 free(strtab);
1704 return 0;
1705
1706err:
1707 free(strtab);
1708 return -1;
1709}
1710
1711#endif /* SUNOS4 */