blob: 93b3c41e76bea87ab1ed0148f5df2a5aaba687e5 [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 */
Wichert Akkerman90470761999-03-17 00:42:25 +000042#if __GLIBC__ == 2 && __GLIBC_MINOR__ >= 1 && (defined(I386) || defined(M68K))
Wichert Akkerman76baf7c1999-02-19 00:21:36 +000043# 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;
Wichert Akkerman5daa0281999-03-15 19:49:42 +0000521 int started = 0;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000522 union {
523 long val;
524 char x[sizeof(long)];
525 } u;
526
527 if (addr & (sizeof(long) - 1)) {
528 /* addr not a multiple of sizeof(long) */
529 n = addr - (addr & -sizeof(long)); /* residue */
530 addr &= -sizeof(long); /* residue */
531 errno = 0;
532 u.val = ptrace(PTRACE_PEEKDATA, pid, (char *) addr, 0);
533 if (errno) {
Wichert Akkerman5daa0281999-03-15 19:49:42 +0000534 if (started && (errno==EPERM || errno==EIO)) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000535 /* Ran into 'end of memory' - stupid "printpath" */
536 return 0;
537 }
Wichert Akkerman5daa0281999-03-15 19:49:42 +0000538 /* But if not started, we had a bogus address. */
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000539 perror("ptrace: umoven");
540 return -1;
541 }
Wichert Akkerman5daa0281999-03-15 19:49:42 +0000542 started = 1;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000543 memcpy(laddr, &u.x[n], m = MIN(sizeof(long) - n, len));
544 addr += sizeof(long), laddr += m, len -= m;
545 }
546 while (len) {
547 errno = 0;
548 u.val = ptrace(PTRACE_PEEKDATA, pid, (char *) addr, 0);
549 if (errno) {
Wichert Akkerman5daa0281999-03-15 19:49:42 +0000550 if (started && (errno==EPERM || errno==EIO)) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000551 /* Ran into 'end of memory' - stupid "printpath" */
552 return 0;
553 }
554 perror("ptrace: umoven");
555 return -1;
556 }
Wichert Akkerman5daa0281999-03-15 19:49:42 +0000557 started = 1;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000558 memcpy(laddr, u.x, m = MIN(sizeof(long), len));
559 addr += sizeof(long), laddr += m, len -= m;
560 }
561#endif /* LINUX */
562
563#ifdef SUNOS4
564 int pid = tcp->pid;
565#if 0
566 int n, m;
567 union {
568 long val;
569 char x[sizeof(long)];
570 } u;
571
572 if (addr & (sizeof(long) - 1)) {
573 /* addr not a multiple of sizeof(long) */
574 n = addr - (addr & -sizeof(long)); /* residue */
575 addr &= -sizeof(long); /* residue */
576 errno = 0;
577 u.val = ptrace(PTRACE_PEEKDATA, pid, (char *) addr, 0);
578 if (errno) {
579 perror("umoven");
580 return -1;
581 }
582 memcpy(laddr, &u.x[n], m = MIN(sizeof(long) - n, len));
583 addr += sizeof(long), laddr += m, len -= m;
584 }
585 while (len) {
586 errno = 0;
587 u.val = ptrace(PTRACE_PEEKDATA, pid, (char *) addr, 0);
588 if (errno) {
589 perror("umoven");
590 return -1;
591 }
592 memcpy(laddr, u.x, m = MIN(sizeof(long), len));
593 addr += sizeof(long), laddr += m, len -= m;
594 }
595#else /* !oldway */
596 int n;
597
598 while (len) {
599 n = MIN(len, PAGSIZ);
600 n = MIN(n, ((addr + PAGSIZ) & PAGMASK) - addr);
601 if (ptrace(PTRACE_READDATA, pid,
602 (char *) addr, len, laddr) < 0) {
603 perror("umoven: ptrace(PTRACE_READDATA, ...)");
604 abort();
605 return -1;
606 }
607 len -= n;
608 addr += n;
609 laddr += n;
610 }
611#endif /* !oldway */
612#endif /* SUNOS4 */
613
614#ifdef SVR4
615/*
616 * We would like to use pread preferentially for speed
617 * but even though SGI has it in their library, it no longer works.
618 */
619#ifdef MIPS
620#undef HAVE_PREAD
621#endif
622#ifdef HAVE_PREAD
623 if (pread(tcp->pfd, laddr, len, addr) == -1)
624 return -1;
625#else /* !HAVE_PREAD */
626 lseek(tcp->pfd, addr, SEEK_SET);
627 if (read(tcp->pfd, laddr, len) == -1)
628 return -1;
629#endif /* !HAVE_PREAD */
630#endif /* SVR4 */
631
632 return 0;
633}
634
635/*
636 * like `umove' but make the additional effort of looking
637 * for a terminating zero byte.
638 */
639int
640umovestr(tcp, addr, len, laddr)
641struct tcb *tcp;
642long addr;
643int len;
644char *laddr;
645{
646#ifdef SRVR4
647 return umoven(tcp, addr, len, laddr);
648#else /* !SVR4 */
Wichert Akkerman5daa0281999-03-15 19:49:42 +0000649 int started = 0;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000650 int pid = tcp->pid;
651 int i, n, m;
652 union {
653 long val;
654 char x[sizeof(long)];
655 } u;
656
657 if (addr & (sizeof(long) - 1)) {
658 /* addr not a multiple of sizeof(long) */
659 n = addr - (addr & -sizeof(long)); /* residue */
660 addr &= -sizeof(long); /* residue */
661 errno = 0;
662 u.val = ptrace(PTRACE_PEEKDATA, pid, (char *)addr, 0);
663 if (errno) {
Wichert Akkerman5daa0281999-03-15 19:49:42 +0000664 if (started && (errno==EPERM || errno==EIO)) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000665 /* Ran into 'end of memory' - stupid "printpath" */
666 return 0;
667 }
668 perror("umovestr");
669 return -1;
670 }
Wichert Akkerman5daa0281999-03-15 19:49:42 +0000671 started = 1;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000672 memcpy(laddr, &u.x[n], m = MIN(sizeof(long)-n,len));
673 while (n & (sizeof(long) - 1))
674 if (u.x[n++] == '\0')
675 return 0;
676 addr += sizeof(long), laddr += m, len -= m;
677 }
678 while (len) {
679 errno = 0;
680 u.val = ptrace(PTRACE_PEEKDATA, pid, (char *)addr, 0);
681 if (errno) {
Wichert Akkerman5daa0281999-03-15 19:49:42 +0000682 if (started && (errno==EPERM || errno==EIO)) {
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000683 /* Ran into 'end of memory' - stupid "printpath" */
684 return 0;
685 }
686 perror("umovestr");
687 return -1;
688 }
Wichert Akkerman5daa0281999-03-15 19:49:42 +0000689 started = 1;
Wichert Akkerman76baf7c1999-02-19 00:21:36 +0000690 memcpy(laddr, u.x, m = MIN(sizeof(long), len));
691 for (i = 0; i < sizeof(long); i++)
692 if (u.x[i] == '\0')
693 return 0;
694
695 addr += sizeof(long), laddr += m, len -= m;
696 }
697 return 0;
698#endif /* !SVR4 */
699}
700
701#ifdef LINUX
702#ifndef SPARC
703#define PTRACE_WRITETEXT 101
704#define PTRACE_WRITEDATA 102
705#endif /* !SPARC */
706#endif /* LINUX */
707
708#ifdef SUNOS4
709
710static int
711uload(cmd, pid, addr, len, laddr)
712int cmd;
713int pid;
714long addr;
715int len;
716char *laddr;
717{
718#if 0
719 int n;
720
721 while (len) {
722 n = MIN(len, PAGSIZ);
723 n = MIN(n, ((addr + PAGSIZ) & PAGMASK) - addr);
724 if (ptrace(cmd, pid, (char *)addr, n, laddr) < 0) {
725 perror("uload: ptrace(PTRACE_WRITE, ...)");
726 return -1;
727 }
728 len -= n;
729 addr += n;
730 laddr += n;
731 }
732#else
733 int peek, poke;
734 int n, m;
735 union {
736 long val;
737 char x[sizeof(long)];
738 } u;
739
740 if (cmd == PTRACE_WRITETEXT) {
741 peek = PTRACE_PEEKTEXT;
742 poke = PTRACE_POKETEXT;
743 }
744 else {
745 peek = PTRACE_PEEKDATA;
746 poke = PTRACE_POKEDATA;
747 }
748 if (addr & (sizeof(long) - 1)) {
749 /* addr not a multiple of sizeof(long) */
750 n = addr - (addr & -sizeof(long)); /* residue */
751 addr &= -sizeof(long);
752 errno = 0;
753 u.val = ptrace(peek, pid, (char *) addr, 0);
754 if (errno) {
755 perror("uload: POKE");
756 return -1;
757 }
758 memcpy(&u.x[n], laddr, m = MIN(sizeof(long) - n, len));
759 if (ptrace(poke, pid, (char *)addr, u.val) < 0) {
760 perror("uload: POKE");
761 return -1;
762 }
763 addr += sizeof(long), laddr += m, len -= m;
764 }
765 while (len) {
766 if (len < sizeof(long))
767 u.val = ptrace(peek, pid, (char *) addr, 0);
768 memcpy(u.x, laddr, m = MIN(sizeof(long), len));
769 if (ptrace(poke, pid, (char *) addr, u.val) < 0) {
770 perror("uload: POKE");
771 return -1;
772 }
773 addr += sizeof(long), laddr += m, len -= m;
774 }
775#endif
776 return 0;
777}
778
779int
780tload(pid, addr, len, laddr)
781int pid;
782int addr, len;
783char *laddr;
784{
785 return uload(PTRACE_WRITETEXT, pid, addr, len, laddr);
786}
787
788int
789dload(pid, addr, len, laddr)
790int pid;
791int addr;
792int len;
793char *laddr;
794{
795 return uload(PTRACE_WRITEDATA, pid, addr, len, laddr);
796}
797
798#endif /* SUNOS4 */
799
800#ifndef SVR4
801
802int
803upeek(pid, off, res)
804int pid;
805long off;
806long *res;
807{
808 long val;
809
810#ifdef SUNOS4_KERNEL_ARCH_KLUDGE
811 {
812 static int is_sun4m = -1;
813 struct utsname name;
814
815 /* Round up the usual suspects. */
816 if (is_sun4m == -1) {
817 if (uname(&name) < 0) {
818 perror("upeek: uname?");
819 exit(1);
820 }
821 is_sun4m = strcmp(name.machine, "sun4m") == 0;
822 if (is_sun4m) {
823 extern struct xlat struct_user_offsets[];
824 struct xlat *x;
825
826 for (x = struct_user_offsets; x->str; x++)
827 x->val += 1024;
828 }
829 }
830 if (is_sun4m)
831 off += 1024;
832 }
833#endif /* SUNOS4_KERNEL_ARCH_KLUDGE */
834 errno = 0;
835 val = ptrace(PTRACE_PEEKUSER, pid, (char *) off, 0);
836 if (val == -1 && errno) {
837 perror("upeek: ptrace(PTRACE_PEEKUSER, ... )");
838 return -1;
839 }
840 *res = val;
841 return 0;
842}
843
844#endif /* !SVR4 */
845
846long
847getpc(tcp)
848struct tcb *tcp;
849{
850
851#ifdef LINUX
852 long pc;
853
854#ifdef I386
855 if (upeek(tcp->pid, 4*EIP, &pc) < 0)
856 return -1;
857#else /* !I386 */
858#ifdef ARM
859 if (upeek(tcp->pid, 4*15, &pc) < 0)
860 return -1;
861#else /* !ARM */
862#ifdef POWERPC
863 if (upeek(tcp->pid, 4*PT_NIP, &pc) < 0)
864 return -1;
865#else
866#ifdef M68K
867 if (upeek(tcp->pid, 4*PT_PC, &pc) < 0)
868 return -1;
869#else /* !M68K */
870#ifdef ALPHA
871 if (upeek(tcp->pid, REG_PC, &pc) < 0)
872 return -1;
873#else /* !ALPHA */
874#ifdef SPARC
875 struct pt_regs regs;
876 if (ptrace(PTRACE_GETREGS,tcp->pid,(char *)&regs,0) < 0)
877 return -1;
878 pc = regs.pc;
879#endif /* SPARC */
880#endif /* ALPHA */
881#endif /* !M68K */
882#endif /* !POWERPC */
883#endif /* !ARM */
884#endif /* !I386 */
885 return pc;
886#endif /* LINUX */
887
888#ifdef SUNOS4
889 /*
890 * Return current program counter for `pid'
891 * Assumes PC is never 0xffffffff
892 */
893 struct regs regs;
894
895 if (ptrace(PTRACE_GETREGS, tcp->pid, (char *) &regs, 0) < 0) {
896 perror("getpc: ptrace(PTRACE_GETREGS, ...)");
897 return -1;
898 }
899 return regs.r_pc;
900#endif /* SUNOS4 */
901
902#ifdef SVR4
903 /* XXX */
904 return 0;
905#endif /* SVR4 */
906
907}
908
909void
910printcall(tcp)
911struct tcb *tcp;
912{
913
914#ifdef LINUX
915#ifdef I386
916 long eip;
917
918 if (upeek(tcp->pid, 4*EIP, &eip) < 0) {
919 tprintf("[????????] ");
920 return;
921 }
922 tprintf("[%08lx] ", eip);
923#else /* !I386K */
924#ifdef POWERPC
925 long pc;
926
927 if (upeek(tcp->pid, 4*PT_NIP, &pc) < 0) {
928 tprintf ("[????????] ");
929 return;
930 }
931 tprintf("[%08lx] ", pc);
932#else /* !POWERPC */
933#ifdef M68K
934 long pc;
935
936 if (upeek(tcp->pid, 4*PT_PC, &pc) < 0) {
937 tprintf ("[????????] ");
938 return;
939 }
940 tprintf("[%08lx] ", pc);
941#else /* !M68K */
942#ifdef ALPHA
943 long pc;
944
945 if (upeek(tcp->pid, REG_PC, &pc) < 0) {
946 tprintf ("[????????] ");
947 return;
948 }
949 tprintf("[%08lx] ", pc);
950#else /* !ALPHA */
951#ifdef SPARC
952 struct pt_regs regs;
953 if (ptrace(PTRACE_GETREGS,tcp->pid,(char *)&regs,0) < 0) {
954 tprintf("[????????] ");
955 return;
956 }
957 tprintf("[%08lx] ", regs.pc);
958#endif /* SPARC */
959#endif /* ALPHA */
960#endif /* !M68K */
961#endif /* !POWERPC */
962#endif /* !I386 */
963#endif /* LINUX */
964
965#ifdef SUNOS4
966 struct regs regs;
967
968 if (ptrace(PTRACE_GETREGS, tcp->pid, (char *) &regs, 0) < 0) {
969 perror("printcall: ptrace(PTRACE_GETREGS, ...)");
970 tprintf("[????????] ");
971 return;
972 }
973 tprintf("[%08x] ", regs.r_o7);
974#endif /* SUNOS4 */
975
976#ifdef SVR4
977 /* XXX */
978 tprintf("[????????] ");
979#endif
980
981}
982
983#ifndef SVR4
984
985int
986setbpt(tcp)
987struct tcb *tcp;
988{
989
990#ifdef LINUX
991#ifdef SPARC
992 /* We simply use the SunOS breakpoint code. */
993
994 struct pt_regs regs;
995#define LOOPA 0x30800000 /* ba,a 0 */
996
997 if (tcp->flags & TCB_BPTSET) {
998 fprintf(stderr, "PANIC: TCB already set in pid %u\n", tcp->pid);
999 return -1;
1000 }
1001 if (ptrace(PTRACE_GETREGS, tcp->pid, (char *)&regs, 0) < 0) {
1002 perror("setbpt: ptrace(PTRACE_GETREGS, ...)");
1003 return -1;
1004 }
1005 memmove (&regs.u_regs [1], &regs.u_regs [0],
1006 sizeof (regs.u_regs) - sizeof (regs.u_regs [0]));
1007 tcp->baddr = regs.u_regs[UREG_I7] + 8;
1008 errno = 0;
1009 tcp->inst[0] = ptrace(PTRACE_PEEKTEXT, tcp->pid, (char *)tcp->baddr, 0);
1010 if(errno) {
1011 perror("setbpt: ptrace(PTRACE_PEEKTEXT, ...)");
1012 return -1;
1013 }
1014
1015 /*
1016 * XXX - BRUTAL MODE ON
1017 * We cannot set a real BPT in the child, since it will not be
1018 * traced at the moment it will reach the trap and would probably
1019 * die with a core dump.
1020 * Thus, we are force our way in by taking out two instructions
1021 * and insert an eternal loop instead, in expectance of the SIGSTOP
1022 * generated by out PTRACE_ATTACH.
1023 * Of cause, if we evaporate ourselves in the middle of all this...
1024 */
1025 errno = 0;
1026 ptrace(PTRACE_POKETEXT, tcp->pid, (char *) tcp->baddr, LOOPA);
1027 if(errno) {
1028 perror("setbpt: ptrace(PTRACE_POKETEXT, ...)");
1029 return -1;
1030 }
1031 tcp->flags |= TCB_BPTSET;
1032
1033#else /* !SPARC */
1034
1035#if defined (I386)
1036#define LOOP 0x0000feeb
1037#elif defined (M68K)
1038#define LOOP 0x60fe0000
1039#elif defined (ALPHA)
1040#define LOOP 0xc3ffffff
1041#elif defined (POWERPC)
1042#define LOOP 0x0000feeb
1043#elif defined(ARM)
1044#define LOOP -1 /* almost certainly wrong, jws */
1045#else
1046#error unknown architecture
1047#endif
1048
1049 if (tcp->flags & TCB_BPTSET) {
1050 fprintf(stderr, "PANIC: bpt already set in pid %u\n", tcp->pid);
1051 return -1;
1052 }
1053#if defined (I386)
1054 if (upeek(tcp->pid, 4*EIP, &tcp->baddr) < 0)
1055 return -1;
1056#elif defined (M68K)
1057 if (upeek(tcp->pid, 4*PT_PC, &tcp->baddr) < 0)
1058 return -1;
1059#elif defined (ALPHA)
1060 return -1;
1061#elif defined (ARM)
1062 return -1;
1063#elif defined (POWERPC)
1064 if (upeek(tcp->pid, 4*PT_NIP, &tcp->baddr) < 0)
1065 return -1;
1066#else
1067#error unknown architecture
1068#endif
1069 if (debug)
1070 fprintf(stderr, "[%d] setting bpt at %lx\n", tcp->pid, tcp->baddr);
1071 tcp->inst[0] = ptrace(PTRACE_PEEKTEXT, tcp->pid, (char *) tcp->baddr, 0);
1072 if (errno) {
1073 perror("setbpt: ptrace(PTRACE_PEEKTEXT, ...)");
1074 return -1;
1075 }
1076 ptrace(PTRACE_POKETEXT, tcp->pid, (char *) tcp->baddr, LOOP);
1077 if (errno) {
1078 perror("setbpt: ptrace(PTRACE_POKETEXT, ...)");
1079 return -1;
1080 }
1081 tcp->flags |= TCB_BPTSET;
1082
1083#endif /* SPARC */
1084#endif /* LINUX */
1085
1086#ifdef SUNOS4
1087#ifdef SPARC /* This code is slightly sparc specific */
1088
1089 struct pt_regs regs;
1090#define BPT 0x91d02001 /* ta 1 */
1091#define LOOP 0x10800000 /* ba 0 */
1092#define LOOPA 0x30800000 /* ba,a 0 */
1093#define NOP 0x01000000
1094#if LOOPA
1095 static int loopdeloop[1] = {LOOPA};
1096#else
1097 static int loopdeloop[2] = {LOOP, NOP};
1098#endif
1099
1100 if (tcp->flags & TCB_BPTSET) {
1101 fprintf(stderr, "PANIC: TCB already set in pid %u\n", tcp->pid);
1102 return -1;
1103 }
1104 if (ptrace(PTRACE_GETREGS, tcp->pid, (char *)&regs, 0) < 0) {
1105 perror("setbpt: ptrace(PTRACE_GETREGS, ...)");
1106 return -1;
1107 }
1108 tcp->baddr = regs.r_o7 + 8;
1109 if (ptrace(PTRACE_READTEXT, tcp->pid, (char *)tcp->baddr,
1110 sizeof tcp->inst, (char *)tcp->inst) < 0) {
1111 perror("setbpt: ptrace(PTRACE_READTEXT, ...)");
1112 return -1;
1113 }
1114
1115 /*
1116 * XXX - BRUTAL MODE ON
1117 * We cannot set a real BPT in the child, since it will not be
1118 * traced at the moment it will reach the trap and would probably
1119 * die with a core dump.
1120 * Thus, we are force our way in by taking out two instructions
1121 * and insert an eternal loop in stead, in expectance of the SIGSTOP
1122 * generated by out PTRACE_ATTACH.
1123 * Of cause, if we evaporate ourselves in the middle of all this...
1124 */
1125 if (ptrace(PTRACE_WRITETEXT, tcp->pid, (char *) tcp->baddr,
1126 sizeof loopdeloop, (char *) loopdeloop) < 0) {
1127 perror("setbpt: ptrace(PTRACE_WRITETEXT, ...)");
1128 return -1;
1129 }
1130 tcp->flags |= TCB_BPTSET;
1131
1132#endif /* SPARC */
1133#endif /* SUNOS4 */
1134
1135 return 0;
1136}
1137
1138int
1139clearbpt(tcp)
1140struct tcb *tcp;
1141{
1142
1143#ifdef LINUX
1144#ifdef I386
1145 long eip;
1146#else /* !I386 */
1147#ifdef POWERPC
1148 long pc;
1149#else /* !POWERPC */
1150#ifdef M68K
1151 long pc;
1152#else /* !M68K */
1153#ifdef ALPHA
1154 long pc;
1155#endif /* ALPHA */
1156#endif /* !M68K */
1157#endif /* !POWERPC */
1158#endif /* !I386 */
1159
1160#ifdef SPARC
1161 /* Again, we borrow the SunOS breakpoint code. */
1162 if (!(tcp->flags & TCB_BPTSET)) {
1163 fprintf(stderr, "PANIC: TCB not set in pid %u\n", tcp->pid);
1164 return -1;
1165 }
1166 errno = 0;
1167 ptrace(PTRACE_POKETEXT, tcp->pid, (char *) tcp->baddr, tcp->inst[0]);
1168 if(errno) {
1169 perror("clearbtp: ptrace(PTRACE_POKETEXT, ...)");
1170 return -1;
1171 }
1172 tcp->flags &= ~TCB_BPTSET;
1173#else /* !SPARC */
1174
1175 if (debug)
1176 fprintf(stderr, "[%d] clearing bpt\n", tcp->pid);
1177 if (!(tcp->flags & TCB_BPTSET)) {
1178 fprintf(stderr, "PANIC: TCB not set in pid %u\n", tcp->pid);
1179 return -1;
1180 }
1181 errno = 0;
1182 ptrace(PTRACE_POKETEXT, tcp->pid, (char *) tcp->baddr, tcp->inst[0]);
1183 if (errno) {
1184 perror("clearbtp: ptrace(PTRACE_POKETEXT, ...)");
1185 return -1;
1186 }
1187 tcp->flags &= ~TCB_BPTSET;
1188
1189#ifdef I386
1190 if (upeek(tcp->pid, 4*EIP, &eip) < 0)
1191 return -1;
1192 if (eip != tcp->baddr) {
1193 /* The breakpoint has not been reached yet. */
1194 if (debug)
1195 fprintf(stderr,
1196 "NOTE: PC not at bpt (pc %#lx baddr %#lx)\n",
1197 eip, tcp->baddr);
1198 return 0;
1199 }
1200#else /* !I386 */
1201#ifdef POWERPC
1202 if (upeek(tcp->pid, 4*PT_NIP, &pc) < 0)
1203 return -1;
1204 if (pc != tcp->baddr) {
1205 /* The breakpoint has not been reached yet. */
1206 if (debug)
1207 fprintf(stderr, "NOTE: PC not at bpt (pc %#lx baddr %#lx)\n",
1208 pc, tcp->baddr);
1209 return 0;
1210 }
1211#else /* !POWERPC */
1212#ifdef M68K
1213 if (upeek(tcp->pid, 4*PT_PC, &pc) < 0)
1214 return -1;
1215 if (pc != tcp->baddr) {
1216 /* The breakpoint has not been reached yet. */
1217 if (debug)
1218 fprintf(stderr, "NOTE: PC not at bpt (pc %#lx baddr %#lx)\n",
1219 pc, tcp->baddr);
1220 return 0;
1221 }
1222#else /* !M68K */
1223#ifdef ALPHA
1224 if (upeek(tcp->pid, REG_PC, &pc) < 0)
1225 return -1;
1226 if (pc != tcp->baddr) {
1227 /* The breakpoint has not been reached yet. */
1228 if (debug)
1229 fprintf(stderr, "NOTE: PC not at bpt (pc %#lx baddr %#lx)\n",
1230 pc, tcp->baddr);
1231 return 0;
1232 }
1233#endif /* ALPHA */
1234#endif /* !M68K */
1235#endif /* !POWERPC */
1236#endif /* !I386 */
1237#endif /* !SPARC */
1238#endif /* LINUX */
1239
1240#ifdef SUNOS4
1241#ifdef SPARC
1242
1243#if !LOOPA
1244 struct pt_regs regs;
1245#endif
1246
1247 if (!(tcp->flags & TCB_BPTSET)) {
1248 fprintf(stderr, "PANIC: TCB not set in pid %u\n", tcp->pid);
1249 return -1;
1250 }
1251 if (ptrace(PTRACE_WRITETEXT, tcp->pid, (char *) tcp->baddr,
1252 sizeof tcp->inst, (char *) tcp->inst) < 0) {
1253 perror("clearbtp: ptrace(PTRACE_WRITETEXT, ...)");
1254 return -1;
1255 }
1256 tcp->flags &= ~TCB_BPTSET;
1257
1258#if !LOOPA
1259 /*
1260 * Since we don't have a single instruction breakpoint, we may have
1261 * to adjust the program counter after removing the our `breakpoint'.
1262 */
1263 if (ptrace(PTRACE_GETREGS, tcp->pid, (char *)&regs, 0) < 0) {
1264 perror("clearbpt: ptrace(PTRACE_GETREGS, ...)");
1265 return -1;
1266 }
1267 if ((regs.r_pc < tcp->baddr) ||
1268 (regs.r_pc > tcp->baddr + 4)) {
1269 /* The breakpoint has not been reached yet */
1270 if (debug)
1271 fprintf(stderr,
1272 "NOTE: PC not at bpt (pc %#x baddr %#x)\n",
1273 regs.r_pc, tcp->parent->baddr);
1274 return 0;
1275 }
1276 if (regs.r_pc != tcp->baddr)
1277 if (debug)
1278 fprintf(stderr, "NOTE: PC adjusted (%#x -> %#x\n",
1279 regs.r_pc, tcp->baddr);
1280
1281 regs.r_pc = tcp->baddr;
1282 if (ptrace(PTRACE_SETREGS, tcp->pid, (char *)&regs, 0) < 0) {
1283 perror("clearbpt: ptrace(PTRACE_SETREGS, ...)");
1284 return -1;
1285 }
1286#endif /* LOOPA */
1287#endif /* SPARC */
1288#endif /* SUNOS4 */
1289
1290 return 0;
1291}
1292
1293#endif /* !SVR4 */
1294
1295#ifdef SUNOS4
1296
1297static int
1298getex(pid, hdr)
1299int pid;
1300struct exec *hdr;
1301{
1302 int n;
1303
1304 for (n = 0; n < sizeof *hdr; n += 4) {
1305 long res;
1306 if (upeek(pid, uoff(u_exdata) + n, &res) < 0)
1307 return -1;
1308 memcpy(((char *) hdr) + n, &res, 4);
1309 }
1310 if (debug) {
1311 fprintf(stderr, "[struct exec: magic: %o version %u Mach %o\n",
1312 hdr->a_magic, hdr->a_toolversion, hdr->a_machtype);
1313 fprintf(stderr, "Text %lu Data %lu Bss %lu Syms %lu Entry %#lx]\n",
1314 hdr->a_text, hdr->a_data, hdr->a_bss, hdr->a_syms, hdr->a_entry);
1315 }
1316 return 0;
1317}
1318
1319int
1320fixvfork(tcp)
1321struct tcb *tcp;
1322{
1323 int pid = tcp->pid;
1324 /*
1325 * Change `vfork' in a freshly exec'ed dynamically linked
1326 * executable's (internal) symbol table to plain old `fork'
1327 */
1328
1329 struct exec hdr;
1330 struct link_dynamic dyn;
1331 struct link_dynamic_2 ld;
1332 char *strtab, *cp;
1333
1334 if (getex(pid, &hdr) < 0)
1335 return -1;
1336 if (!hdr.a_dynamic)
1337 return -1;
1338
1339 if (umove(tcp, (int) N_DATADDR(hdr), &dyn) < 0) {
1340 fprintf(stderr, "Cannot read DYNAMIC\n");
1341 return -1;
1342 }
1343 if (umove(tcp, (int) dyn.ld_un.ld_2, &ld) < 0) {
1344 fprintf(stderr, "Cannot read link_dynamic_2\n");
1345 return -1;
1346 }
1347 if ((strtab = malloc((unsigned)ld.ld_symb_size)) == NULL) {
1348 fprintf(stderr, "fixvfork: out of memory\n");
1349 return -1;
1350 }
1351 if (umoven(tcp, (int)ld.ld_symbols+(int)N_TXTADDR(hdr),
1352 (int)ld.ld_symb_size, strtab) < 0)
1353 goto err;
1354
1355#if 0
1356 for (cp = strtab; cp < strtab + ld.ld_symb_size; ) {
1357 fprintf(stderr, "[symbol: %s]\n", cp);
1358 cp += strlen(cp)+1;
1359 }
1360 return 0;
1361#endif
1362 for (cp = strtab; cp < strtab + ld.ld_symb_size; ) {
1363 if (strcmp(cp, "_vfork") == 0) {
1364 if (debug)
1365 fprintf(stderr, "fixvfork: FOUND _vfork\n");
1366 strcpy(cp, "_fork");
1367 break;
1368 }
1369 cp += strlen(cp)+1;
1370 }
1371 if (cp < strtab + ld.ld_symb_size)
1372 /*
1373 * Write entire symbol table back to avoid
1374 * memory alignment bugs in ptrace
1375 */
1376 if (tload(pid, (int)ld.ld_symbols+(int)N_TXTADDR(hdr),
1377 (int)ld.ld_symb_size, strtab) < 0)
1378 goto err;
1379
1380 free(strtab);
1381 return 0;
1382
1383err:
1384 free(strtab);
1385 return -1;
1386}
1387
1388#endif /* SUNOS4 */