blob: 6fd726ce14be83202eb398fd3f6209ae4d9b6cc9 [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>
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * 3. The name of the author may not be used to endorse or promote products
16 * derived from this software without specific prior written permission.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
19 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
20 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
21 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
22 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
23 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
27 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 *
29 * $Id$
30 */
31
32#include "defs.h"
33
34#include <sys/user.h>
35#include <sys/param.h>
36#include <fcntl.h>
37#ifdef SUNOS4
38#include <machine/reg.h>
39#include <a.out.h>
40#include <link.h>
41#endif /* SUNOS4 */
42#if __GLIBC__ == 2 && __GLIBC_MINOR__ >= 1
43# include <sys/reg.h>
44# define PTRACE_PEEKUSR PTRACE_PEEKUSER
45#endif
46#ifdef LINUX
47#include <linux/ptrace.h>
48#endif /* LINUX */
49
50#ifdef SUNOS4_KERNEL_ARCH_KLUDGE
51#include <sys/utsname.h>
52#endif /* SUNOS4_KERNEL_ARCH_KLUDGE */
53
54#if defined(LINUX) && defined(SPARC) && !defined(__GLIBC__)
55
56#include <linux/unistd.h>
57
58#define _hack_syscall5(type,name,type1,arg1,type2,arg2,type3,arg3,type4,arg4,\
59 type5,arg5,syscall) \
60type name (type1 arg1,type2 arg2,type3 arg3,type4 arg4,type5 arg5) \
61{ \
62 long __res; \
63\
64__asm__ volatile ("or %%g0, %1, %%o0\n\t" \
65 "or %%g0, %2, %%o1\n\t" \
66 "or %%g0, %3, %%o2\n\t" \
67 "or %%g0, %4, %%o3\n\t" \
68 "or %%g0, %5, %%o4\n\t" \
69 "or %%g0, %6, %%g1\n\t" \
70 "t 0x10\n\t" \
71 "bcc 1f\n\t" \
72 "or %%g0, %%o0, %0\n\t" \
73 "sub %%g0, %%o0, %0\n\t" \
74 "1:\n\t" \
75 : "=r" (__res) \
76 : "0" ((long)(arg1)),"1" ((long)(arg2)), \
77 "2" ((long)(arg3)),"3" ((long)(arg4)),"4" ((long)(arg5)), \
78 "i" (__NR_##syscall) \
79 : "g1", "o0", "o1", "o2", "o3", "o4"); \
80if (__res>=0) \
81 return (type) __res; \
82errno = -__res; \
83return -1; \
84}
85
86static _hack_syscall5(int,_ptrace,int,__request,int,__pid,int,__addr,int,__data,int,__addr2,ptrace)
87
88#define _ptrace
89
90#endif
91
92/* macros */
93#ifndef MAX
94#define MAX(a,b) (((a) > (b)) ? (a) : (b))
95#endif
96#ifndef MIN
97#define MIN(a,b) (((a) < (b)) ? (a) : (b))
98#endif
99
100void
101tv_tv(tv, a, b)
102struct timeval *tv;
103int a;
104int b;
105{
106 tv->tv_sec = a;
107 tv->tv_usec = b;
108}
109
110int
111tv_nz(a)
112struct timeval *a;
113{
114 return a->tv_sec || a->tv_usec;
115}
116
117int
118tv_cmp(a, b)
119struct timeval *a, *b;
120{
121 if (a->tv_sec < b->tv_sec
122 || (a->tv_sec == b->tv_sec && a->tv_usec < b->tv_usec))
123 return -1;
124 if (a->tv_sec > b->tv_sec
125 || (a->tv_sec == b->tv_sec && a->tv_usec > b->tv_usec))
126 return 1;
127 return 0;
128}
129
130double
131tv_float(tv)
132struct timeval *tv;
133{
134 return tv->tv_sec + tv->tv_usec/1000000.0;
135}
136
137void
138tv_add(tv, a, b)
139struct timeval *tv, *a, *b;
140{
141 tv->tv_sec = a->tv_sec + b->tv_sec;
142 tv->tv_usec = a->tv_usec + b->tv_usec;
143 if (tv->tv_usec > 1000000) {
144 tv->tv_sec++;
145 tv->tv_usec -= 1000000;
146 }
147}
148
149void
150tv_sub(tv, a, b)
151struct timeval *tv, *a, *b;
152{
153 tv->tv_sec = a->tv_sec - b->tv_sec;
154 tv->tv_usec = a->tv_usec - b->tv_usec;
155 if (((long) tv->tv_usec) < 0) {
156 tv->tv_sec--;
157 tv->tv_usec += 1000000;
158 }
159}
160
161void
162tv_div(tv, a, n)
163struct timeval *tv, *a;
164int n;
165{
166 tv->tv_usec = (a->tv_sec % n * 1000000 + a->tv_usec + n / 2) / n;
167 tv->tv_sec = a->tv_sec / n + tv->tv_usec / 1000000;
168 tv->tv_usec %= 1000000;
169}
170
171void
172tv_mul(tv, a, n)
173struct timeval *tv, *a;
174int n;
175{
176 tv->tv_usec = a->tv_usec * n;
177 tv->tv_sec = a->tv_sec * n + a->tv_usec / 1000000;
178 tv->tv_usec %= 1000000;
179}
180
181char *
182xlookup(xlat, val)
183struct xlat *xlat;
184int val;
185{
186 for (; xlat->str != NULL; xlat++)
187 if (xlat->val == val)
188 return xlat->str;
189 return NULL;
190}
191
192/*
193 * Print entry in struct xlat table, if there.
194 */
195void
196printxval(xlat, val, dflt)
197struct xlat *xlat;
198int val;
199char *dflt;
200{
201 char *str = xlookup(xlat, val);
202
203 if (str)
204 tprintf("%s", str);
205 else
206 tprintf("%#x /* %s */", val, dflt);
207}
208
209/*
210 * Interpret `xlat' as an array of flags
211 * print the entries whose bits are on in `flags'
212 * return # of flags printed.
213 */
214int
215addflags(xlat, flags)
216struct xlat *xlat;
217int flags;
218{
219 int n;
220
221 for (n = 0; xlat->str; xlat++) {
222 if (xlat->val && (flags & xlat->val) == xlat->val) {
223 tprintf("|%s", xlat->str);
224 flags &= ~xlat->val;
225 n++;
226 }
227 }
228 if (flags) {
229 tprintf("|%#x", flags);
230 n++;
231 }
232 return n;
233}
234
235int
236printflags(xlat, flags)
237struct xlat *xlat;
238int flags;
239{
240 int n;
241 char *sep;
242
243 if (flags == 0 && xlat->val == 0) {
244 tprintf("%s", xlat->str);
245 return 1;
246 }
247
248 sep = "";
249 for (n = 0; xlat->str; xlat++) {
250 if (xlat->val && (flags & xlat->val) == xlat->val) {
251 tprintf("%s%s", sep, xlat->str);
252 flags &= ~xlat->val;
253 sep = "|";
254 n++;
255 }
256 }
257 if (flags) {
258 tprintf("%s%#x", sep, flags);
259 n++;
260 }
261 return n;
262}
263
264void
265printnum(tcp, addr, fmt)
266struct tcb *tcp;
267long addr;
268char *fmt;
269{
270 int num;
271
272 if (!addr) {
273 tprintf("NULL");
274 return;
275 }
276 if (umove(tcp, addr, &num) < 0) {
277 tprintf("%#lx", addr);
278 return;
279 }
280 tprintf("[");
281 tprintf(fmt, num);
282 tprintf("]");
283}
284
285static char path[MAXPATHLEN + 1];
286
287void
288string_quote(str)
289char *str;
290{
291 char buf[2 * MAXPATHLEN + 1];
292 char *s;
293
294 if (!strpbrk(str, "\"\'\\")) {
295 tprintf("\"%s\"", str);
296 return;
297 }
298 for (s = buf; *str; str++) {
299 switch (*str) {
300 case '\"': case '\'': case '\\':
301 *s++ = '\\'; *s++ = *str; break;
302 default:
303 *s++ = *str; break;
304 }
305 }
306 *s = '\0';
307 tprintf("\"%s\"", buf);
308}
309
310void
311printpath(tcp, addr)
312struct tcb *tcp;
313long addr;
314{
315 if (umovestr(tcp, addr, MAXPATHLEN, path) < 0)
316 tprintf("%#lx", addr);
317 else
318 string_quote(path);
319 return;
320}
321
322void
323printpathn(tcp, addr, n)
324struct tcb *tcp;
325long addr;
326int n;
327{
328 if (umovestr(tcp, addr, n, path) < 0)
329 tprintf("%#lx", addr);
330 else {
331 path[n] = '\0';
332 string_quote(path);
333 }
334}
335
336void
337printstr(tcp, addr, len)
338struct tcb *tcp;
339long addr;
340int len;
341{
342 static unsigned char *str = NULL;
343 static char *outstr;
344 int i, n, c, usehex;
345 char *s, *outend;
346
347 if (!addr) {
348 tprintf("NULL");
349 return;
350 }
351 if (!str) {
352 if ((str = malloc(max_strlen)) == NULL
353 || (outstr = malloc(2*max_strlen)) == NULL) {
354 fprintf(stderr, "printstr: no memory\n");
355 tprintf("%#lx", addr);
356 return;
357 }
358 }
359 outend = outstr + max_strlen;
360 if (len < 0) {
361 n = max_strlen;
362 if (umovestr(tcp, addr, n, (char *) str) < 0) {
363 tprintf("%#lx", addr);
364 return;
365 }
366 }
367 else {
368 n = MIN(len, max_strlen);
369 if (umoven(tcp, addr, n, (char *) str) < 0) {
370 tprintf("%#lx", addr);
371 return;
372 }
373 }
374
375 usehex = 0;
376 if (xflag > 1)
377 usehex = 1;
378 else if (xflag) {
379 for (i = 0; i < n; i++) {
380 c = str[i];
381 if (len < 0 && c == '\0')
382 break;
383 if (!isprint(c) && !isspace(c)) {
384 usehex = 1;
385 break;
386 }
387 }
388 }
389
390 s = outstr;
391 *s++ = '\"';
392
393 if (usehex) {
394 for (i = 0; i < n; i++) {
395 c = str[i];
396 if (len < 0 && c == '\0')
397 break;
398 sprintf(s, "\\x%02x", c);
399 s += 4;
400 if (s > outend)
401 break;
402 }
403 }
404 else {
405 for (i = 0; i < n; i++) {
406 c = str[i];
407 if (len < 0 && c == '\0')
408 break;
409 switch (c) {
410 case '\"': case '\'': case '\\':
411 *s++ = '\\'; *s++ = c; break;
412 case '\f':
413 *s++ = '\\'; *s++ = 'f'; break;
414 case '\n':
415 *s++ = '\\'; *s++ = 'n'; break;
416 case '\r':
417 *s++ = '\\'; *s++ = 'r'; break;
418 case '\t':
419 *s++ = '\\'; *s++ = 't'; break;
420 case '\v':
421 *s++ = '\\'; *s++ = 'v'; break;
422 default:
423 if (isprint(c))
424 *s++ = c;
425 else if (i < n - 1 && isdigit(str[i + 1])) {
426 sprintf(s, "\\%03o", c);
427 s += 4;
428 }
429 else {
430 sprintf(s, "\\%o", c);
431 s += strlen(s);
432 }
433 break;
434 }
435 if (s > outend)
436 break;
437 }
438 }
439
440 *s++ = '\"';
441 if (i < len || (len < 0 && (i == n || s > outend))) {
442 *s++ = '.'; *s++ = '.'; *s++ = '.';
443 }
444 *s = '\0';
445 tprintf("%s", outstr);
446}
447
448void
449dumpstr(tcp, addr, len)
450struct tcb *tcp;
451long addr;
452int len;
453{
454 static int strsize = -1;
455 static unsigned char *str;
456 static char outstr[80];
457 char *s;
458 int i, j;
459
460 if (strsize < len) {
461 if (str)
462 free(str);
463 if ((str = malloc(len)) == NULL) {
464 fprintf(stderr, "dump: no memory\n");
465 return;
466 }
467 strsize = len;
468 }
469
470 if (umoven(tcp, addr, len, (char *) str) < 0)
471 return;
472
473 for (i = 0; i < len; i += 16) {
474 s = outstr;
475 sprintf(s, " | %05x ", i);
476 s += 9;
477 for (j = 0; j < 16; j++) {
478 if (j == 8)
479 *s++ = ' ';
480 if (i + j < len) {
481 sprintf(s, " %02x", str[i + j]);
482 s += 3;
483 }
484 else {
485 *s++ = ' '; *s++ = ' '; *s++ = ' ';
486 }
487 }
488 *s++ = ' '; *s++ = ' ';
489 for (j = 0; j < 16; j++) {
490 if (j == 8)
491 *s++ = ' ';
492 if (i + j < len) {
493 if (isprint(str[i + j]))
494 *s++ = str[i + j];
495 else
496 *s++ = '.';
497 }
498 else
499 *s++ = ' ';
500 }
501 tprintf("%s |\n", outstr);
502 }
503}
504
505#define PAGMASK (~(PAGSIZ - 1))
506/*
507 * move `len' bytes of data from process `pid'
508 * at address `addr' to our space at `laddr'
509 */
510int
511umoven(tcp, addr, len, laddr)
512struct tcb *tcp;
513long addr;
514int len;
515char *laddr;
516{
517
518#ifdef LINUX
519 int pid = tcp->pid;
520 int n, m;
521 union {
522 long val;
523 char x[sizeof(long)];
524 } u;
525
526 if (addr & (sizeof(long) - 1)) {
527 /* addr not a multiple of sizeof(long) */
528 n = addr - (addr & -sizeof(long)); /* residue */
529 addr &= -sizeof(long); /* residue */
530 errno = 0;
531 u.val = ptrace(PTRACE_PEEKDATA, pid, (char *) addr, 0);
532 if (errno) {
533 if (errno==EPERM || errno==EIO) {
534 /* Ran into 'end of memory' - stupid "printpath" */
535 return 0;
536 }
537 perror("ptrace: umoven");
538 return -1;
539 }
540 memcpy(laddr, &u.x[n], m = MIN(sizeof(long) - n, len));
541 addr += sizeof(long), laddr += m, len -= m;
542 }
543 while (len) {
544 errno = 0;
545 u.val = ptrace(PTRACE_PEEKDATA, pid, (char *) addr, 0);
546 if (errno) {
547 if (errno==EPERM || errno==EIO) {
548 /* Ran into 'end of memory' - stupid "printpath" */
549 return 0;
550 }
551 perror("ptrace: umoven");
552 return -1;
553 }
554 memcpy(laddr, u.x, m = MIN(sizeof(long), len));
555 addr += sizeof(long), laddr += m, len -= m;
556 }
557#endif /* LINUX */
558
559#ifdef SUNOS4
560 int pid = tcp->pid;
561#if 0
562 int n, m;
563 union {
564 long val;
565 char x[sizeof(long)];
566 } u;
567
568 if (addr & (sizeof(long) - 1)) {
569 /* addr not a multiple of sizeof(long) */
570 n = addr - (addr & -sizeof(long)); /* residue */
571 addr &= -sizeof(long); /* residue */
572 errno = 0;
573 u.val = ptrace(PTRACE_PEEKDATA, pid, (char *) addr, 0);
574 if (errno) {
575 perror("umoven");
576 return -1;
577 }
578 memcpy(laddr, &u.x[n], m = MIN(sizeof(long) - n, len));
579 addr += sizeof(long), laddr += m, len -= m;
580 }
581 while (len) {
582 errno = 0;
583 u.val = ptrace(PTRACE_PEEKDATA, pid, (char *) addr, 0);
584 if (errno) {
585 perror("umoven");
586 return -1;
587 }
588 memcpy(laddr, u.x, m = MIN(sizeof(long), len));
589 addr += sizeof(long), laddr += m, len -= m;
590 }
591#else /* !oldway */
592 int n;
593
594 while (len) {
595 n = MIN(len, PAGSIZ);
596 n = MIN(n, ((addr + PAGSIZ) & PAGMASK) - addr);
597 if (ptrace(PTRACE_READDATA, pid,
598 (char *) addr, len, laddr) < 0) {
599 perror("umoven: ptrace(PTRACE_READDATA, ...)");
600 abort();
601 return -1;
602 }
603 len -= n;
604 addr += n;
605 laddr += n;
606 }
607#endif /* !oldway */
608#endif /* SUNOS4 */
609
610#ifdef SVR4
611/*
612 * We would like to use pread preferentially for speed
613 * but even though SGI has it in their library, it no longer works.
614 */
615#ifdef MIPS
616#undef HAVE_PREAD
617#endif
618#ifdef HAVE_PREAD
619 if (pread(tcp->pfd, laddr, len, addr) == -1)
620 return -1;
621#else /* !HAVE_PREAD */
622 lseek(tcp->pfd, addr, SEEK_SET);
623 if (read(tcp->pfd, laddr, len) == -1)
624 return -1;
625#endif /* !HAVE_PREAD */
626#endif /* SVR4 */
627
628 return 0;
629}
630
631/*
632 * like `umove' but make the additional effort of looking
633 * for a terminating zero byte.
634 */
635int
636umovestr(tcp, addr, len, laddr)
637struct tcb *tcp;
638long addr;
639int len;
640char *laddr;
641{
642#ifdef SRVR4
643 return umoven(tcp, addr, len, laddr);
644#else /* !SVR4 */
645 int pid = tcp->pid;
646 int i, n, m;
647 union {
648 long val;
649 char x[sizeof(long)];
650 } u;
651
652 if (addr & (sizeof(long) - 1)) {
653 /* addr not a multiple of sizeof(long) */
654 n = addr - (addr & -sizeof(long)); /* residue */
655 addr &= -sizeof(long); /* residue */
656 errno = 0;
657 u.val = ptrace(PTRACE_PEEKDATA, pid, (char *)addr, 0);
658 if (errno) {
659 if (errno==EPERM || errno==EIO) {
660 /* Ran into 'end of memory' - stupid "printpath" */
661 return 0;
662 }
663 perror("umovestr");
664 return -1;
665 }
666 memcpy(laddr, &u.x[n], m = MIN(sizeof(long)-n,len));
667 while (n & (sizeof(long) - 1))
668 if (u.x[n++] == '\0')
669 return 0;
670 addr += sizeof(long), laddr += m, len -= m;
671 }
672 while (len) {
673 errno = 0;
674 u.val = ptrace(PTRACE_PEEKDATA, pid, (char *)addr, 0);
675 if (errno) {
676 if (errno==EPERM || errno==EIO) {
677 /* Ran into 'end of memory' - stupid "printpath" */
678 return 0;
679 }
680 perror("umovestr");
681 return -1;
682 }
683 memcpy(laddr, u.x, m = MIN(sizeof(long), len));
684 for (i = 0; i < sizeof(long); i++)
685 if (u.x[i] == '\0')
686 return 0;
687
688 addr += sizeof(long), laddr += m, len -= m;
689 }
690 return 0;
691#endif /* !SVR4 */
692}
693
694#ifdef LINUX
695#ifndef SPARC
696#define PTRACE_WRITETEXT 101
697#define PTRACE_WRITEDATA 102
698#endif /* !SPARC */
699#endif /* LINUX */
700
701#ifdef SUNOS4
702
703static int
704uload(cmd, pid, addr, len, laddr)
705int cmd;
706int pid;
707long addr;
708int len;
709char *laddr;
710{
711#if 0
712 int n;
713
714 while (len) {
715 n = MIN(len, PAGSIZ);
716 n = MIN(n, ((addr + PAGSIZ) & PAGMASK) - addr);
717 if (ptrace(cmd, pid, (char *)addr, n, laddr) < 0) {
718 perror("uload: ptrace(PTRACE_WRITE, ...)");
719 return -1;
720 }
721 len -= n;
722 addr += n;
723 laddr += n;
724 }
725#else
726 int peek, poke;
727 int n, m;
728 union {
729 long val;
730 char x[sizeof(long)];
731 } u;
732
733 if (cmd == PTRACE_WRITETEXT) {
734 peek = PTRACE_PEEKTEXT;
735 poke = PTRACE_POKETEXT;
736 }
737 else {
738 peek = PTRACE_PEEKDATA;
739 poke = PTRACE_POKEDATA;
740 }
741 if (addr & (sizeof(long) - 1)) {
742 /* addr not a multiple of sizeof(long) */
743 n = addr - (addr & -sizeof(long)); /* residue */
744 addr &= -sizeof(long);
745 errno = 0;
746 u.val = ptrace(peek, pid, (char *) addr, 0);
747 if (errno) {
748 perror("uload: POKE");
749 return -1;
750 }
751 memcpy(&u.x[n], laddr, m = MIN(sizeof(long) - n, len));
752 if (ptrace(poke, pid, (char *)addr, u.val) < 0) {
753 perror("uload: POKE");
754 return -1;
755 }
756 addr += sizeof(long), laddr += m, len -= m;
757 }
758 while (len) {
759 if (len < sizeof(long))
760 u.val = ptrace(peek, pid, (char *) addr, 0);
761 memcpy(u.x, laddr, m = MIN(sizeof(long), len));
762 if (ptrace(poke, pid, (char *) addr, u.val) < 0) {
763 perror("uload: POKE");
764 return -1;
765 }
766 addr += sizeof(long), laddr += m, len -= m;
767 }
768#endif
769 return 0;
770}
771
772int
773tload(pid, addr, len, laddr)
774int pid;
775int addr, len;
776char *laddr;
777{
778 return uload(PTRACE_WRITETEXT, pid, addr, len, laddr);
779}
780
781int
782dload(pid, addr, len, laddr)
783int pid;
784int addr;
785int len;
786char *laddr;
787{
788 return uload(PTRACE_WRITEDATA, pid, addr, len, laddr);
789}
790
791#endif /* SUNOS4 */
792
793#ifndef SVR4
794
795int
796upeek(pid, off, res)
797int pid;
798long off;
799long *res;
800{
801 long val;
802
803#ifdef SUNOS4_KERNEL_ARCH_KLUDGE
804 {
805 static int is_sun4m = -1;
806 struct utsname name;
807
808 /* Round up the usual suspects. */
809 if (is_sun4m == -1) {
810 if (uname(&name) < 0) {
811 perror("upeek: uname?");
812 exit(1);
813 }
814 is_sun4m = strcmp(name.machine, "sun4m") == 0;
815 if (is_sun4m) {
816 extern struct xlat struct_user_offsets[];
817 struct xlat *x;
818
819 for (x = struct_user_offsets; x->str; x++)
820 x->val += 1024;
821 }
822 }
823 if (is_sun4m)
824 off += 1024;
825 }
826#endif /* SUNOS4_KERNEL_ARCH_KLUDGE */
827 errno = 0;
828 val = ptrace(PTRACE_PEEKUSER, pid, (char *) off, 0);
829 if (val == -1 && errno) {
830 perror("upeek: ptrace(PTRACE_PEEKUSER, ... )");
831 return -1;
832 }
833 *res = val;
834 return 0;
835}
836
837#endif /* !SVR4 */
838
839long
840getpc(tcp)
841struct tcb *tcp;
842{
843
844#ifdef LINUX
845 long pc;
846
847#ifdef I386
848 if (upeek(tcp->pid, 4*EIP, &pc) < 0)
849 return -1;
850#else /* !I386 */
851#ifdef ARM
852 if (upeek(tcp->pid, 4*15, &pc) < 0)
853 return -1;
854#else /* !ARM */
855#ifdef POWERPC
856 if (upeek(tcp->pid, 4*PT_NIP, &pc) < 0)
857 return -1;
858#else
859#ifdef M68K
860 if (upeek(tcp->pid, 4*PT_PC, &pc) < 0)
861 return -1;
862#else /* !M68K */
863#ifdef ALPHA
864 if (upeek(tcp->pid, REG_PC, &pc) < 0)
865 return -1;
866#else /* !ALPHA */
867#ifdef SPARC
868 struct pt_regs regs;
869 if (ptrace(PTRACE_GETREGS,tcp->pid,(char *)&regs,0) < 0)
870 return -1;
871 pc = regs.pc;
872#endif /* SPARC */
873#endif /* ALPHA */
874#endif /* !M68K */
875#endif /* !POWERPC */
876#endif /* !ARM */
877#endif /* !I386 */
878 return pc;
879#endif /* LINUX */
880
881#ifdef SUNOS4
882 /*
883 * Return current program counter for `pid'
884 * Assumes PC is never 0xffffffff
885 */
886 struct regs regs;
887
888 if (ptrace(PTRACE_GETREGS, tcp->pid, (char *) &regs, 0) < 0) {
889 perror("getpc: ptrace(PTRACE_GETREGS, ...)");
890 return -1;
891 }
892 return regs.r_pc;
893#endif /* SUNOS4 */
894
895#ifdef SVR4
896 /* XXX */
897 return 0;
898#endif /* SVR4 */
899
900}
901
902void
903printcall(tcp)
904struct tcb *tcp;
905{
906
907#ifdef LINUX
908#ifdef I386
909 long eip;
910
911 if (upeek(tcp->pid, 4*EIP, &eip) < 0) {
912 tprintf("[????????] ");
913 return;
914 }
915 tprintf("[%08lx] ", eip);
916#else /* !I386K */
917#ifdef POWERPC
918 long pc;
919
920 if (upeek(tcp->pid, 4*PT_NIP, &pc) < 0) {
921 tprintf ("[????????] ");
922 return;
923 }
924 tprintf("[%08lx] ", pc);
925#else /* !POWERPC */
926#ifdef M68K
927 long pc;
928
929 if (upeek(tcp->pid, 4*PT_PC, &pc) < 0) {
930 tprintf ("[????????] ");
931 return;
932 }
933 tprintf("[%08lx] ", pc);
934#else /* !M68K */
935#ifdef ALPHA
936 long pc;
937
938 if (upeek(tcp->pid, REG_PC, &pc) < 0) {
939 tprintf ("[????????] ");
940 return;
941 }
942 tprintf("[%08lx] ", pc);
943#else /* !ALPHA */
944#ifdef SPARC
945 struct pt_regs regs;
946 if (ptrace(PTRACE_GETREGS,tcp->pid,(char *)&regs,0) < 0) {
947 tprintf("[????????] ");
948 return;
949 }
950 tprintf("[%08lx] ", regs.pc);
951#endif /* SPARC */
952#endif /* ALPHA */
953#endif /* !M68K */
954#endif /* !POWERPC */
955#endif /* !I386 */
956#endif /* LINUX */
957
958#ifdef SUNOS4
959 struct regs regs;
960
961 if (ptrace(PTRACE_GETREGS, tcp->pid, (char *) &regs, 0) < 0) {
962 perror("printcall: ptrace(PTRACE_GETREGS, ...)");
963 tprintf("[????????] ");
964 return;
965 }
966 tprintf("[%08x] ", regs.r_o7);
967#endif /* SUNOS4 */
968
969#ifdef SVR4
970 /* XXX */
971 tprintf("[????????] ");
972#endif
973
974}
975
976#ifndef SVR4
977
978int
979setbpt(tcp)
980struct tcb *tcp;
981{
982
983#ifdef LINUX
984#ifdef SPARC
985 /* We simply use the SunOS breakpoint code. */
986
987 struct pt_regs regs;
988#define LOOPA 0x30800000 /* ba,a 0 */
989
990 if (tcp->flags & TCB_BPTSET) {
991 fprintf(stderr, "PANIC: TCB already set in pid %u\n", tcp->pid);
992 return -1;
993 }
994 if (ptrace(PTRACE_GETREGS, tcp->pid, (char *)&regs, 0) < 0) {
995 perror("setbpt: ptrace(PTRACE_GETREGS, ...)");
996 return -1;
997 }
998 memmove (&regs.u_regs [1], &regs.u_regs [0],
999 sizeof (regs.u_regs) - sizeof (regs.u_regs [0]));
1000 tcp->baddr = regs.u_regs[UREG_I7] + 8;
1001 errno = 0;
1002 tcp->inst[0] = ptrace(PTRACE_PEEKTEXT, tcp->pid, (char *)tcp->baddr, 0);
1003 if(errno) {
1004 perror("setbpt: ptrace(PTRACE_PEEKTEXT, ...)");
1005 return -1;
1006 }
1007
1008 /*
1009 * XXX - BRUTAL MODE ON
1010 * We cannot set a real BPT in the child, since it will not be
1011 * traced at the moment it will reach the trap and would probably
1012 * die with a core dump.
1013 * Thus, we are force our way in by taking out two instructions
1014 * and insert an eternal loop instead, in expectance of the SIGSTOP
1015 * generated by out PTRACE_ATTACH.
1016 * Of cause, if we evaporate ourselves in the middle of all this...
1017 */
1018 errno = 0;
1019 ptrace(PTRACE_POKETEXT, tcp->pid, (char *) tcp->baddr, LOOPA);
1020 if(errno) {
1021 perror("setbpt: ptrace(PTRACE_POKETEXT, ...)");
1022 return -1;
1023 }
1024 tcp->flags |= TCB_BPTSET;
1025
1026#else /* !SPARC */
1027
1028#if defined (I386)
1029#define LOOP 0x0000feeb
1030#elif defined (M68K)
1031#define LOOP 0x60fe0000
1032#elif defined (ALPHA)
1033#define LOOP 0xc3ffffff
1034#elif defined (POWERPC)
1035#define LOOP 0x0000feeb
1036#elif defined(ARM)
1037#define LOOP -1 /* almost certainly wrong, jws */
1038#else
1039#error unknown architecture
1040#endif
1041
1042 if (tcp->flags & TCB_BPTSET) {
1043 fprintf(stderr, "PANIC: bpt already set in pid %u\n", tcp->pid);
1044 return -1;
1045 }
1046#if defined (I386)
1047 if (upeek(tcp->pid, 4*EIP, &tcp->baddr) < 0)
1048 return -1;
1049#elif defined (M68K)
1050 if (upeek(tcp->pid, 4*PT_PC, &tcp->baddr) < 0)
1051 return -1;
1052#elif defined (ALPHA)
1053 return -1;
1054#elif defined (ARM)
1055 return -1;
1056#elif defined (POWERPC)
1057 if (upeek(tcp->pid, 4*PT_NIP, &tcp->baddr) < 0)
1058 return -1;
1059#else
1060#error unknown architecture
1061#endif
1062 if (debug)
1063 fprintf(stderr, "[%d] setting bpt at %lx\n", tcp->pid, tcp->baddr);
1064 tcp->inst[0] = ptrace(PTRACE_PEEKTEXT, tcp->pid, (char *) tcp->baddr, 0);
1065 if (errno) {
1066 perror("setbpt: ptrace(PTRACE_PEEKTEXT, ...)");
1067 return -1;
1068 }
1069 ptrace(PTRACE_POKETEXT, tcp->pid, (char *) tcp->baddr, LOOP);
1070 if (errno) {
1071 perror("setbpt: ptrace(PTRACE_POKETEXT, ...)");
1072 return -1;
1073 }
1074 tcp->flags |= TCB_BPTSET;
1075
1076#endif /* SPARC */
1077#endif /* LINUX */
1078
1079#ifdef SUNOS4
1080#ifdef SPARC /* This code is slightly sparc specific */
1081
1082 struct pt_regs regs;
1083#define BPT 0x91d02001 /* ta 1 */
1084#define LOOP 0x10800000 /* ba 0 */
1085#define LOOPA 0x30800000 /* ba,a 0 */
1086#define NOP 0x01000000
1087#if LOOPA
1088 static int loopdeloop[1] = {LOOPA};
1089#else
1090 static int loopdeloop[2] = {LOOP, NOP};
1091#endif
1092
1093 if (tcp->flags & TCB_BPTSET) {
1094 fprintf(stderr, "PANIC: TCB already set in pid %u\n", tcp->pid);
1095 return -1;
1096 }
1097 if (ptrace(PTRACE_GETREGS, tcp->pid, (char *)&regs, 0) < 0) {
1098 perror("setbpt: ptrace(PTRACE_GETREGS, ...)");
1099 return -1;
1100 }
1101 tcp->baddr = regs.r_o7 + 8;
1102 if (ptrace(PTRACE_READTEXT, tcp->pid, (char *)tcp->baddr,
1103 sizeof tcp->inst, (char *)tcp->inst) < 0) {
1104 perror("setbpt: ptrace(PTRACE_READTEXT, ...)");
1105 return -1;
1106 }
1107
1108 /*
1109 * XXX - BRUTAL MODE ON
1110 * We cannot set a real BPT in the child, since it will not be
1111 * traced at the moment it will reach the trap and would probably
1112 * die with a core dump.
1113 * Thus, we are force our way in by taking out two instructions
1114 * and insert an eternal loop in stead, in expectance of the SIGSTOP
1115 * generated by out PTRACE_ATTACH.
1116 * Of cause, if we evaporate ourselves in the middle of all this...
1117 */
1118 if (ptrace(PTRACE_WRITETEXT, tcp->pid, (char *) tcp->baddr,
1119 sizeof loopdeloop, (char *) loopdeloop) < 0) {
1120 perror("setbpt: ptrace(PTRACE_WRITETEXT, ...)");
1121 return -1;
1122 }
1123 tcp->flags |= TCB_BPTSET;
1124
1125#endif /* SPARC */
1126#endif /* SUNOS4 */
1127
1128 return 0;
1129}
1130
1131int
1132clearbpt(tcp)
1133struct tcb *tcp;
1134{
1135
1136#ifdef LINUX
1137#ifdef I386
1138 long eip;
1139#else /* !I386 */
1140#ifdef POWERPC
1141 long pc;
1142#else /* !POWERPC */
1143#ifdef M68K
1144 long pc;
1145#else /* !M68K */
1146#ifdef ALPHA
1147 long pc;
1148#endif /* ALPHA */
1149#endif /* !M68K */
1150#endif /* !POWERPC */
1151#endif /* !I386 */
1152
1153#ifdef SPARC
1154 /* Again, we borrow the SunOS breakpoint code. */
1155 if (!(tcp->flags & TCB_BPTSET)) {
1156 fprintf(stderr, "PANIC: TCB not set in pid %u\n", tcp->pid);
1157 return -1;
1158 }
1159 errno = 0;
1160 ptrace(PTRACE_POKETEXT, tcp->pid, (char *) tcp->baddr, tcp->inst[0]);
1161 if(errno) {
1162 perror("clearbtp: ptrace(PTRACE_POKETEXT, ...)");
1163 return -1;
1164 }
1165 tcp->flags &= ~TCB_BPTSET;
1166#else /* !SPARC */
1167
1168 if (debug)
1169 fprintf(stderr, "[%d] clearing bpt\n", tcp->pid);
1170 if (!(tcp->flags & TCB_BPTSET)) {
1171 fprintf(stderr, "PANIC: TCB not set in pid %u\n", tcp->pid);
1172 return -1;
1173 }
1174 errno = 0;
1175 ptrace(PTRACE_POKETEXT, tcp->pid, (char *) tcp->baddr, tcp->inst[0]);
1176 if (errno) {
1177 perror("clearbtp: ptrace(PTRACE_POKETEXT, ...)");
1178 return -1;
1179 }
1180 tcp->flags &= ~TCB_BPTSET;
1181
1182#ifdef I386
1183 if (upeek(tcp->pid, 4*EIP, &eip) < 0)
1184 return -1;
1185 if (eip != tcp->baddr) {
1186 /* The breakpoint has not been reached yet. */
1187 if (debug)
1188 fprintf(stderr,
1189 "NOTE: PC not at bpt (pc %#lx baddr %#lx)\n",
1190 eip, tcp->baddr);
1191 return 0;
1192 }
1193#else /* !I386 */
1194#ifdef POWERPC
1195 if (upeek(tcp->pid, 4*PT_NIP, &pc) < 0)
1196 return -1;
1197 if (pc != tcp->baddr) {
1198 /* The breakpoint has not been reached yet. */
1199 if (debug)
1200 fprintf(stderr, "NOTE: PC not at bpt (pc %#lx baddr %#lx)\n",
1201 pc, tcp->baddr);
1202 return 0;
1203 }
1204#else /* !POWERPC */
1205#ifdef M68K
1206 if (upeek(tcp->pid, 4*PT_PC, &pc) < 0)
1207 return -1;
1208 if (pc != tcp->baddr) {
1209 /* The breakpoint has not been reached yet. */
1210 if (debug)
1211 fprintf(stderr, "NOTE: PC not at bpt (pc %#lx baddr %#lx)\n",
1212 pc, tcp->baddr);
1213 return 0;
1214 }
1215#else /* !M68K */
1216#ifdef ALPHA
1217 if (upeek(tcp->pid, REG_PC, &pc) < 0)
1218 return -1;
1219 if (pc != tcp->baddr) {
1220 /* The breakpoint has not been reached yet. */
1221 if (debug)
1222 fprintf(stderr, "NOTE: PC not at bpt (pc %#lx baddr %#lx)\n",
1223 pc, tcp->baddr);
1224 return 0;
1225 }
1226#endif /* ALPHA */
1227#endif /* !M68K */
1228#endif /* !POWERPC */
1229#endif /* !I386 */
1230#endif /* !SPARC */
1231#endif /* LINUX */
1232
1233#ifdef SUNOS4
1234#ifdef SPARC
1235
1236#if !LOOPA
1237 struct pt_regs regs;
1238#endif
1239
1240 if (!(tcp->flags & TCB_BPTSET)) {
1241 fprintf(stderr, "PANIC: TCB not set in pid %u\n", tcp->pid);
1242 return -1;
1243 }
1244 if (ptrace(PTRACE_WRITETEXT, tcp->pid, (char *) tcp->baddr,
1245 sizeof tcp->inst, (char *) tcp->inst) < 0) {
1246 perror("clearbtp: ptrace(PTRACE_WRITETEXT, ...)");
1247 return -1;
1248 }
1249 tcp->flags &= ~TCB_BPTSET;
1250
1251#if !LOOPA
1252 /*
1253 * Since we don't have a single instruction breakpoint, we may have
1254 * to adjust the program counter after removing the our `breakpoint'.
1255 */
1256 if (ptrace(PTRACE_GETREGS, tcp->pid, (char *)&regs, 0) < 0) {
1257 perror("clearbpt: ptrace(PTRACE_GETREGS, ...)");
1258 return -1;
1259 }
1260 if ((regs.r_pc < tcp->baddr) ||
1261 (regs.r_pc > tcp->baddr + 4)) {
1262 /* The breakpoint has not been reached yet */
1263 if (debug)
1264 fprintf(stderr,
1265 "NOTE: PC not at bpt (pc %#x baddr %#x)\n",
1266 regs.r_pc, tcp->parent->baddr);
1267 return 0;
1268 }
1269 if (regs.r_pc != tcp->baddr)
1270 if (debug)
1271 fprintf(stderr, "NOTE: PC adjusted (%#x -> %#x\n",
1272 regs.r_pc, tcp->baddr);
1273
1274 regs.r_pc = tcp->baddr;
1275 if (ptrace(PTRACE_SETREGS, tcp->pid, (char *)&regs, 0) < 0) {
1276 perror("clearbpt: ptrace(PTRACE_SETREGS, ...)");
1277 return -1;
1278 }
1279#endif /* LOOPA */
1280#endif /* SPARC */
1281#endif /* SUNOS4 */
1282
1283 return 0;
1284}
1285
1286#endif /* !SVR4 */
1287
1288#ifdef SUNOS4
1289
1290static int
1291getex(pid, hdr)
1292int pid;
1293struct exec *hdr;
1294{
1295 int n;
1296
1297 for (n = 0; n < sizeof *hdr; n += 4) {
1298 long res;
1299 if (upeek(pid, uoff(u_exdata) + n, &res) < 0)
1300 return -1;
1301 memcpy(((char *) hdr) + n, &res, 4);
1302 }
1303 if (debug) {
1304 fprintf(stderr, "[struct exec: magic: %o version %u Mach %o\n",
1305 hdr->a_magic, hdr->a_toolversion, hdr->a_machtype);
1306 fprintf(stderr, "Text %lu Data %lu Bss %lu Syms %lu Entry %#lx]\n",
1307 hdr->a_text, hdr->a_data, hdr->a_bss, hdr->a_syms, hdr->a_entry);
1308 }
1309 return 0;
1310}
1311
1312int
1313fixvfork(tcp)
1314struct tcb *tcp;
1315{
1316 int pid = tcp->pid;
1317 /*
1318 * Change `vfork' in a freshly exec'ed dynamically linked
1319 * executable's (internal) symbol table to plain old `fork'
1320 */
1321
1322 struct exec hdr;
1323 struct link_dynamic dyn;
1324 struct link_dynamic_2 ld;
1325 char *strtab, *cp;
1326
1327 if (getex(pid, &hdr) < 0)
1328 return -1;
1329 if (!hdr.a_dynamic)
1330 return -1;
1331
1332 if (umove(tcp, (int) N_DATADDR(hdr), &dyn) < 0) {
1333 fprintf(stderr, "Cannot read DYNAMIC\n");
1334 return -1;
1335 }
1336 if (umove(tcp, (int) dyn.ld_un.ld_2, &ld) < 0) {
1337 fprintf(stderr, "Cannot read link_dynamic_2\n");
1338 return -1;
1339 }
1340 if ((strtab = malloc((unsigned)ld.ld_symb_size)) == NULL) {
1341 fprintf(stderr, "fixvfork: out of memory\n");
1342 return -1;
1343 }
1344 if (umoven(tcp, (int)ld.ld_symbols+(int)N_TXTADDR(hdr),
1345 (int)ld.ld_symb_size, strtab) < 0)
1346 goto err;
1347
1348#if 0
1349 for (cp = strtab; cp < strtab + ld.ld_symb_size; ) {
1350 fprintf(stderr, "[symbol: %s]\n", cp);
1351 cp += strlen(cp)+1;
1352 }
1353 return 0;
1354#endif
1355 for (cp = strtab; cp < strtab + ld.ld_symb_size; ) {
1356 if (strcmp(cp, "_vfork") == 0) {
1357 if (debug)
1358 fprintf(stderr, "fixvfork: FOUND _vfork\n");
1359 strcpy(cp, "_fork");
1360 break;
1361 }
1362 cp += strlen(cp)+1;
1363 }
1364 if (cp < strtab + ld.ld_symb_size)
1365 /*
1366 * Write entire symbol table back to avoid
1367 * memory alignment bugs in ptrace
1368 */
1369 if (tload(pid, (int)ld.ld_symbols+(int)N_TXTADDR(hdr),
1370 (int)ld.ld_symb_size, strtab) < 0)
1371 goto err;
1372
1373 free(strtab);
1374 return 0;
1375
1376err:
1377 free(strtab);
1378 return -1;
1379}
1380
1381#endif /* SUNOS4 */