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