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